RelaxedPrecisionVisitor.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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 and the unary
  67. // operation is operating on numerical values, the result is also
  68. // RelaxedPrecision.
  69. if (inst->getOperand()->isRelaxedPrecision() &&
  70. isScalarOrNonStructAggregateOfNumericalTypes(
  71. inst->getOperand()->getAstResultType()))
  72. inst->setRelaxedPrecision();
  73. return true;
  74. }
  75. bool RelaxedPrecisionVisitor::visit(SpirvBinaryOp *inst) {
  76. // If either argument of the binary operation is RelaxedPrecision, and the
  77. // binary operation is operating on numerical values, the result is also
  78. // RelaxedPrecision.
  79. if (inst->getOperand1()->isRelaxedPrecision() &&
  80. isScalarOrNonStructAggregateOfNumericalTypes(
  81. inst->getOperand1()->getAstResultType()) &&
  82. inst->getOperand2()->isRelaxedPrecision() &&
  83. isScalarOrNonStructAggregateOfNumericalTypes(
  84. inst->getOperand2()->getAstResultType()))
  85. inst->setRelaxedPrecision();
  86. return true;
  87. }
  88. bool RelaxedPrecisionVisitor::visit(SpirvSpecConstantUnaryOp *inst) {
  89. // If the argument of the unary operation is RelaxedPrecision and the unary
  90. // operation is operating on numerical values, the result is also
  91. // RelaxedPrecision.
  92. if (inst->getOperand()->isRelaxedPrecision() &&
  93. isScalarOrNonStructAggregateOfNumericalTypes(
  94. inst->getOperand()->getAstResultType()))
  95. inst->setRelaxedPrecision();
  96. return true;
  97. }
  98. bool RelaxedPrecisionVisitor::visit(SpirvSpecConstantBinaryOp *inst) {
  99. // If either argument of the binary operation is RelaxedPrecision, and the
  100. // binary operation is operating on numerical values, the result is also
  101. // RelaxedPrecision.
  102. if (inst->getOperand1()->isRelaxedPrecision() &&
  103. isScalarOrNonStructAggregateOfNumericalTypes(
  104. inst->getOperand1()->getAstResultType()) &&
  105. inst->getOperand2()->isRelaxedPrecision() &&
  106. isScalarOrNonStructAggregateOfNumericalTypes(
  107. inst->getOperand2()->getAstResultType()))
  108. inst->setRelaxedPrecision();
  109. return true;
  110. }
  111. bool RelaxedPrecisionVisitor::visit(SpirvLoad *inst) {
  112. // If loading from a RelaxedPrecision variable, the result is also decorated
  113. // with RelaxedPrecision.
  114. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  115. inst->setRelaxedPrecision();
  116. return true;
  117. }
  118. bool RelaxedPrecisionVisitor::visit(SpirvStore *inst) { return true; }
  119. bool RelaxedPrecisionVisitor::visit(SpirvSelect *inst) {
  120. if (inst->getTrueObject()->isRelaxedPrecision() &&
  121. inst->getFalseObject()->isRelaxedPrecision())
  122. inst->setRelaxedPrecision();
  123. return true;
  124. }
  125. bool RelaxedPrecisionVisitor::visit(SpirvFunctionCall *inst) {
  126. // If the return type of the function is RelaxedPrecision, we can decorate the
  127. // result-id of the OpFunctionCall.
  128. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  129. inst->setRelaxedPrecision();
  130. return true;
  131. }
  132. bool RelaxedPrecisionVisitor::visit(SpirvExtInst *inst) {
  133. // If all operands to numeric instructions in GLSL extended instruction set is
  134. // RelaxedPrecision, the result of the opration is also RelaxedPrecision.
  135. if (inst->getInstructionSet()->getExtendedInstSetName() == "GLSL.std.450") {
  136. const auto &operands = inst->getOperands();
  137. if (std::all_of(operands.begin(), operands.end(), [](SpirvInstruction *op) {
  138. return op->isRelaxedPrecision();
  139. })) {
  140. inst->setRelaxedPrecision();
  141. }
  142. }
  143. return true;
  144. }
  145. bool RelaxedPrecisionVisitor::visit(SpirvCompositeInsert *inst) {
  146. // If inserting a RelaxedPrecision object into a composite, check the type of
  147. // the resulting composite. For example: if you are inserting a
  148. // RelaxedPrecision object as a member into a structure, the resulting
  149. // structure type is not RelaxedPrecision. But, if you are inserting a
  150. // RelaxedPrecision object into a vector of RelaxedPrecision integers, the
  151. // resulting composite *is* RelaxedPrecision.
  152. // In short, it simply depends on the composite type.
  153. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  154. inst->setRelaxedPrecision();
  155. return true;
  156. }
  157. bool RelaxedPrecisionVisitor::visit(SpirvCompositeExtract *inst) {
  158. // If extracting a RelaxedPrecision object from a composite, check the type of
  159. // the extracted object. For example: if extracting different members of a
  160. // structure, depending on the member, you may or may not want to apply the
  161. // RelaxedPrecision decoration.
  162. // In short, it simply depends on the type of what you have extracted.
  163. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  164. inst->setRelaxedPrecision();
  165. return true;
  166. }
  167. bool RelaxedPrecisionVisitor::visit(SpirvCompositeConstruct *inst) {
  168. // When constructing a composite, only look at the type of the resulting
  169. // composite.
  170. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  171. inst->setRelaxedPrecision();
  172. return true;
  173. }
  174. bool RelaxedPrecisionVisitor::visit(SpirvConstantBoolean *) {
  175. // Booleans do not have precision!
  176. return true;
  177. }
  178. bool RelaxedPrecisionVisitor::visit(SpirvConstantInteger *inst) {
  179. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  180. inst->setRelaxedPrecision();
  181. return true;
  182. }
  183. bool RelaxedPrecisionVisitor::visit(SpirvConstantFloat *inst) {
  184. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  185. inst->setRelaxedPrecision();
  186. return true;
  187. }
  188. bool RelaxedPrecisionVisitor::visit(SpirvConstantComposite *inst) {
  189. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  190. inst->setRelaxedPrecision();
  191. return true;
  192. }
  193. bool RelaxedPrecisionVisitor::visit(SpirvBitFieldExtract *inst) {
  194. if (inst->getBase()->isRelaxedPrecision())
  195. inst->setRelaxedPrecision();
  196. return true;
  197. }
  198. bool RelaxedPrecisionVisitor::visit(SpirvBitFieldInsert *inst) {
  199. if (inst->getBase()->isRelaxedPrecision())
  200. inst->setRelaxedPrecision();
  201. return true;
  202. }
  203. bool RelaxedPrecisionVisitor::visit(SpirvAtomic *inst) {
  204. // If the original pointer is RelaxedPrecision or operating on a value that is
  205. // RelaxedPrecision, result is RelaxedPrecision.
  206. if (inst->getPointer()->isRelaxedPrecision()) {
  207. if (!inst->hasValue() ||
  208. (inst->hasValue() && inst->getValue()->isRelaxedPrecision()))
  209. inst->setRelaxedPrecision();
  210. }
  211. return true;
  212. }
  213. bool RelaxedPrecisionVisitor::visit(SpirvAccessChain *) {
  214. // The access chain operation itself is irrelevant regarding precision.
  215. return true;
  216. }
  217. bool RelaxedPrecisionVisitor::visit(SpirvFunctionParameter *inst) {
  218. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  219. inst->setRelaxedPrecision();
  220. return true;
  221. }
  222. bool RelaxedPrecisionVisitor::visit(SpirvVariable *inst) {
  223. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
  224. inst->setRelaxedPrecision();
  225. return true;
  226. }
  227. bool RelaxedPrecisionVisitor::visit(SpirvImageOp *inst) {
  228. // If the operation result type or the underlying image type is relaxed
  229. // precision, the instruction can be considered relaxed precision.
  230. if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions) ||
  231. isRelaxedPrecisionType(inst->getImage()->getAstResultType(), spvOptions))
  232. inst->setRelaxedPrecision();
  233. return true;
  234. }
  235. } // end namespace spirv
  236. } // namespace clang