ir_loader_test.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. // Copyright (c) 2016 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <algorithm>
  15. #include <memory>
  16. #include <string>
  17. #include <unordered_set>
  18. #include <utility>
  19. #include <vector>
  20. #include "gtest/gtest.h"
  21. #include "source/opt/build_module.h"
  22. #include "source/opt/ir_context.h"
  23. #include "spirv-tools/libspirv.hpp"
  24. namespace spvtools {
  25. namespace opt {
  26. namespace {
  27. void DoRoundTripCheck(const std::string& text) {
  28. SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
  29. std::unique_ptr<IRContext> context =
  30. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
  31. ASSERT_NE(nullptr, context) << "Failed to assemble\n" << text;
  32. std::vector<uint32_t> binary;
  33. context->module()->ToBinary(&binary, /* skip_nop = */ false);
  34. std::string disassembled_text;
  35. EXPECT_TRUE(t.Disassemble(binary, &disassembled_text));
  36. EXPECT_EQ(text, disassembled_text);
  37. }
  38. TEST(IrBuilder, RoundTrip) {
  39. // #version 310 es
  40. // int add(int a, int b) { return a + b; }
  41. // void main() { add(1, 2); }
  42. DoRoundTripCheck(
  43. // clang-format off
  44. "OpCapability Shader\n"
  45. "%1 = OpExtInstImport \"GLSL.std.450\"\n"
  46. "OpMemoryModel Logical GLSL450\n"
  47. "OpEntryPoint Vertex %main \"main\"\n"
  48. "OpSource ESSL 310\n"
  49. "OpSourceExtension \"GL_GOOGLE_cpp_style_line_directive\"\n"
  50. "OpSourceExtension \"GL_GOOGLE_include_directive\"\n"
  51. "OpName %main \"main\"\n"
  52. "OpName %add_i1_i1_ \"add(i1;i1;\"\n"
  53. "OpName %a \"a\"\n"
  54. "OpName %b \"b\"\n"
  55. "OpName %param \"param\"\n"
  56. "OpName %param_0 \"param\"\n"
  57. "%void = OpTypeVoid\n"
  58. "%9 = OpTypeFunction %void\n"
  59. "%int = OpTypeInt 32 1\n"
  60. "%_ptr_Function_int = OpTypePointer Function %int\n"
  61. "%12 = OpTypeFunction %int %_ptr_Function_int %_ptr_Function_int\n"
  62. "%int_1 = OpConstant %int 1\n"
  63. "%int_2 = OpConstant %int 2\n"
  64. "%main = OpFunction %void None %9\n"
  65. "%15 = OpLabel\n"
  66. "%param = OpVariable %_ptr_Function_int Function\n"
  67. "%param_0 = OpVariable %_ptr_Function_int Function\n"
  68. "OpStore %param %int_1\n"
  69. "OpStore %param_0 %int_2\n"
  70. "%16 = OpFunctionCall %int %add_i1_i1_ %param %param_0\n"
  71. "OpReturn\n"
  72. "OpFunctionEnd\n"
  73. "%add_i1_i1_ = OpFunction %int None %12\n"
  74. "%a = OpFunctionParameter %_ptr_Function_int\n"
  75. "%b = OpFunctionParameter %_ptr_Function_int\n"
  76. "%17 = OpLabel\n"
  77. "%18 = OpLoad %int %a\n"
  78. "%19 = OpLoad %int %b\n"
  79. "%20 = OpIAdd %int %18 %19\n"
  80. "OpReturnValue %20\n"
  81. "OpFunctionEnd\n");
  82. // clang-format on
  83. }
  84. TEST(IrBuilder, RoundTripIncompleteBasicBlock) {
  85. DoRoundTripCheck(
  86. "%2 = OpFunction %1 None %3\n"
  87. "%4 = OpLabel\n"
  88. "OpNop\n");
  89. }
  90. TEST(IrBuilder, RoundTripIncompleteFunction) {
  91. DoRoundTripCheck("%2 = OpFunction %1 None %3\n");
  92. }
  93. TEST(IrBuilder, KeepLineDebugInfo) {
  94. // #version 310 es
  95. // void main() {}
  96. DoRoundTripCheck(
  97. // clang-format off
  98. "OpCapability Shader\n"
  99. "%1 = OpExtInstImport \"GLSL.std.450\"\n"
  100. "OpMemoryModel Logical GLSL450\n"
  101. "OpEntryPoint Vertex %main \"main\"\n"
  102. "%3 = OpString \"minimal.vert\"\n"
  103. "OpSource ESSL 310\n"
  104. "OpName %main \"main\"\n"
  105. "OpLine %3 10 10\n"
  106. "%void = OpTypeVoid\n"
  107. "OpLine %3 100 100\n"
  108. "%5 = OpTypeFunction %void\n"
  109. "%main = OpFunction %void None %5\n"
  110. "OpLine %3 1 1\n"
  111. "OpNoLine\n"
  112. "OpLine %3 2 2\n"
  113. "OpLine %3 3 3\n"
  114. "%6 = OpLabel\n"
  115. "OpLine %3 4 4\n"
  116. "OpNoLine\n"
  117. "OpReturn\n"
  118. "OpFunctionEnd\n");
  119. // clang-format on
  120. }
  121. TEST(IrBuilder, LocalGlobalVariables) {
  122. // #version 310 es
  123. //
  124. // float gv1 = 10.;
  125. // float gv2 = 100.;
  126. //
  127. // float f() {
  128. // float lv1 = gv1 + gv2;
  129. // float lv2 = gv1 * gv2;
  130. // return lv1 / lv2;
  131. // }
  132. //
  133. // void main() {
  134. // float lv1 = gv1 - gv2;
  135. // }
  136. DoRoundTripCheck(
  137. // clang-format off
  138. "OpCapability Shader\n"
  139. "%1 = OpExtInstImport \"GLSL.std.450\"\n"
  140. "OpMemoryModel Logical GLSL450\n"
  141. "OpEntryPoint Vertex %main \"main\"\n"
  142. "OpSource ESSL 310\n"
  143. "OpName %main \"main\"\n"
  144. "OpName %f_ \"f(\"\n"
  145. "OpName %gv1 \"gv1\"\n"
  146. "OpName %gv2 \"gv2\"\n"
  147. "OpName %lv1 \"lv1\"\n"
  148. "OpName %lv2 \"lv2\"\n"
  149. "OpName %lv1_0 \"lv1\"\n"
  150. "%void = OpTypeVoid\n"
  151. "%10 = OpTypeFunction %void\n"
  152. "%float = OpTypeFloat 32\n"
  153. "%12 = OpTypeFunction %float\n"
  154. "%_ptr_Private_float = OpTypePointer Private %float\n"
  155. "%gv1 = OpVariable %_ptr_Private_float Private\n"
  156. "%float_10 = OpConstant %float 10\n"
  157. "%gv2 = OpVariable %_ptr_Private_float Private\n"
  158. "%float_100 = OpConstant %float 100\n"
  159. "%_ptr_Function_float = OpTypePointer Function %float\n"
  160. "%main = OpFunction %void None %10\n"
  161. "%17 = OpLabel\n"
  162. "%lv1_0 = OpVariable %_ptr_Function_float Function\n"
  163. "OpStore %gv1 %float_10\n"
  164. "OpStore %gv2 %float_100\n"
  165. "%18 = OpLoad %float %gv1\n"
  166. "%19 = OpLoad %float %gv2\n"
  167. "%20 = OpFSub %float %18 %19\n"
  168. "OpStore %lv1_0 %20\n"
  169. "OpReturn\n"
  170. "OpFunctionEnd\n"
  171. "%f_ = OpFunction %float None %12\n"
  172. "%21 = OpLabel\n"
  173. "%lv1 = OpVariable %_ptr_Function_float Function\n"
  174. "%lv2 = OpVariable %_ptr_Function_float Function\n"
  175. "%22 = OpLoad %float %gv1\n"
  176. "%23 = OpLoad %float %gv2\n"
  177. "%24 = OpFAdd %float %22 %23\n"
  178. "OpStore %lv1 %24\n"
  179. "%25 = OpLoad %float %gv1\n"
  180. "%26 = OpLoad %float %gv2\n"
  181. "%27 = OpFMul %float %25 %26\n"
  182. "OpStore %lv2 %27\n"
  183. "%28 = OpLoad %float %lv1\n"
  184. "%29 = OpLoad %float %lv2\n"
  185. "%30 = OpFDiv %float %28 %29\n"
  186. "OpReturnValue %30\n"
  187. "OpFunctionEnd\n");
  188. // clang-format on
  189. }
  190. TEST(IrBuilder, OpUndefOutsideFunction) {
  191. // #version 310 es
  192. // void main() {}
  193. const std::string text =
  194. // clang-format off
  195. "OpMemoryModel Logical GLSL450\n"
  196. "%int = OpTypeInt 32 1\n"
  197. "%uint = OpTypeInt 32 0\n"
  198. "%float = OpTypeFloat 32\n"
  199. "%4 = OpUndef %int\n"
  200. "%int_10 = OpConstant %int 10\n"
  201. "%6 = OpUndef %uint\n"
  202. "%bool = OpTypeBool\n"
  203. "%8 = OpUndef %float\n"
  204. "%double = OpTypeFloat 64\n";
  205. // clang-format on
  206. SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
  207. std::unique_ptr<IRContext> context =
  208. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
  209. ASSERT_NE(nullptr, context);
  210. const auto opundef_count = std::count_if(
  211. context->module()->types_values_begin(),
  212. context->module()->types_values_end(),
  213. [](const Instruction& inst) { return inst.opcode() == SpvOpUndef; });
  214. EXPECT_EQ(3, opundef_count);
  215. std::vector<uint32_t> binary;
  216. context->module()->ToBinary(&binary, /* skip_nop = */ false);
  217. std::string disassembled_text;
  218. EXPECT_TRUE(t.Disassemble(binary, &disassembled_text));
  219. EXPECT_EQ(text, disassembled_text);
  220. }
  221. TEST(IrBuilder, OpUndefInBasicBlock) {
  222. DoRoundTripCheck(
  223. // clang-format off
  224. "OpMemoryModel Logical GLSL450\n"
  225. "OpName %main \"main\"\n"
  226. "%void = OpTypeVoid\n"
  227. "%uint = OpTypeInt 32 0\n"
  228. "%double = OpTypeFloat 64\n"
  229. "%5 = OpTypeFunction %void\n"
  230. "%main = OpFunction %void None %5\n"
  231. "%6 = OpLabel\n"
  232. "%7 = OpUndef %uint\n"
  233. "%8 = OpUndef %double\n"
  234. "OpReturn\n"
  235. "OpFunctionEnd\n");
  236. // clang-format on
  237. }
  238. TEST(IrBuilder, KeepLineDebugInfoBeforeType) {
  239. DoRoundTripCheck(
  240. // clang-format off
  241. "OpCapability Shader\n"
  242. "OpMemoryModel Logical GLSL450\n"
  243. "%1 = OpString \"minimal.vert\"\n"
  244. "OpLine %1 1 1\n"
  245. "OpNoLine\n"
  246. "%void = OpTypeVoid\n"
  247. "OpLine %1 2 2\n"
  248. "%3 = OpTypeFunction %void\n");
  249. // clang-format on
  250. }
  251. TEST(IrBuilder, KeepLineDebugInfoBeforeLabel) {
  252. DoRoundTripCheck(
  253. // clang-format off
  254. "OpCapability Shader\n"
  255. "OpMemoryModel Logical GLSL450\n"
  256. "%1 = OpString \"minimal.vert\"\n"
  257. "%void = OpTypeVoid\n"
  258. "%3 = OpTypeFunction %void\n"
  259. "%4 = OpFunction %void None %3\n"
  260. "%5 = OpLabel\n"
  261. "OpBranch %6\n"
  262. "OpLine %1 1 1\n"
  263. "OpLine %1 2 2\n"
  264. "%6 = OpLabel\n"
  265. "OpBranch %7\n"
  266. "OpLine %1 100 100\n"
  267. "%7 = OpLabel\n"
  268. "OpReturn\n"
  269. "OpFunctionEnd\n");
  270. // clang-format on
  271. }
  272. TEST(IrBuilder, KeepLineDebugInfoBeforeFunctionEnd) {
  273. DoRoundTripCheck(
  274. // clang-format off
  275. "OpCapability Shader\n"
  276. "OpMemoryModel Logical GLSL450\n"
  277. "%1 = OpString \"minimal.vert\"\n"
  278. "%void = OpTypeVoid\n"
  279. "%3 = OpTypeFunction %void\n"
  280. "%4 = OpFunction %void None %3\n"
  281. "OpLine %1 1 1\n"
  282. "OpLine %1 2 2\n"
  283. "OpFunctionEnd\n");
  284. // clang-format on
  285. }
  286. TEST(IrBuilder, KeepModuleProcessedInRightPlace) {
  287. DoRoundTripCheck(
  288. // clang-format off
  289. "OpCapability Shader\n"
  290. "OpMemoryModel Logical GLSL450\n"
  291. "%1 = OpString \"minimal.vert\"\n"
  292. "OpName %void \"void\"\n"
  293. "OpModuleProcessed \"Made it faster\"\n"
  294. "OpModuleProcessed \".. and smaller\"\n"
  295. "%void = OpTypeVoid\n");
  296. // clang-format on
  297. }
  298. // Checks the given |error_message| is reported when trying to build a module
  299. // from the given |assembly|.
  300. void DoErrorMessageCheck(const std::string& assembly,
  301. const std::string& error_message, uint32_t line_num) {
  302. auto consumer = [error_message, line_num](spv_message_level_t, const char*,
  303. const spv_position_t& position,
  304. const char* m) {
  305. EXPECT_EQ(error_message, m);
  306. EXPECT_EQ(line_num, position.line);
  307. };
  308. SpirvTools t(SPV_ENV_UNIVERSAL_1_1);
  309. std::unique_ptr<IRContext> context =
  310. BuildModule(SPV_ENV_UNIVERSAL_1_1, std::move(consumer), assembly);
  311. EXPECT_EQ(nullptr, context);
  312. }
  313. TEST(IrBuilder, FunctionInsideFunction) {
  314. DoErrorMessageCheck("%2 = OpFunction %1 None %3\n%5 = OpFunction %4 None %6",
  315. "function inside function", 2);
  316. }
  317. TEST(IrBuilder, MismatchOpFunctionEnd) {
  318. DoErrorMessageCheck("OpFunctionEnd",
  319. "OpFunctionEnd without corresponding OpFunction", 1);
  320. }
  321. TEST(IrBuilder, OpFunctionEndInsideBasicBlock) {
  322. DoErrorMessageCheck(
  323. "%2 = OpFunction %1 None %3\n"
  324. "%4 = OpLabel\n"
  325. "OpFunctionEnd",
  326. "OpFunctionEnd inside basic block", 3);
  327. }
  328. TEST(IrBuilder, BasicBlockOutsideFunction) {
  329. DoErrorMessageCheck("OpCapability Shader\n%1 = OpLabel",
  330. "OpLabel outside function", 2);
  331. }
  332. TEST(IrBuilder, OpLabelInsideBasicBlock) {
  333. DoErrorMessageCheck(
  334. "%2 = OpFunction %1 None %3\n"
  335. "%4 = OpLabel\n"
  336. "%5 = OpLabel",
  337. "OpLabel inside basic block", 3);
  338. }
  339. TEST(IrBuilder, TerminatorOutsideFunction) {
  340. DoErrorMessageCheck("OpReturn", "terminator instruction outside function", 1);
  341. }
  342. TEST(IrBuilder, TerminatorOutsideBasicBlock) {
  343. DoErrorMessageCheck("%2 = OpFunction %1 None %3\nOpReturn",
  344. "terminator instruction outside basic block", 2);
  345. }
  346. TEST(IrBuilder, NotAllowedInstAppearingInFunction) {
  347. DoErrorMessageCheck("%2 = OpFunction %1 None %3\n%5 = OpVariable %4 Function",
  348. "Non-OpFunctionParameter (opcode: 59) found inside "
  349. "function but outside basic block",
  350. 2);
  351. }
  352. TEST(IrBuilder, UniqueIds) {
  353. const std::string text =
  354. // clang-format off
  355. "OpCapability Shader\n"
  356. "%1 = OpExtInstImport \"GLSL.std.450\"\n"
  357. "OpMemoryModel Logical GLSL450\n"
  358. "OpEntryPoint Vertex %main \"main\"\n"
  359. "OpSource ESSL 310\n"
  360. "OpName %main \"main\"\n"
  361. "OpName %f_ \"f(\"\n"
  362. "OpName %gv1 \"gv1\"\n"
  363. "OpName %gv2 \"gv2\"\n"
  364. "OpName %lv1 \"lv1\"\n"
  365. "OpName %lv2 \"lv2\"\n"
  366. "OpName %lv1_0 \"lv1\"\n"
  367. "%void = OpTypeVoid\n"
  368. "%10 = OpTypeFunction %void\n"
  369. "%float = OpTypeFloat 32\n"
  370. "%12 = OpTypeFunction %float\n"
  371. "%_ptr_Private_float = OpTypePointer Private %float\n"
  372. "%gv1 = OpVariable %_ptr_Private_float Private\n"
  373. "%float_10 = OpConstant %float 10\n"
  374. "%gv2 = OpVariable %_ptr_Private_float Private\n"
  375. "%float_100 = OpConstant %float 100\n"
  376. "%_ptr_Function_float = OpTypePointer Function %float\n"
  377. "%main = OpFunction %void None %10\n"
  378. "%17 = OpLabel\n"
  379. "%lv1_0 = OpVariable %_ptr_Function_float Function\n"
  380. "OpStore %gv1 %float_10\n"
  381. "OpStore %gv2 %float_100\n"
  382. "%18 = OpLoad %float %gv1\n"
  383. "%19 = OpLoad %float %gv2\n"
  384. "%20 = OpFSub %float %18 %19\n"
  385. "OpStore %lv1_0 %20\n"
  386. "OpReturn\n"
  387. "OpFunctionEnd\n"
  388. "%f_ = OpFunction %float None %12\n"
  389. "%21 = OpLabel\n"
  390. "%lv1 = OpVariable %_ptr_Function_float Function\n"
  391. "%lv2 = OpVariable %_ptr_Function_float Function\n"
  392. "%22 = OpLoad %float %gv1\n"
  393. "%23 = OpLoad %float %gv2\n"
  394. "%24 = OpFAdd %float %22 %23\n"
  395. "OpStore %lv1 %24\n"
  396. "%25 = OpLoad %float %gv1\n"
  397. "%26 = OpLoad %float %gv2\n"
  398. "%27 = OpFMul %float %25 %26\n"
  399. "OpStore %lv2 %27\n"
  400. "%28 = OpLoad %float %lv1\n"
  401. "%29 = OpLoad %float %lv2\n"
  402. "%30 = OpFDiv %float %28 %29\n"
  403. "OpReturnValue %30\n"
  404. "OpFunctionEnd\n";
  405. // clang-format on
  406. std::unique_ptr<IRContext> context =
  407. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text);
  408. ASSERT_NE(nullptr, context);
  409. std::unordered_set<uint32_t> ids;
  410. context->module()->ForEachInst([&ids](const Instruction* inst) {
  411. EXPECT_TRUE(ids.insert(inst->unique_id()).second);
  412. });
  413. }
  414. } // namespace
  415. } // namespace opt
  416. } // namespace spvtools