lcssa.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. // Copyright (c) 2018 Google LLC.
  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 <memory>
  15. #include <vector>
  16. #include "effcee/effcee.h"
  17. #include "gmock/gmock.h"
  18. #include "source/opt/build_module.h"
  19. #include "source/opt/loop_descriptor.h"
  20. #include "source/opt/loop_utils.h"
  21. #include "test/opt//assembly_builder.h"
  22. #include "test/opt/function_utils.h"
  23. namespace spvtools {
  24. namespace opt {
  25. namespace {
  26. bool Validate(const std::vector<uint32_t>& bin) {
  27. spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
  28. spv_context spvContext = spvContextCreate(target_env);
  29. spv_diagnostic diagnostic = nullptr;
  30. spv_const_binary_t binary = {bin.data(), bin.size()};
  31. spv_result_t error = spvValidate(spvContext, &binary, &diagnostic);
  32. if (error != 0) spvDiagnosticPrint(diagnostic);
  33. spvDiagnosticDestroy(diagnostic);
  34. spvContextDestroy(spvContext);
  35. return error == 0;
  36. }
  37. void Match(const std::string& original, IRContext* context,
  38. bool do_validation = true) {
  39. std::vector<uint32_t> bin;
  40. context->module()->ToBinary(&bin, true);
  41. if (do_validation) {
  42. EXPECT_TRUE(Validate(bin));
  43. }
  44. std::string assembly;
  45. SpirvTools tools(SPV_ENV_UNIVERSAL_1_2);
  46. EXPECT_TRUE(
  47. tools.Disassemble(bin, &assembly, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER))
  48. << "Disassembling failed for shader:\n"
  49. << assembly << std::endl;
  50. auto match_result = effcee::Match(assembly, original);
  51. EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
  52. << match_result.message() << "\nChecking result:\n"
  53. << assembly;
  54. }
  55. using LCSSATest = ::testing::Test;
  56. /*
  57. Generated from the following GLSL + --eliminate-local-multi-store
  58. #version 330 core
  59. layout(location = 0) out vec4 c;
  60. void main() {
  61. int i = 0;
  62. for (; i < 10; i++) {
  63. }
  64. if (i != 0) {
  65. i = 1;
  66. }
  67. }
  68. */
  69. TEST_F(LCSSATest, SimpleLCSSA) {
  70. const std::string text = R"(
  71. ; CHECK: OpLoopMerge [[merge:%\w+]] %19 None
  72. ; CHECK: [[merge]] = OpLabel
  73. ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %30 %20
  74. ; CHECK-NEXT: %27 = OpINotEqual {{%\w+}} [[phi]] %9
  75. OpCapability Shader
  76. %1 = OpExtInstImport "GLSL.std.450"
  77. OpMemoryModel Logical GLSL450
  78. OpEntryPoint Fragment %2 "main" %3
  79. OpExecutionMode %2 OriginUpperLeft
  80. OpSource GLSL 330
  81. OpName %2 "main"
  82. OpName %3 "c"
  83. OpDecorate %3 Location 0
  84. %5 = OpTypeVoid
  85. %6 = OpTypeFunction %5
  86. %7 = OpTypeInt 32 1
  87. %8 = OpTypePointer Function %7
  88. %9 = OpConstant %7 0
  89. %10 = OpConstant %7 10
  90. %11 = OpTypeBool
  91. %12 = OpConstant %7 1
  92. %13 = OpTypeFloat 32
  93. %14 = OpTypeVector %13 4
  94. %15 = OpTypePointer Output %14
  95. %3 = OpVariable %15 Output
  96. %2 = OpFunction %5 None %6
  97. %16 = OpLabel
  98. OpBranch %17
  99. %17 = OpLabel
  100. %30 = OpPhi %7 %9 %16 %25 %19
  101. OpLoopMerge %18 %19 None
  102. OpBranch %20
  103. %20 = OpLabel
  104. %22 = OpSLessThan %11 %30 %10
  105. OpBranchConditional %22 %23 %18
  106. %23 = OpLabel
  107. OpBranch %19
  108. %19 = OpLabel
  109. %25 = OpIAdd %7 %30 %12
  110. OpBranch %17
  111. %18 = OpLabel
  112. %27 = OpINotEqual %11 %30 %9
  113. OpSelectionMerge %28 None
  114. OpBranchConditional %27 %29 %28
  115. %29 = OpLabel
  116. OpBranch %28
  117. %28 = OpLabel
  118. %31 = OpPhi %7 %30 %18 %12 %29
  119. OpReturn
  120. OpFunctionEnd
  121. )";
  122. std::unique_ptr<IRContext> context =
  123. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  124. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  125. Module* module = context->module();
  126. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  127. << text << std::endl;
  128. const Function* f = spvtest::GetFunction(module, 2);
  129. LoopDescriptor ld{context.get(), f};
  130. Loop* loop = ld[17];
  131. EXPECT_FALSE(loop->IsLCSSA());
  132. LoopUtils Util(context.get(), loop);
  133. Util.MakeLoopClosedSSA();
  134. EXPECT_TRUE(loop->IsLCSSA());
  135. Match(text, context.get());
  136. }
  137. /*
  138. Generated from the following GLSL + --eliminate-local-multi-store
  139. #version 330 core
  140. layout(location = 0) out vec4 c;
  141. void main() {
  142. int i = 0;
  143. for (; i < 10; i++) {
  144. }
  145. if (i != 0) {
  146. i = 1;
  147. }
  148. }
  149. */
  150. // Same test as above, but should reuse an existing phi.
  151. TEST_F(LCSSATest, PhiReuseLCSSA) {
  152. const std::string text = R"(
  153. ; CHECK: OpLoopMerge [[merge:%\w+]] %19 None
  154. ; CHECK: [[merge]] = OpLabel
  155. ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %30 %20
  156. ; CHECK-NEXT: %27 = OpINotEqual {{%\w+}} [[phi]] %9
  157. OpCapability Shader
  158. %1 = OpExtInstImport "GLSL.std.450"
  159. OpMemoryModel Logical GLSL450
  160. OpEntryPoint Fragment %2 "main" %3
  161. OpExecutionMode %2 OriginUpperLeft
  162. OpSource GLSL 330
  163. OpName %2 "main"
  164. OpName %3 "c"
  165. OpDecorate %3 Location 0
  166. %5 = OpTypeVoid
  167. %6 = OpTypeFunction %5
  168. %7 = OpTypeInt 32 1
  169. %8 = OpTypePointer Function %7
  170. %9 = OpConstant %7 0
  171. %10 = OpConstant %7 10
  172. %11 = OpTypeBool
  173. %12 = OpConstant %7 1
  174. %13 = OpTypeFloat 32
  175. %14 = OpTypeVector %13 4
  176. %15 = OpTypePointer Output %14
  177. %3 = OpVariable %15 Output
  178. %2 = OpFunction %5 None %6
  179. %16 = OpLabel
  180. OpBranch %17
  181. %17 = OpLabel
  182. %30 = OpPhi %7 %9 %16 %25 %19
  183. OpLoopMerge %18 %19 None
  184. OpBranch %20
  185. %20 = OpLabel
  186. %22 = OpSLessThan %11 %30 %10
  187. OpBranchConditional %22 %23 %18
  188. %23 = OpLabel
  189. OpBranch %19
  190. %19 = OpLabel
  191. %25 = OpIAdd %7 %30 %12
  192. OpBranch %17
  193. %18 = OpLabel
  194. %32 = OpPhi %7 %30 %20
  195. %27 = OpINotEqual %11 %30 %9
  196. OpSelectionMerge %28 None
  197. OpBranchConditional %27 %29 %28
  198. %29 = OpLabel
  199. OpBranch %28
  200. %28 = OpLabel
  201. %31 = OpPhi %7 %30 %18 %12 %29
  202. OpReturn
  203. OpFunctionEnd
  204. )";
  205. std::unique_ptr<IRContext> context =
  206. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  207. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  208. Module* module = context->module();
  209. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  210. << text << std::endl;
  211. const Function* f = spvtest::GetFunction(module, 2);
  212. LoopDescriptor ld{context.get(), f};
  213. Loop* loop = ld[17];
  214. EXPECT_FALSE(loop->IsLCSSA());
  215. LoopUtils Util(context.get(), loop);
  216. Util.MakeLoopClosedSSA();
  217. EXPECT_TRUE(loop->IsLCSSA());
  218. Match(text, context.get());
  219. }
  220. /*
  221. Generated from the following GLSL + --eliminate-local-multi-store
  222. #version 330 core
  223. layout(location = 0) out vec4 c;
  224. void main() {
  225. int i = 0;
  226. int j = 0;
  227. for (; i < 10; i++) {}
  228. for (; j < 10; j++) {}
  229. if (j != 0) {
  230. i = 1;
  231. }
  232. }
  233. */
  234. TEST_F(LCSSATest, DualLoopLCSSA) {
  235. const std::string text = R"(
  236. ; CHECK: %20 = OpLabel
  237. ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %6 %17 %21
  238. ; CHECK: %33 = OpLabel
  239. ; CHECK-NEXT: {{%\w+}} = OpPhi {{%\w+}} [[phi]] %28 %11 %34
  240. OpCapability Shader
  241. %1 = OpExtInstImport "GLSL.std.450"
  242. OpMemoryModel Logical GLSL450
  243. OpEntryPoint Fragment %2 "main" %3
  244. OpExecutionMode %2 OriginUpperLeft
  245. OpSource GLSL 330
  246. OpName %2 "main"
  247. OpName %3 "c"
  248. OpDecorate %3 Location 0
  249. %4 = OpTypeVoid
  250. %5 = OpTypeFunction %4
  251. %6 = OpTypeInt 32 1
  252. %7 = OpTypePointer Function %6
  253. %8 = OpConstant %6 0
  254. %9 = OpConstant %6 10
  255. %10 = OpTypeBool
  256. %11 = OpConstant %6 1
  257. %12 = OpTypeFloat 32
  258. %13 = OpTypeVector %12 4
  259. %14 = OpTypePointer Output %13
  260. %3 = OpVariable %14 Output
  261. %2 = OpFunction %4 None %5
  262. %15 = OpLabel
  263. OpBranch %16
  264. %16 = OpLabel
  265. %17 = OpPhi %6 %8 %15 %18 %19
  266. OpLoopMerge %20 %19 None
  267. OpBranch %21
  268. %21 = OpLabel
  269. %22 = OpSLessThan %10 %17 %9
  270. OpBranchConditional %22 %23 %20
  271. %23 = OpLabel
  272. OpBranch %19
  273. %19 = OpLabel
  274. %18 = OpIAdd %6 %17 %11
  275. OpBranch %16
  276. %20 = OpLabel
  277. OpBranch %24
  278. %24 = OpLabel
  279. %25 = OpPhi %6 %8 %20 %26 %27
  280. OpLoopMerge %28 %27 None
  281. OpBranch %29
  282. %29 = OpLabel
  283. %30 = OpSLessThan %10 %25 %9
  284. OpBranchConditional %30 %31 %28
  285. %31 = OpLabel
  286. OpBranch %27
  287. %27 = OpLabel
  288. %26 = OpIAdd %6 %25 %11
  289. OpBranch %24
  290. %28 = OpLabel
  291. %32 = OpINotEqual %10 %25 %8
  292. OpSelectionMerge %33 None
  293. OpBranchConditional %32 %34 %33
  294. %34 = OpLabel
  295. OpBranch %33
  296. %33 = OpLabel
  297. %35 = OpPhi %6 %17 %28 %11 %34
  298. OpReturn
  299. OpFunctionEnd
  300. )";
  301. std::unique_ptr<IRContext> context =
  302. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  303. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  304. Module* module = context->module();
  305. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  306. << text << std::endl;
  307. const Function* f = spvtest::GetFunction(module, 2);
  308. LoopDescriptor ld{context.get(), f};
  309. Loop* loop = ld[16];
  310. EXPECT_FALSE(loop->IsLCSSA());
  311. LoopUtils Util(context.get(), loop);
  312. Util.MakeLoopClosedSSA();
  313. EXPECT_TRUE(loop->IsLCSSA());
  314. Match(text, context.get());
  315. }
  316. /*
  317. Generated from the following GLSL + --eliminate-local-multi-store
  318. #version 330 core
  319. layout(location = 0) out vec4 c;
  320. void main() {
  321. int i = 0;
  322. if (i != 0) {
  323. for (; i < 10; i++) {}
  324. }
  325. if (i != 0) {
  326. i = 1;
  327. }
  328. }
  329. */
  330. TEST_F(LCSSATest, PhiUserLCSSA) {
  331. const std::string text = R"(
  332. ; CHECK: OpLoopMerge [[merge:%\w+]] %22 None
  333. ; CHECK: [[merge]] = OpLabel
  334. ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %20 %24
  335. ; CHECK: %17 = OpLabel
  336. ; CHECK-NEXT: {{%\w+}} = OpPhi {{%\w+}} %8 %15 [[phi]] %23
  337. OpCapability Shader
  338. %1 = OpExtInstImport "GLSL.std.450"
  339. OpMemoryModel Logical GLSL450
  340. OpEntryPoint Fragment %2 "main" %3
  341. OpExecutionMode %2 OriginUpperLeft
  342. OpSource GLSL 330
  343. OpName %2 "main"
  344. OpName %3 "c"
  345. OpDecorate %3 Location 0
  346. %4 = OpTypeVoid
  347. %5 = OpTypeFunction %4
  348. %6 = OpTypeInt 32 1
  349. %7 = OpTypePointer Function %6
  350. %8 = OpConstant %6 0
  351. %9 = OpTypeBool
  352. %10 = OpConstant %6 10
  353. %11 = OpConstant %6 1
  354. %12 = OpTypeFloat 32
  355. %13 = OpTypeVector %12 4
  356. %14 = OpTypePointer Output %13
  357. %3 = OpVariable %14 Output
  358. %2 = OpFunction %4 None %5
  359. %15 = OpLabel
  360. %16 = OpINotEqual %9 %8 %8
  361. OpSelectionMerge %17 None
  362. OpBranchConditional %16 %18 %17
  363. %18 = OpLabel
  364. OpBranch %19
  365. %19 = OpLabel
  366. %20 = OpPhi %6 %8 %18 %21 %22
  367. OpLoopMerge %23 %22 None
  368. OpBranch %24
  369. %24 = OpLabel
  370. %25 = OpSLessThan %9 %20 %10
  371. OpBranchConditional %25 %26 %23
  372. %26 = OpLabel
  373. OpBranch %22
  374. %22 = OpLabel
  375. %21 = OpIAdd %6 %20 %11
  376. OpBranch %19
  377. %23 = OpLabel
  378. OpBranch %17
  379. %17 = OpLabel
  380. %27 = OpPhi %6 %8 %15 %20 %23
  381. %28 = OpINotEqual %9 %27 %8
  382. OpSelectionMerge %29 None
  383. OpBranchConditional %28 %30 %29
  384. %30 = OpLabel
  385. OpBranch %29
  386. %29 = OpLabel
  387. %31 = OpPhi %6 %27 %17 %11 %30
  388. OpReturn
  389. OpFunctionEnd
  390. )";
  391. std::unique_ptr<IRContext> context =
  392. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  393. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  394. Module* module = context->module();
  395. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  396. << text << std::endl;
  397. const Function* f = spvtest::GetFunction(module, 2);
  398. LoopDescriptor ld{context.get(), f};
  399. Loop* loop = ld[19];
  400. EXPECT_FALSE(loop->IsLCSSA());
  401. LoopUtils Util(context.get(), loop);
  402. Util.MakeLoopClosedSSA();
  403. EXPECT_TRUE(loop->IsLCSSA());
  404. Match(text, context.get());
  405. }
  406. /*
  407. Generated from the following GLSL + --eliminate-local-multi-store
  408. #version 330 core
  409. void main() {
  410. int i = 0;
  411. if (i != 0) {
  412. for (; i < 10; i++) {
  413. if (i > 5) break;
  414. }
  415. }
  416. if (i != 0) {
  417. i = 1;
  418. }
  419. }
  420. */
  421. TEST_F(LCSSATest, LCSSAWithBreak) {
  422. const std::string text = R"(
  423. ; CHECK: OpLoopMerge [[merge:%\w+]] %19 None
  424. ; CHECK: [[merge]] = OpLabel
  425. ; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} %17 %21 %17 %26
  426. ; CHECK: %14 = OpLabel
  427. ; CHECK-NEXT: {{%\w+}} = OpPhi {{%\w+}} %7 %12 [[phi]] [[merge]]
  428. OpCapability Shader
  429. %1 = OpExtInstImport "GLSL.std.450"
  430. OpMemoryModel Logical GLSL450
  431. OpEntryPoint Fragment %2 "main"
  432. OpExecutionMode %2 OriginUpperLeft
  433. OpSource GLSL 330
  434. OpName %2 "main"
  435. %3 = OpTypeVoid
  436. %4 = OpTypeFunction %3
  437. %5 = OpTypeInt 32 1
  438. %6 = OpTypePointer Function %5
  439. %7 = OpConstant %5 0
  440. %8 = OpTypeBool
  441. %9 = OpConstant %5 10
  442. %10 = OpConstant %5 5
  443. %11 = OpConstant %5 1
  444. %2 = OpFunction %3 None %4
  445. %12 = OpLabel
  446. %13 = OpINotEqual %8 %7 %7
  447. OpSelectionMerge %14 None
  448. OpBranchConditional %13 %15 %14
  449. %15 = OpLabel
  450. OpBranch %16
  451. %16 = OpLabel
  452. %17 = OpPhi %5 %7 %15 %18 %19
  453. OpLoopMerge %20 %19 None
  454. OpBranch %21
  455. %21 = OpLabel
  456. %22 = OpSLessThan %8 %17 %9
  457. OpBranchConditional %22 %23 %20
  458. %23 = OpLabel
  459. %24 = OpSGreaterThan %8 %17 %10
  460. OpSelectionMerge %25 None
  461. OpBranchConditional %24 %26 %25
  462. %26 = OpLabel
  463. OpBranch %20
  464. %25 = OpLabel
  465. OpBranch %19
  466. %19 = OpLabel
  467. %18 = OpIAdd %5 %17 %11
  468. OpBranch %16
  469. %20 = OpLabel
  470. OpBranch %14
  471. %14 = OpLabel
  472. %27 = OpPhi %5 %7 %12 %17 %20
  473. %28 = OpINotEqual %8 %27 %7
  474. OpSelectionMerge %29 None
  475. OpBranchConditional %28 %30 %29
  476. %30 = OpLabel
  477. OpBranch %29
  478. %29 = OpLabel
  479. %31 = OpPhi %5 %27 %14 %11 %30
  480. OpReturn
  481. OpFunctionEnd
  482. )";
  483. std::unique_ptr<IRContext> context =
  484. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  485. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  486. Module* module = context->module();
  487. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  488. << text << std::endl;
  489. const Function* f = spvtest::GetFunction(module, 2);
  490. LoopDescriptor ld{context.get(), f};
  491. Loop* loop = ld[19];
  492. EXPECT_FALSE(loop->IsLCSSA());
  493. LoopUtils Util(context.get(), loop);
  494. Util.MakeLoopClosedSSA();
  495. EXPECT_TRUE(loop->IsLCSSA());
  496. Match(text, context.get());
  497. }
  498. /*
  499. Generated from the following GLSL + --eliminate-local-multi-store
  500. #version 330 core
  501. void main() {
  502. int i = 0;
  503. for (; i < 10; i++) {}
  504. for (int j = i; j < 10;) { j = i + j; }
  505. }
  506. */
  507. TEST_F(LCSSATest, LCSSAUseInNonEligiblePhi) {
  508. const std::string text = R"(
  509. ; CHECK: %12 = OpLabel
  510. ; CHECK-NEXT: [[def_to_close:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} [[continue:%\w+]]
  511. ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None
  512. ; CHECK: [[merge]] = OpLabel
  513. ; CHECK-NEXT: [[closing_phi:%\w+]] = OpPhi {{%\w+}} [[def_to_close]] %17
  514. ; CHECK: %16 = OpLabel
  515. ; CHECK-NEXT: [[use_in_phi:%\w+]] = OpPhi {{%\w+}} %21 %22 [[closing_phi]] [[merge]]
  516. ; CHECK: OpIAdd {{%\w+}} [[closing_phi]] [[use_in_phi]]
  517. OpCapability Shader
  518. %1 = OpExtInstImport "GLSL.std.450"
  519. OpMemoryModel Logical GLSL450
  520. OpEntryPoint Fragment %2 "main"
  521. OpExecutionMode %2 OriginUpperLeft
  522. OpSource GLSL 330
  523. OpName %2 "main"
  524. %3 = OpTypeVoid
  525. %4 = OpTypeFunction %3
  526. %5 = OpTypeInt 32 1
  527. %6 = OpTypePointer Function %5
  528. %7 = OpConstant %5 0
  529. %8 = OpConstant %5 10
  530. %9 = OpTypeBool
  531. %10 = OpConstant %5 1
  532. %2 = OpFunction %3 None %4
  533. %11 = OpLabel
  534. OpBranch %12
  535. %12 = OpLabel
  536. %13 = OpPhi %5 %7 %11 %14 %15
  537. OpLoopMerge %16 %15 None
  538. OpBranch %17
  539. %17 = OpLabel
  540. %18 = OpSLessThan %9 %13 %8
  541. OpBranchConditional %18 %19 %16
  542. %19 = OpLabel
  543. OpBranch %15
  544. %15 = OpLabel
  545. %14 = OpIAdd %5 %13 %10
  546. OpBranch %12
  547. %16 = OpLabel
  548. %20 = OpPhi %5 %13 %17 %21 %22
  549. OpLoopMerge %23 %22 None
  550. OpBranch %24
  551. %24 = OpLabel
  552. %25 = OpSLessThan %9 %20 %8
  553. OpBranchConditional %25 %26 %23
  554. %26 = OpLabel
  555. %21 = OpIAdd %5 %13 %20
  556. OpBranch %22
  557. %22 = OpLabel
  558. OpBranch %16
  559. %23 = OpLabel
  560. OpReturn
  561. OpFunctionEnd
  562. )";
  563. std::unique_ptr<IRContext> context =
  564. BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
  565. SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
  566. Module* module = context->module();
  567. EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
  568. << text << std::endl;
  569. const Function* f = spvtest::GetFunction(module, 2);
  570. LoopDescriptor ld{context.get(), f};
  571. Loop* loop = ld[12];
  572. EXPECT_FALSE(loop->IsLCSSA());
  573. LoopUtils Util(context.get(), loop);
  574. Util.MakeLoopClosedSSA();
  575. EXPECT_TRUE(loop->IsLCSSA());
  576. Match(text, context.get());
  577. }
  578. } // namespace
  579. } // namespace opt
  580. } // namespace spvtools