lcssa.cpp 19 KB

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