Constant.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. //===--- Constant.cpp - SPIR-V Constant implementation --------------------===//
  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/Constant.h"
  10. #include "clang/SPIRV/BitwiseCast.h"
  11. #include "clang/SPIRV/SPIRVContext.h"
  12. namespace {
  13. uint32_t zeroExtendTo32Bits(uint16_t value) {
  14. // TODO: The ordering of the 2 words depends on the endian-ness of the host
  15. // machine. Assuming Little Endian at the moment.
  16. struct two16Bits {
  17. uint16_t low;
  18. uint16_t high;
  19. };
  20. two16Bits result = {value, 0};
  21. return clang::spirv::cast::BitwiseCast<uint32_t, two16Bits>(result);
  22. }
  23. uint32_t signExtendTo32Bits(int16_t value) {
  24. // TODO: The ordering of the 2 words depends on the endian-ness of the host
  25. // machine. Assuming Little Endian at the moment.
  26. struct two16Bits {
  27. int16_t low;
  28. uint16_t high;
  29. };
  30. two16Bits result = {value, 0};
  31. // Sign bit is 1
  32. if (value >> 15) {
  33. result.high = 0xffff;
  34. }
  35. return clang::spirv::cast::BitwiseCast<uint32_t, two16Bits>(result);
  36. }
  37. } // namespace
  38. namespace clang {
  39. namespace spirv {
  40. Constant::Constant(spv::Op op, uint32_t type, llvm::ArrayRef<uint32_t> arg)
  41. : opcode(op), typeId(type), args(arg.begin(), arg.end()) {}
  42. const Constant *Constant::getUniqueConstant(SPIRVContext &context,
  43. const Constant &c) {
  44. return context.registerConstant(c);
  45. }
  46. const Constant *Constant::getTrue(SPIRVContext &ctx, uint32_t type_id) {
  47. Constant c = Constant(spv::Op::OpConstantTrue, type_id, {});
  48. return getUniqueConstant(ctx, c);
  49. }
  50. const Constant *Constant::getFalse(SPIRVContext &ctx, uint32_t type_id) {
  51. Constant c = Constant(spv::Op::OpConstantFalse, type_id, {});
  52. return getUniqueConstant(ctx, c);
  53. }
  54. const Constant *Constant::getFloat16(SPIRVContext &ctx, uint32_t type_id,
  55. int16_t value) {
  56. // According to the SPIR-V Spec:
  57. // When the type's bit width is less than 32-bits, the literal's value appears
  58. // in the low-order bits of the word, and the high-order bits must be 0 for a
  59. // floating-point type.
  60. Constant c =
  61. Constant(spv::Op::OpConstant, type_id, {zeroExtendTo32Bits(value)});
  62. return getUniqueConstant(ctx, c);
  63. }
  64. const Constant *Constant::getFloat32(SPIRVContext &ctx, uint32_t type_id,
  65. float value) {
  66. Constant c = Constant(spv::Op::OpConstant, type_id,
  67. {cast::BitwiseCast<uint32_t, float>(value)});
  68. return getUniqueConstant(ctx, c);
  69. }
  70. const Constant *Constant::getFloat64(SPIRVContext &ctx, uint32_t type_id,
  71. double value) {
  72. // TODO: The ordering of the 2 words depends on the endian-ness of the host
  73. // machine.
  74. struct wideFloat {
  75. uint32_t word0;
  76. uint32_t word1;
  77. };
  78. wideFloat words = cast::BitwiseCast<wideFloat, double>(value);
  79. Constant c =
  80. Constant(spv::Op::OpConstant, type_id, {words.word0, words.word1});
  81. return getUniqueConstant(ctx, c);
  82. }
  83. const Constant *Constant::getUint16(SPIRVContext &ctx, uint32_t type_id,
  84. uint16_t value) {
  85. // According to the SPIR-V Spec:
  86. // When the type's bit width is less than 32-bits, the literal's value appears
  87. // in the low-order bits of the word, and the high-order bits must be 0 for an
  88. // integer type with Signedness of 0.
  89. Constant c =
  90. Constant(spv::Op::OpConstant, type_id, {zeroExtendTo32Bits(value)});
  91. return getUniqueConstant(ctx, c);
  92. }
  93. const Constant *Constant::getUint32(SPIRVContext &ctx, uint32_t type_id,
  94. uint32_t value) {
  95. Constant c = Constant(spv::Op::OpConstant, type_id, {value});
  96. return getUniqueConstant(ctx, c);
  97. }
  98. const Constant *Constant::getUint64(SPIRVContext &ctx, uint32_t type_id,
  99. uint64_t value) {
  100. struct wideInt {
  101. uint32_t word0;
  102. uint32_t word1;
  103. };
  104. wideInt words = cast::BitwiseCast<wideInt, uint64_t>(value);
  105. Constant c =
  106. Constant(spv::Op::OpConstant, type_id, {words.word0, words.word1});
  107. return getUniqueConstant(ctx, c);
  108. }
  109. const Constant *Constant::getInt16(SPIRVContext &ctx, uint32_t type_id,
  110. int16_t value) {
  111. // According to the SPIR-V Spec:
  112. // When the type's bit width is less than 32-bits, the literal's value appears
  113. // in the low-order bits of the word, and the high-order bits must be
  114. // sign-extended for integers with Signedness of 1.
  115. Constant c =
  116. Constant(spv::Op::OpConstant, type_id, {signExtendTo32Bits(value)});
  117. return getUniqueConstant(ctx, c);
  118. }
  119. const Constant *Constant::getInt32(SPIRVContext &ctx, uint32_t type_id,
  120. int32_t value) {
  121. Constant c = Constant(spv::Op::OpConstant, type_id,
  122. {cast::BitwiseCast<uint32_t, int32_t>(value)});
  123. return getUniqueConstant(ctx, c);
  124. }
  125. const Constant *Constant::getInt64(SPIRVContext &ctx, uint32_t type_id,
  126. int64_t value) {
  127. struct wideInt {
  128. uint32_t word0;
  129. uint32_t word1;
  130. };
  131. wideInt words = cast::BitwiseCast<wideInt, int64_t>(value);
  132. Constant c =
  133. Constant(spv::Op::OpConstant, type_id, {words.word0, words.word1});
  134. return getUniqueConstant(ctx, c);
  135. }
  136. const Constant *Constant::getComposite(SPIRVContext &ctx, uint32_t type_id,
  137. llvm::ArrayRef<uint32_t> constituents) {
  138. Constant c = Constant(spv::Op::OpConstantComposite, type_id, constituents);
  139. return getUniqueConstant(ctx, c);
  140. }
  141. const Constant *Constant::getSampler(SPIRVContext &ctx, uint32_t type_id,
  142. spv::SamplerAddressingMode sam,
  143. uint32_t param,
  144. spv::SamplerFilterMode sfm) {
  145. Constant c =
  146. Constant(spv::Op::OpConstantSampler, type_id,
  147. {static_cast<uint32_t>(sam), param, static_cast<uint32_t>(sfm)});
  148. return getUniqueConstant(ctx, c);
  149. }
  150. const Constant *Constant::getNull(SPIRVContext &ctx, uint32_t type_id) {
  151. Constant c = Constant(spv::Op::OpConstantNull, type_id, {});
  152. return getUniqueConstant(ctx, c);
  153. }
  154. bool Constant::isBoolean() const {
  155. return (opcode == spv::Op::OpConstantTrue ||
  156. opcode == spv::Op::OpConstantFalse ||
  157. opcode == spv::Op::OpSpecConstantTrue ||
  158. opcode == spv::Op::OpSpecConstantFalse);
  159. }
  160. bool Constant::isNumerical() const {
  161. return (opcode == spv::Op::OpConstant || opcode == spv::Op::OpSpecConstant);
  162. }
  163. bool Constant::isComposite() const {
  164. return (opcode == spv::Op::OpConstantComposite ||
  165. opcode == spv::Op::OpSpecConstantComposite);
  166. }
  167. std::vector<uint32_t> Constant::withResultId(uint32_t resultId) const {
  168. std::vector<uint32_t> words;
  169. // TODO: we are essentially duplicate the work InstBuilder is responsible for.
  170. // Should figure out a way to unify them.
  171. words.reserve(3 + args.size());
  172. words.push_back(static_cast<uint32_t>(opcode));
  173. words.push_back(typeId);
  174. words.push_back(resultId);
  175. words.insert(words.end(), args.begin(), args.end());
  176. words.front() |= static_cast<uint32_t>(words.size()) << 16;
  177. return words;
  178. }
  179. } // end namespace spirv
  180. } // end namespace clang