RelaxedPrecisionVisitor.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. //===--- RelaxedPrecisionVisitor.cpp - RelaxedPrecision Visitor --*- 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 "RelaxedPrecisionVisitor.h"
  10. #include "clang/SPIRV/AstTypeProbe.h"
  11. #include "clang/SPIRV/SpirvBuilder.h"
  12. namespace clang {
  13. namespace spirv {
  14. bool RelaxedPrecisionVisitor::visit(SpirvFunction *fn, Phase phase) {
  15. assert(fn);
  16. if (phase == Visitor::Phase::Init)
  17. if (isRelaxedPrecisionType(fn->getAstReturnType(), spvOptions))
  18. fn->setRelaxedPrecision();
  19. return true;
  20. }
  21. bool RelaxedPrecisionVisitor::visit(SpirvVectorShuffle *inst) {
  22. // The result of vector shuffle must have RelaxedPrecision if the chosen
  23. // elements come from a vector that is RelaxedPrecision.
  24. auto *vec1 = inst->getVec1();
  25. auto *vec2 = inst->getVec2();
  26. const auto vec1Type = vec1->getAstResultType();
  27. const auto vec2Type = vec2->getAstResultType();
  28. const bool isVec1Relaxed = isRelaxedPrecisionType(vec1Type, spvOptions);
  29. const bool isVec2Relaxed = isRelaxedPrecisionType(vec2Type, spvOptions);
  30. uint32_t vec1Size;
  31. uint32_t vec2Size;
  32. (void)isVectorType(vec1Type, nullptr, &vec1Size);
  33. (void)isVectorType(vec2Type, nullptr, &vec2Size);
  34. bool vec1ElemUsed = false;
  35. bool vec2ElemUsed = false;
  36. for (auto component : inst->getComponents()) {
  37. if (component < vec1Size)
  38. vec1ElemUsed = true;
  39. else
  40. vec2ElemUsed = true;
  41. }
  42. const bool onlyVec1Used = vec1ElemUsed && !vec2ElemUsed;
  43. const bool onlyVec2Used = vec2ElemUsed && !vec1ElemUsed;
  44. if ((onlyVec1Used && isVec1Relaxed) || (onlyVec2Used && isVec2Relaxed) ||
  45. (vec1ElemUsed && vec2ElemUsed && isVec1Relaxed && isVec2Relaxed))
  46. inst->setRelaxedPrecision();
  47. return true;
  48. }
  49. bool RelaxedPrecisionVisitor::visit(SpirvUnaryOp *inst) {
  50. // For conversion operations, check the result QualType. For example: if we
  51. // are converting from min12int to int, the result should no longet get
  52. // RelaxedPrecision.
  53. switch (inst->getopcode()) {
  54. case spv::Op::OpBitcast:
  55. case spv::Op::OpFConvert:
  56. case spv::Op::OpSConvert:
  57. case spv::Op::OpUConvert: {
  58. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions)) {
  59. inst->setRelaxedPrecision();
  60. }
  61. return true;
  62. }
  63. default:
  64. break;
  65. }
  66. // If the argument of the unary operation is RelaxedPrecision, the result is
  67. // also RelaxedPrecision.
  68. if (inst->getOperand()->isRelaxedPrecision())
  69. inst->setRelaxedPrecision();
  70. return true;
  71. }
  72. bool RelaxedPrecisionVisitor::visit(SpirvBinaryOp *inst) {
  73. // If either argument of the binary operation is RelaxedPrecision, the result
  74. // is also RelaxedPrecision.
  75. if (inst->getOperand1()->isRelaxedPrecision() &&
  76. inst->getOperand2()->isRelaxedPrecision())
  77. inst->setRelaxedPrecision();
  78. return true;
  79. }
  80. bool RelaxedPrecisionVisitor::visit(SpirvSpecConstantUnaryOp *inst) {
  81. // If the argument of the unary operation is RelaxedPrecision, the result is
  82. // also RelaxedPrecision.
  83. if (inst->getOperand()->isRelaxedPrecision())
  84. inst->setRelaxedPrecision();
  85. return true;
  86. }
  87. bool RelaxedPrecisionVisitor::visit(SpirvSpecConstantBinaryOp *inst) {
  88. // If either argument of the binary operation is RelaxedPrecision, the result
  89. // is also RelaxedPrecision.
  90. if (inst->getOperand1()->isRelaxedPrecision() &&
  91. inst->getOperand2()->isRelaxedPrecision())
  92. inst->setRelaxedPrecision();
  93. return true;
  94. }
  95. bool RelaxedPrecisionVisitor::visit(SpirvLoad *inst) {
  96. // If loading from a RelaxedPrecision variable, the result is also decorated
  97. // with RelaxedPrecision.
  98. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  99. inst->setRelaxedPrecision();
  100. return true;
  101. }
  102. bool RelaxedPrecisionVisitor::visit(SpirvStore *inst) { return true; }
  103. bool RelaxedPrecisionVisitor::visit(SpirvSelect *inst) {
  104. if (inst->getTrueObject()->isRelaxedPrecision() &&
  105. inst->getFalseObject()->isRelaxedPrecision())
  106. inst->setRelaxedPrecision();
  107. return true;
  108. }
  109. bool RelaxedPrecisionVisitor::visit(SpirvFunctionCall *inst) {
  110. // If the return type of the function is RelaxedPrecision, we can decorate the
  111. // result-id of the OpFunctionCall.
  112. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  113. inst->setRelaxedPrecision();
  114. return true;
  115. }
  116. bool RelaxedPrecisionVisitor::visit(SpirvExtInst *inst) {
  117. // If all operands to numeric instructions in GLSL extended instruction set is
  118. // RelaxedPrecision, the result of the opration is also RelaxedPrecision.
  119. if (inst->getInstructionSet()->getExtendedInstSetName() == "GLSL.std.450") {
  120. const auto &operands = inst->getOperands();
  121. if (std::all_of(operands.begin(), operands.end(), [](SpirvInstruction *op) {
  122. return op->isRelaxedPrecision();
  123. })) {
  124. inst->setRelaxedPrecision();
  125. }
  126. }
  127. return true;
  128. }
  129. bool RelaxedPrecisionVisitor::visit(SpirvCompositeInsert *inst) {
  130. // If inserting a RelaxedPrecision object into a composite, check the type of
  131. // the resulting composite. For example: if you are inserting a
  132. // RelaxedPrecision object as a member into a structure, the resulting
  133. // structure type is not RelaxedPrecision. But, if you are inserting a
  134. // RelaxedPrecision object into a vector of RelaxedPrecision integers, the
  135. // resulting composite *is* RelaxedPrecision.
  136. // In short, it simply depends on the composite type.
  137. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  138. inst->setRelaxedPrecision();
  139. return true;
  140. }
  141. bool RelaxedPrecisionVisitor::visit(SpirvCompositeExtract *inst) {
  142. // If extracting a RelaxedPrecision object from a composite, check the type of
  143. // the extracted object. For example: if extracting different members of a
  144. // structure, depending on the member, you may or may not want to apply the
  145. // RelaxedPrecision decoration.
  146. // In short, it simply depends on the type of what you have extracted.
  147. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  148. inst->setRelaxedPrecision();
  149. return true;
  150. }
  151. bool RelaxedPrecisionVisitor::visit(SpirvCompositeConstruct *inst) {
  152. // When constructing a composite, only look at the type of the resulting
  153. // composite.
  154. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  155. inst->setRelaxedPrecision();
  156. return true;
  157. }
  158. bool RelaxedPrecisionVisitor::visit(SpirvConstantBoolean *) {
  159. // Booleans do not have precision!
  160. return true;
  161. }
  162. bool RelaxedPrecisionVisitor::visit(SpirvConstantInteger *inst) {
  163. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  164. inst->setRelaxedPrecision();
  165. return true;
  166. }
  167. bool RelaxedPrecisionVisitor::visit(SpirvConstantFloat *inst) {
  168. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  169. inst->setRelaxedPrecision();
  170. return true;
  171. }
  172. bool RelaxedPrecisionVisitor::visit(SpirvConstantComposite *inst) {
  173. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  174. inst->setRelaxedPrecision();
  175. return true;
  176. }
  177. bool RelaxedPrecisionVisitor::visit(SpirvBitFieldExtract *inst) {
  178. if (inst->getBase()->isRelaxedPrecision())
  179. inst->setRelaxedPrecision();
  180. return true;
  181. }
  182. bool RelaxedPrecisionVisitor::visit(SpirvBitFieldInsert *inst) {
  183. if (inst->getBase()->isRelaxedPrecision())
  184. inst->setRelaxedPrecision();
  185. return true;
  186. }
  187. bool RelaxedPrecisionVisitor::visit(SpirvAtomic *inst) {
  188. // If the original pointer is RelaxedPrecision or operating on a value that is
  189. // RelaxedPrecision, result is RelaxedPrecision.
  190. if (inst->getPointer()->isRelaxedPrecision()) {
  191. if (!inst->hasValue() ||
  192. (inst->hasValue() && inst->getValue()->isRelaxedPrecision()))
  193. inst->setRelaxedPrecision();
  194. }
  195. return true;
  196. }
  197. bool RelaxedPrecisionVisitor::visit(SpirvAccessChain *) {
  198. // The access chain operation itself is irrelevant regarding precision.
  199. return true;
  200. }
  201. bool RelaxedPrecisionVisitor::visit(SpirvFunctionParameter *inst) {
  202. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  203. inst->setRelaxedPrecision();
  204. return true;
  205. }
  206. bool RelaxedPrecisionVisitor::visit(SpirvVariable *inst) {
  207. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  208. inst->setRelaxedPrecision();
  209. return true;
  210. }
  211. bool RelaxedPrecisionVisitor::visit(SpirvImageOp *inst) {
  212. // If the operation result type or the underlying image type is relaxed
  213. // precision, the instruction can be considered relaxed precision.
  214. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions) ||
  215. isRelaxedPrecisionType(inst->getImage()->getAstResultType(), spvOptions))
  216. inst->setRelaxedPrecision();
  217. return true;
  218. }
  219. } // end namespace spirv
  220. } // namespace clang