StructureTest.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. //===- unittests/SPIRV/StructureTest.cpp ------ SPIR-V structures tests ---===//
  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/Structure.h"
  10. #include "SPIRVTestUtils.h"
  11. #include "clang/SPIRV/SPIRVContext.h"
  12. namespace {
  13. using namespace clang::spirv;
  14. using ::testing::ContainerEq;
  15. TEST(Structure, InstructionHasCorrectOpcode) {
  16. Instruction inst(constructInst(spv::Op::OpIAdd, {1, 2, 3, 4}));
  17. ASSERT_TRUE(!inst.isEmpty());
  18. EXPECT_EQ(inst.getOpcode(), spv::Op::OpIAdd);
  19. }
  20. TEST(Structure, InstructionGetOriginalContents) {
  21. Instruction inst(constructInst(spv::Op::OpIAdd, {1, 2, 3, 4}));
  22. EXPECT_THAT(inst.take(),
  23. ContainerEq(constructInst(spv::Op::OpIAdd, {1, 2, 3, 4})));
  24. }
  25. TEST(Structure, InstructionIsTerminator) {
  26. for (auto opcode :
  27. {spv::Op::OpKill, spv::Op::OpUnreachable, spv::Op::OpBranch,
  28. spv::Op::OpBranchConditional, spv::Op::OpSwitch, spv::Op::OpReturn,
  29. spv::Op::OpReturnValue}) {
  30. Instruction inst(constructInst(opcode, {/* wrong params here */ 1}));
  31. EXPECT_TRUE(inst.isTerminator());
  32. }
  33. }
  34. TEST(Structure, InstructionIsNotTerminator) {
  35. for (auto opcode : {spv::Op::OpNop, spv::Op::OpAccessChain, spv::Op::OpAll}) {
  36. Instruction inst(constructInst(opcode, {/* wrong params here */ 1}));
  37. EXPECT_FALSE(inst.isTerminator());
  38. }
  39. }
  40. TEST(Structure, TakeBasicBlockHaveAllContents) {
  41. std::vector<uint32_t> result;
  42. auto ib = constructInstBuilder(result);
  43. auto bb = BasicBlock(42);
  44. bb.appendInstruction(constructInst(spv::Op::OpReturn, {}));
  45. bb.take(&ib);
  46. SimpleInstBuilder sib;
  47. sib.inst(spv::Op::OpLabel, {42});
  48. sib.inst(spv::Op::OpReturn, {});
  49. EXPECT_THAT(result, ContainerEq(sib.get()));
  50. EXPECT_TRUE(bb.isEmpty());
  51. }
  52. TEST(Structure, AfterClearBasicBlockIsEmpty) {
  53. auto bb = BasicBlock(42);
  54. bb.appendInstruction(constructInst(spv::Op::OpNop, {}));
  55. EXPECT_FALSE(bb.isEmpty());
  56. bb.clear();
  57. EXPECT_TRUE(bb.isEmpty());
  58. }
  59. TEST(Structure, TakeFunctionHaveAllContents) {
  60. auto f = Function(1, 2, spv::FunctionControlMask::Inline, 3);
  61. f.addParameter(1, 42);
  62. auto bb = llvm::make_unique<BasicBlock>(10);
  63. bb->appendInstruction(constructInst(spv::Op::OpReturn, {}));
  64. f.addBasicBlock(std::move(bb));
  65. std::vector<uint32_t> result;
  66. auto ib = constructInstBuilder(result);
  67. f.take(&ib);
  68. SimpleInstBuilder sib;
  69. sib.inst(spv::Op::OpFunction, {1, 2, 1, 3});
  70. sib.inst(spv::Op::OpFunctionParameter, {1, 42});
  71. sib.inst(spv::Op::OpLabel, {10});
  72. sib.inst(spv::Op::OpReturn, {});
  73. sib.inst(spv::Op::OpFunctionEnd, {});
  74. EXPECT_THAT(result, ContainerEq(sib.get()));
  75. EXPECT_TRUE(f.isEmpty());
  76. }
  77. TEST(Structure, AfterClearFunctionIsEmpty) {
  78. auto f = Function(1, 2, spv::FunctionControlMask::Inline, 3);
  79. f.addParameter(1, 42);
  80. EXPECT_FALSE(f.isEmpty());
  81. f.clear();
  82. EXPECT_TRUE(f.isEmpty());
  83. }
  84. TEST(Structure, DefaultConstructedModuleIsEmpty) {
  85. auto m = SPIRVModule();
  86. EXPECT_TRUE(m.isEmpty());
  87. }
  88. TEST(Structure, AfterClearModuleIsEmpty) {
  89. auto m = SPIRVModule();
  90. m.setBound(12);
  91. EXPECT_FALSE(m.isEmpty());
  92. m.clear();
  93. EXPECT_TRUE(m.isEmpty());
  94. }
  95. TEST(Structure, TakeModuleHaveAllContents) {
  96. SPIRVContext context;
  97. auto m = SPIRVModule();
  98. // Will fix up the bound later.
  99. SimpleInstBuilder sib(0);
  100. m.addCapability(spv::Capability::Shader);
  101. sib.inst(spv::Op::OpCapability,
  102. {static_cast<uint32_t>(spv::Capability::Shader)});
  103. m.addExtension("ext");
  104. const uint32_t extWord = 'e' | ('x' << 8) | ('t' << 16);
  105. sib.inst(spv::Op::OpExtension, {extWord});
  106. const uint32_t extInstSetId = context.takeNextId();
  107. m.addExtInstSet(extInstSetId, "gl");
  108. const uint32_t glWord = 'g' | ('l' << 8);
  109. sib.inst(spv::Op::OpExtInstImport, {extInstSetId, glWord});
  110. m.setAddressingModel(spv::AddressingModel::Logical);
  111. m.setMemoryModel(spv::MemoryModel::GLSL450);
  112. sib.inst(spv::Op::OpMemoryModel,
  113. {static_cast<uint32_t>(spv::AddressingModel::Logical),
  114. static_cast<uint32_t>(spv::MemoryModel::GLSL450)});
  115. const uint32_t entryPointId = context.takeNextId();
  116. m.addEntryPoint(spv::ExecutionModel::Fragment, entryPointId, "main", {42});
  117. const uint32_t mainWord = 'm' | ('a' << 8) | ('i' << 16) | ('n' << 24);
  118. sib.inst(spv::Op::OpEntryPoint,
  119. {static_cast<uint32_t>(spv::ExecutionModel::Fragment), entryPointId,
  120. mainWord, /* addtional null in name */ 0, 42});
  121. m.addExecutionMode(constructInst(
  122. spv::Op::OpExecutionMode,
  123. {entryPointId,
  124. static_cast<uint32_t>(spv::ExecutionMode::OriginUpperLeft)}));
  125. sib.inst(spv::Op::OpExecutionMode,
  126. {entryPointId,
  127. static_cast<uint32_t>(spv::ExecutionMode::OriginUpperLeft)});
  128. // TODO: source code debug information
  129. m.addDebugName(entryPointId, "main");
  130. sib.inst(spv::Op::OpName,
  131. {entryPointId, mainWord, /* additional null in name */ 0});
  132. m.addDecoration(Decoration::getRelaxedPrecision(context), entryPointId);
  133. sib.inst(
  134. spv::Op::OpDecorate,
  135. {entryPointId, static_cast<uint32_t>(spv::Decoration::RelaxedPrecision)});
  136. const auto *i32Type = Type::getInt32(context);
  137. const uint32_t i32Id = context.getResultIdForType(i32Type);
  138. m.addType(i32Type, i32Id);
  139. sib.inst(spv::Op::OpTypeInt, {i32Id, 32, 1});
  140. const auto *voidType = Type::getVoid(context);
  141. const uint32_t voidId = context.getResultIdForType(voidType);
  142. m.addType(voidType, voidId);
  143. sib.inst(spv::Op::OpTypeVoid, {voidId});
  144. const auto *funcType = Type::getFunction(context, voidId, {voidId});
  145. const uint32_t funcTypeId = context.getResultIdForType(funcType);
  146. m.addType(funcType, funcTypeId);
  147. sib.inst(spv::Op::OpTypeFunction, {funcTypeId, voidId, voidId});
  148. const auto *i32Const = Constant::getInt32(context, i32Id, 42);
  149. const uint32_t constantId = context.takeNextId();
  150. m.addConstant(i32Const, constantId);
  151. sib.inst(spv::Op::OpConstant, {i32Id, constantId, 42});
  152. const uint32_t varId = context.takeNextId();
  153. m.addVariable(constructInst(
  154. spv::Op::OpVariable,
  155. {i32Id, varId, static_cast<uint32_t>(spv::StorageClass::Input)}));
  156. sib.inst(spv::Op::OpVariable,
  157. {i32Id, varId, static_cast<uint32_t>(spv::StorageClass::Input)});
  158. const uint32_t funcId = context.takeNextId();
  159. auto f = llvm::make_unique<Function>(
  160. voidId, funcId, spv::FunctionControlMask::MaskNone, funcTypeId);
  161. const uint32_t bbId = context.takeNextId();
  162. auto bb = llvm::make_unique<BasicBlock>(bbId);
  163. bb->appendInstruction(constructInst(spv::Op::OpReturn, {}));
  164. f->addBasicBlock(std::move(bb));
  165. m.addFunction(std::move(f));
  166. sib.inst(spv::Op::OpFunction, {voidId, funcId, 0, funcTypeId});
  167. sib.inst(spv::Op::OpLabel, {bbId});
  168. sib.inst(spv::Op::OpReturn, {});
  169. sib.inst(spv::Op::OpFunctionEnd, {});
  170. m.setBound(context.getNextId());
  171. std::vector<uint32_t> expected = sib.get();
  172. expected[3] = context.getNextId();
  173. std::vector<uint32_t> result;
  174. auto ib = constructInstBuilder(result);
  175. m.take(&ib);
  176. EXPECT_THAT(result, ContainerEq(expected));
  177. EXPECT_TRUE(m.isEmpty());
  178. }
  179. TEST(Structure, TakeModuleWithArrayAndConstantDependency) {
  180. SPIRVContext context;
  181. auto m = SPIRVModule();
  182. // Will fix up the id bound later.
  183. SimpleInstBuilder sib(0);
  184. // Add void type
  185. const auto *voidType = Type::getVoid(context);
  186. const uint32_t voidId = context.getResultIdForType(voidType);
  187. m.addType(voidType, voidId);
  188. // Add float type
  189. const auto *f32Type = Type::getFloat32(context);
  190. const uint32_t f32Id = context.getResultIdForType(f32Type);
  191. m.addType(f32Type, f32Id);
  192. // Add int64 type
  193. const auto *i64Type = Type::getInt64(context);
  194. const uint32_t i64Id = context.getResultIdForType(i64Type);
  195. m.addType(i64Type, i64Id);
  196. // Add int32 type
  197. const auto *i32Type = Type::getInt32(context);
  198. const uint32_t i32Id = context.getResultIdForType(i32Type);
  199. m.addType(i32Type, i32Id);
  200. // Add 32-bit integer constant (8)
  201. const auto *i32Const = Constant::getInt32(context, i32Id, 8);
  202. const uint32_t constantId = context.getResultIdForConstant(i32Const);
  203. m.addConstant(i32Const, constantId);
  204. // Add array of 8 32-bit integers type
  205. const auto *arrType = Type::getArray(context, i32Id, constantId);
  206. const uint32_t arrId = context.getResultIdForType(arrType);
  207. m.addType(arrType, arrId);
  208. m.setBound(context.getNextId());
  209. // Add another array of the same size. The constant does not need to be
  210. // redefined.
  211. const auto *arrStride = Decoration::getArrayStride(context, 4);
  212. const auto *secondArrType =
  213. Type::getArray(context, i32Id, constantId, {arrStride});
  214. const uint32_t secondArrId = context.getResultIdForType(arrType);
  215. m.addType(secondArrType, secondArrId);
  216. m.addDecoration(arrStride, secondArrId);
  217. m.setBound(context.getNextId());
  218. // Decorations
  219. sib.inst(
  220. spv::Op::OpDecorate,
  221. {secondArrId, static_cast<uint32_t>(spv::Decoration::ArrayStride), 4});
  222. // Now the expected order: void, float, int64, int32, constant(8), array
  223. sib.inst(spv::Op::OpTypeVoid, {voidId});
  224. sib.inst(spv::Op::OpTypeFloat, {f32Id, 32});
  225. sib.inst(spv::Op::OpTypeInt, {i64Id, 64, 1});
  226. sib.inst(spv::Op::OpTypeInt, {i32Id, 32, 1});
  227. sib.inst(spv::Op::OpConstant, {i32Id, constantId, 8});
  228. sib.inst(spv::Op::OpTypeArray, {arrId, i32Id, constantId});
  229. sib.inst(spv::Op::OpTypeArray, {secondArrId, i32Id, constantId});
  230. std::vector<uint32_t> expected = sib.get();
  231. expected[3] = context.getNextId();
  232. std::vector<uint32_t> result;
  233. auto ib = constructInstBuilder(result);
  234. m.take(&ib);
  235. EXPECT_THAT(result, ContainerEq(expected));
  236. EXPECT_TRUE(m.isEmpty());
  237. }
  238. } // anonymous namespace