InstBuilderManual.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //===-- InstBuilder.cpp - SPIR-V instruction builder ------------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/SPIRV/InstBuilder.h"
  10. #include "clang/SPIRV/String.h"
  11. #include "llvm/llvm_assert/assert.h"
  12. namespace clang {
  13. namespace spirv {
  14. std::vector<uint32_t> InstBuilder::take() {
  15. std::vector<uint32_t> result;
  16. if (TheStatus == Status::Success && Expectation.empty() && !TheInst.empty()) {
  17. TheInst.front() |= uint32_t(TheInst.size()) << 16;
  18. result.swap(TheInst);
  19. }
  20. return result;
  21. }
  22. InstBuilder &InstBuilder::unaryOp(spv::Op op, uint32_t result_type,
  23. uint32_t result_id, uint32_t operand) {
  24. if (!TheInst.empty()) {
  25. TheStatus = Status::NestedInst;
  26. return *this;
  27. }
  28. // TODO: check op range
  29. TheInst.reserve(4);
  30. TheInst.emplace_back(static_cast<uint32_t>(op));
  31. TheInst.emplace_back(result_type);
  32. TheInst.emplace_back(result_id);
  33. TheInst.emplace_back(operand);
  34. return *this;
  35. }
  36. InstBuilder &InstBuilder::binaryOp(spv::Op op, uint32_t result_type,
  37. uint32_t result_id, uint32_t lhs,
  38. uint32_t rhs) {
  39. if (!TheInst.empty()) {
  40. TheStatus = Status::NestedInst;
  41. return *this;
  42. }
  43. // TODO: check op range
  44. TheInst.reserve(5);
  45. TheInst.emplace_back(static_cast<uint32_t>(op));
  46. TheInst.emplace_back(result_type);
  47. TheInst.emplace_back(result_id);
  48. TheInst.emplace_back(lhs);
  49. TheInst.emplace_back(rhs);
  50. return *this;
  51. }
  52. InstBuilder &InstBuilder::specConstantBinaryOp(spv::Op op, uint32_t result_type,
  53. uint32_t result_id, uint32_t lhs,
  54. uint32_t rhs) {
  55. if (!TheInst.empty()) {
  56. TheStatus = Status::NestedInst;
  57. return *this;
  58. }
  59. // TODO: check op range
  60. TheInst.reserve(6);
  61. TheInst.emplace_back(static_cast<uint32_t>(spv::Op::OpSpecConstantOp));
  62. TheInst.emplace_back(result_type);
  63. TheInst.emplace_back(result_id);
  64. TheInst.emplace_back(static_cast<uint32_t>(op));
  65. TheInst.emplace_back(lhs);
  66. TheInst.emplace_back(rhs);
  67. return *this;
  68. }
  69. InstBuilder &InstBuilder::atomicOp(spv::Op op, uint32_t result_type,
  70. uint32_t result_id, uint32_t pointer,
  71. uint32_t scope, uint32_t semantics,
  72. uint32_t value) {
  73. if (!TheInst.empty()) {
  74. TheStatus = Status::NestedInst;
  75. return *this;
  76. }
  77. if (result_type == 0) {
  78. TheStatus = Status::ZeroResultType;
  79. return *this;
  80. }
  81. if (result_id == 0) {
  82. TheStatus = Status::ZeroResultId;
  83. return *this;
  84. }
  85. TheInst.reserve(7);
  86. TheInst.emplace_back(static_cast<uint32_t>(op));
  87. TheInst.emplace_back(result_type);
  88. TheInst.emplace_back(result_id);
  89. TheInst.emplace_back(pointer);
  90. TheInst.emplace_back(scope);
  91. TheInst.emplace_back(semantics);
  92. TheInst.emplace_back(value);
  93. return *this;
  94. }
  95. InstBuilder &InstBuilder::groupNonUniformOp(spv::Op op, uint32_t result_type,
  96. uint32_t result_id,
  97. uint32_t exec_scope) {
  98. if (!TheInst.empty()) {
  99. TheStatus = Status::NestedInst;
  100. return *this;
  101. }
  102. // TODO: check op range
  103. TheInst.reserve(4);
  104. TheInst.emplace_back(static_cast<uint32_t>(op));
  105. TheInst.emplace_back(result_type);
  106. TheInst.emplace_back(result_id);
  107. TheInst.emplace_back(exec_scope);
  108. return *this;
  109. }
  110. InstBuilder &InstBuilder::groupNonUniformUnaryOp(
  111. spv::Op op, uint32_t result_type, uint32_t result_id, uint32_t exec_scope,
  112. llvm::Optional<spv::GroupOperation> groupOp, uint32_t operand) {
  113. if (!TheInst.empty()) {
  114. TheStatus = Status::NestedInst;
  115. return *this;
  116. }
  117. // TODO: check op range
  118. TheInst.reserve(5);
  119. TheInst.emplace_back(static_cast<uint32_t>(op));
  120. TheInst.emplace_back(result_type);
  121. TheInst.emplace_back(result_id);
  122. TheInst.emplace_back(exec_scope);
  123. if (groupOp.hasValue())
  124. TheInst.emplace_back(static_cast<uint32_t>(groupOp.getValue()));
  125. TheInst.emplace_back(operand);
  126. return *this;
  127. }
  128. InstBuilder &
  129. InstBuilder::groupNonUniformBinaryOp(spv::Op op, uint32_t result_type,
  130. uint32_t result_id, uint32_t exec_scope,
  131. uint32_t operand1, uint32_t operand2) {
  132. if (!TheInst.empty()) {
  133. TheStatus = Status::NestedInst;
  134. return *this;
  135. }
  136. // TODO: check op range
  137. TheInst.reserve(6);
  138. TheInst.emplace_back(static_cast<uint32_t>(op));
  139. TheInst.emplace_back(result_type);
  140. TheInst.emplace_back(result_id);
  141. TheInst.emplace_back(exec_scope);
  142. TheInst.emplace_back(operand1);
  143. TheInst.emplace_back(operand2);
  144. return *this;
  145. }
  146. InstBuilder &InstBuilder::opConstant(uint32_t resultType, uint32_t resultId,
  147. uint32_t value) {
  148. if (!TheInst.empty()) {
  149. TheStatus = Status::NestedInst;
  150. return *this;
  151. }
  152. TheInst.reserve(4);
  153. TheInst.emplace_back(static_cast<uint32_t>(spv::Op::OpConstant));
  154. TheInst.emplace_back(resultType);
  155. TheInst.emplace_back(resultId);
  156. TheInst.emplace_back(value);
  157. return *this;
  158. }
  159. InstBuilder &InstBuilder::opImageSample(
  160. uint32_t result_type, uint32_t result_id, uint32_t sampled_image,
  161. uint32_t coordinate, uint32_t dref,
  162. llvm::Optional<spv::ImageOperandsMask> image_operands, bool is_explicit,
  163. bool is_sparse) {
  164. spv::Op op = spv::Op::Max;
  165. if (dref) {
  166. op = is_explicit ? (is_sparse ? spv::Op::OpImageSparseSampleDrefExplicitLod
  167. : spv::Op::OpImageSampleDrefExplicitLod)
  168. : (is_sparse ? spv::Op::OpImageSparseSampleDrefImplicitLod
  169. : spv::Op::OpImageSampleDrefImplicitLod);
  170. } else {
  171. op = is_explicit ? (is_sparse ? spv::Op::OpImageSparseSampleExplicitLod
  172. : spv::Op::OpImageSampleExplicitLod)
  173. : (is_sparse ? spv::Op::OpImageSparseSampleImplicitLod
  174. : spv::Op::OpImageSampleImplicitLod);
  175. }
  176. TheInst.emplace_back(static_cast<uint32_t>(op));
  177. TheInst.emplace_back(result_type);
  178. TheInst.emplace_back(result_id);
  179. TheInst.emplace_back(sampled_image);
  180. TheInst.emplace_back(coordinate);
  181. if (dref)
  182. TheInst.emplace_back(dref);
  183. if (image_operands.hasValue() &&
  184. image_operands.getValue() != spv::ImageOperandsMask::MaskNone) {
  185. const auto &val = image_operands.getValue();
  186. encodeImageOperands(val);
  187. }
  188. return *this;
  189. }
  190. InstBuilder &InstBuilder::opImageFetchRead(
  191. uint32_t result_type, uint32_t result_id, uint32_t image,
  192. uint32_t coordinate, llvm::Optional<spv::ImageOperandsMask> image_operands,
  193. bool is_fetch, bool is_sparse) {
  194. spv::Op op =
  195. is_fetch
  196. ? (is_sparse ? spv::Op::OpImageSparseFetch : spv::Op::OpImageFetch)
  197. : (is_sparse ? spv::Op::OpImageSparseRead : spv::Op::OpImageRead);
  198. TheInst.emplace_back(static_cast<uint32_t>(op));
  199. TheInst.emplace_back(result_type);
  200. TheInst.emplace_back(result_id);
  201. TheInst.emplace_back(image);
  202. TheInst.emplace_back(coordinate);
  203. if (image_operands.hasValue()) {
  204. const auto &val = image_operands.getValue();
  205. encodeImageOperands(val);
  206. }
  207. return *this;
  208. }
  209. InstBuilder &InstBuilder::opSpecConstant(uint32_t resultType, uint32_t resultId,
  210. uint32_t value) {
  211. if (!TheInst.empty()) {
  212. TheStatus = Status::NestedInst;
  213. return *this;
  214. }
  215. TheInst.reserve(4);
  216. TheInst.emplace_back(static_cast<uint32_t>(spv::Op::OpSpecConstant));
  217. TheInst.emplace_back(resultType);
  218. TheInst.emplace_back(resultId);
  219. TheInst.emplace_back(value);
  220. return *this;
  221. }
  222. void InstBuilder::encodeString(llvm::StringRef value) {
  223. const auto &words = string::encodeSPIRVString(value);
  224. TheInst.insert(TheInst.end(), words.begin(), words.end());
  225. }
  226. } // end namespace spirv
  227. } // end namespace clang