InstBuilderManual.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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::groupNonUniformOp(spv::Op op, uint32_t result_type,
  70. uint32_t result_id,
  71. uint32_t exec_scope) {
  72. if (!TheInst.empty()) {
  73. TheStatus = Status::NestedInst;
  74. return *this;
  75. }
  76. // TODO: check op range
  77. TheInst.reserve(4);
  78. TheInst.emplace_back(static_cast<uint32_t>(op));
  79. TheInst.emplace_back(result_type);
  80. TheInst.emplace_back(result_id);
  81. TheInst.emplace_back(exec_scope);
  82. return *this;
  83. }
  84. InstBuilder &InstBuilder::groupNonUniformUnaryOp(
  85. spv::Op op, uint32_t result_type, uint32_t result_id, uint32_t exec_scope,
  86. llvm::Optional<spv::GroupOperation> groupOp, uint32_t operand) {
  87. if (!TheInst.empty()) {
  88. TheStatus = Status::NestedInst;
  89. return *this;
  90. }
  91. // TODO: check op range
  92. TheInst.reserve(5);
  93. TheInst.emplace_back(static_cast<uint32_t>(op));
  94. TheInst.emplace_back(result_type);
  95. TheInst.emplace_back(result_id);
  96. TheInst.emplace_back(exec_scope);
  97. if (groupOp.hasValue())
  98. TheInst.emplace_back(static_cast<uint32_t>(groupOp.getValue()));
  99. TheInst.emplace_back(operand);
  100. return *this;
  101. }
  102. InstBuilder &
  103. InstBuilder::groupNonUniformBinaryOp(spv::Op op, uint32_t result_type,
  104. uint32_t result_id, uint32_t exec_scope,
  105. uint32_t operand1, uint32_t operand2) {
  106. if (!TheInst.empty()) {
  107. TheStatus = Status::NestedInst;
  108. return *this;
  109. }
  110. // TODO: check op range
  111. TheInst.reserve(6);
  112. TheInst.emplace_back(static_cast<uint32_t>(op));
  113. TheInst.emplace_back(result_type);
  114. TheInst.emplace_back(result_id);
  115. TheInst.emplace_back(exec_scope);
  116. TheInst.emplace_back(operand1);
  117. TheInst.emplace_back(operand2);
  118. return *this;
  119. }
  120. InstBuilder &InstBuilder::opConstant(uint32_t resultType, uint32_t resultId,
  121. uint32_t value) {
  122. if (!TheInst.empty()) {
  123. TheStatus = Status::NestedInst;
  124. return *this;
  125. }
  126. TheInst.reserve(4);
  127. TheInst.emplace_back(static_cast<uint32_t>(spv::Op::OpConstant));
  128. TheInst.emplace_back(resultType);
  129. TheInst.emplace_back(resultId);
  130. TheInst.emplace_back(value);
  131. return *this;
  132. }
  133. InstBuilder &InstBuilder::opImageSample(
  134. uint32_t result_type, uint32_t result_id, uint32_t sampled_image,
  135. uint32_t coordinate, uint32_t dref,
  136. llvm::Optional<spv::ImageOperandsMask> image_operands, bool is_explicit,
  137. bool is_sparse) {
  138. spv::Op op = spv::Op::Max;
  139. if (dref) {
  140. op = is_explicit ? (is_sparse ? spv::Op::OpImageSparseSampleDrefExplicitLod
  141. : spv::Op::OpImageSampleDrefExplicitLod)
  142. : (is_sparse ? spv::Op::OpImageSparseSampleDrefImplicitLod
  143. : spv::Op::OpImageSampleDrefImplicitLod);
  144. } else {
  145. op = is_explicit ? (is_sparse ? spv::Op::OpImageSparseSampleExplicitLod
  146. : spv::Op::OpImageSampleExplicitLod)
  147. : (is_sparse ? spv::Op::OpImageSparseSampleImplicitLod
  148. : spv::Op::OpImageSampleImplicitLod);
  149. }
  150. TheInst.emplace_back(static_cast<uint32_t>(op));
  151. TheInst.emplace_back(result_type);
  152. TheInst.emplace_back(result_id);
  153. TheInst.emplace_back(sampled_image);
  154. TheInst.emplace_back(coordinate);
  155. if (dref)
  156. TheInst.emplace_back(dref);
  157. if (image_operands.hasValue()) {
  158. const auto &val = image_operands.getValue();
  159. encodeImageOperands(val);
  160. }
  161. return *this;
  162. }
  163. InstBuilder &InstBuilder::opImageFetchRead(
  164. uint32_t result_type, uint32_t result_id, uint32_t image,
  165. uint32_t coordinate, llvm::Optional<spv::ImageOperandsMask> image_operands,
  166. bool is_fetch, bool is_sparse) {
  167. spv::Op op =
  168. is_fetch
  169. ? (is_sparse ? spv::Op::OpImageSparseFetch : spv::Op::OpImageFetch)
  170. : (is_sparse ? spv::Op::OpImageSparseRead : spv::Op::OpImageRead);
  171. TheInst.emplace_back(static_cast<uint32_t>(op));
  172. TheInst.emplace_back(result_type);
  173. TheInst.emplace_back(result_id);
  174. TheInst.emplace_back(image);
  175. TheInst.emplace_back(coordinate);
  176. if (image_operands.hasValue()) {
  177. const auto &val = image_operands.getValue();
  178. encodeImageOperands(val);
  179. }
  180. return *this;
  181. }
  182. InstBuilder &InstBuilder::opSpecConstant(uint32_t resultType, uint32_t resultId,
  183. uint32_t value) {
  184. if (!TheInst.empty()) {
  185. TheStatus = Status::NestedInst;
  186. return *this;
  187. }
  188. TheInst.reserve(4);
  189. TheInst.emplace_back(static_cast<uint32_t>(spv::Op::OpSpecConstant));
  190. TheInst.emplace_back(resultType);
  191. TheInst.emplace_back(resultId);
  192. TheInst.emplace_back(value);
  193. return *this;
  194. }
  195. void InstBuilder::encodeString(std::string value) {
  196. const auto &words = string::encodeSPIRVString(value);
  197. TheInst.insert(TheInst.end(), words.begin(), words.end());
  198. }
  199. } // end namespace spirv
  200. } // end namespace clang