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
15 #include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h"
16
17 #include "source/opt/build_module.h"
18 #include "source/reduce/reduction_opportunity.h"
19 #include "test/reduce/reduce_test_util.h"
20
21 namespace spvtools {
22 namespace reduce {
23 namespace {
24
TEST(StructuredLoopToSelectionReductionPassTest,LoopyShader1)25 TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader1) {
26 std::string shader = R"(
27 OpCapability Shader
28 %1 = OpExtInstImport "GLSL.std.450"
29 OpMemoryModel Logical GLSL450
30 OpEntryPoint Fragment %4 "main"
31 OpExecutionMode %4 OriginUpperLeft
32 OpSource ESSL 310
33 %2 = OpTypeVoid
34 %3 = OpTypeFunction %2
35 %6 = OpTypeInt 32 1
36 %7 = OpTypePointer Function %6
37 %9 = OpConstant %6 0
38 %16 = OpConstant %6 100
39 %17 = OpTypeBool
40 %20 = OpConstant %6 1
41 %4 = OpFunction %2 None %3
42 %5 = OpLabel
43 %8 = OpVariable %7 Function
44 OpStore %8 %9
45 OpBranch %10
46 %10 = OpLabel
47 OpLoopMerge %12 %13 None
48 OpBranch %14
49 %14 = OpLabel
50 %15 = OpLoad %6 %8
51 %18 = OpSLessThan %17 %15 %16
52 OpBranchConditional %18 %11 %12
53 %11 = OpLabel
54 OpBranch %13
55 %13 = OpLabel
56 %19 = OpLoad %6 %8
57 %21 = OpIAdd %6 %19 %20
58 OpStore %8 %21
59 OpBranch %10
60 %12 = OpLabel
61 OpReturn
62 OpFunctionEnd
63 )";
64
65 const auto env = SPV_ENV_UNIVERSAL_1_3;
66 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
67 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
68 .GetAvailableOpportunities(context.get(), 0);
69 ASSERT_EQ(1, ops.size());
70
71 ASSERT_TRUE(ops[0]->PreconditionHolds());
72 ops[0]->TryToApply();
73 CheckValid(env, context.get());
74
75 std::string after_op_0 = R"(
76 OpCapability Shader
77 %1 = OpExtInstImport "GLSL.std.450"
78 OpMemoryModel Logical GLSL450
79 OpEntryPoint Fragment %4 "main"
80 OpExecutionMode %4 OriginUpperLeft
81 OpSource ESSL 310
82 %2 = OpTypeVoid
83 %3 = OpTypeFunction %2
84 %6 = OpTypeInt 32 1
85 %7 = OpTypePointer Function %6
86 %9 = OpConstant %6 0
87 %16 = OpConstant %6 100
88 %17 = OpTypeBool
89 %20 = OpConstant %6 1
90 %22 = OpConstantTrue %17
91 %4 = OpFunction %2 None %3
92 %5 = OpLabel
93 %8 = OpVariable %7 Function
94 OpStore %8 %9
95 OpBranch %10
96 %10 = OpLabel
97 OpSelectionMerge %12 None
98 OpBranchConditional %22 %14 %12
99 %14 = OpLabel
100 %15 = OpLoad %6 %8
101 %18 = OpSLessThan %17 %15 %16
102 OpBranchConditional %18 %11 %12
103 %11 = OpLabel
104 OpBranch %12
105 %13 = OpLabel
106 %19 = OpLoad %6 %8
107 %21 = OpIAdd %6 %19 %20
108 OpStore %8 %21
109 OpBranch %10
110 %12 = OpLabel
111 OpReturn
112 OpFunctionEnd
113 )";
114 CheckEqual(env, after_op_0, context.get());
115 }
116
TEST(StructuredLoopToSelectionReductionPassTest,LoopyShader2)117 TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader2) {
118 std::string shader = R"(
119 OpCapability Shader
120 %1 = OpExtInstImport "GLSL.std.450"
121 OpMemoryModel Logical GLSL450
122 OpEntryPoint Fragment %4 "main"
123 OpExecutionMode %4 OriginUpperLeft
124 OpSource ESSL 310
125 %2 = OpTypeVoid
126 %3 = OpTypeFunction %2
127 %6 = OpTypeInt 32 1
128 %7 = OpTypePointer Function %6
129 %9 = OpConstant %6 0
130 %16 = OpConstant %6 100
131 %17 = OpTypeBool
132 %28 = OpConstant %6 1
133 %4 = OpFunction %2 None %3
134 %5 = OpLabel
135 %8 = OpVariable %7 Function
136 %19 = OpVariable %7 Function
137 %32 = OpVariable %7 Function
138 %40 = OpVariable %7 Function
139 OpStore %8 %9
140 OpBranch %10
141 %10 = OpLabel
142 OpLoopMerge %12 %13 None
143 OpBranch %14
144 %14 = OpLabel
145 %15 = OpLoad %6 %8
146 %18 = OpSLessThan %17 %15 %16
147 OpBranchConditional %18 %11 %12
148 %11 = OpLabel
149 OpStore %19 %9
150 OpBranch %20
151 %20 = OpLabel
152 OpLoopMerge %22 %23 None
153 OpBranch %24
154 %24 = OpLabel
155 %25 = OpLoad %6 %19
156 %26 = OpSLessThan %17 %25 %16
157 OpBranchConditional %26 %21 %22
158 %21 = OpLabel
159 OpBranch %23
160 %23 = OpLabel
161 %27 = OpLoad %6 %19
162 %29 = OpIAdd %6 %27 %28
163 OpStore %19 %29
164 OpBranch %20
165 %22 = OpLabel
166 OpBranch %13
167 %13 = OpLabel
168 %30 = OpLoad %6 %8
169 %31 = OpIAdd %6 %30 %28
170 OpStore %8 %31
171 OpBranch %10
172 %12 = OpLabel
173 OpStore %32 %9
174 OpBranch %33
175 %33 = OpLabel
176 OpLoopMerge %35 %36 None
177 OpBranch %37
178 %37 = OpLabel
179 %38 = OpLoad %6 %32
180 %39 = OpSLessThan %17 %38 %16
181 OpBranchConditional %39 %34 %35
182 %34 = OpLabel
183 OpStore %40 %9
184 OpBranch %41
185 %41 = OpLabel
186 OpLoopMerge %43 %44 None
187 OpBranch %45
188 %45 = OpLabel
189 %46 = OpLoad %6 %40
190 %47 = OpSLessThan %17 %46 %16
191 OpBranchConditional %47 %42 %43
192 %42 = OpLabel
193 OpBranch %44
194 %44 = OpLabel
195 %48 = OpLoad %6 %40
196 %49 = OpIAdd %6 %48 %28
197 OpStore %40 %49
198 OpBranch %41
199 %43 = OpLabel
200 OpBranch %36
201 %36 = OpLabel
202 %50 = OpLoad %6 %32
203 %51 = OpIAdd %6 %50 %28
204 OpStore %32 %51
205 OpBranch %33
206 %35 = OpLabel
207 OpReturn
208 OpFunctionEnd
209 )";
210
211 const auto env = SPV_ENV_UNIVERSAL_1_3;
212 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
213 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
214 .GetAvailableOpportunities(context.get(), 0);
215 ASSERT_EQ(4, ops.size());
216
217 ASSERT_TRUE(ops[0]->PreconditionHolds());
218 ops[0]->TryToApply();
219 CheckValid(env, context.get());
220 std::string after_op_0 = R"(
221 OpCapability Shader
222 %1 = OpExtInstImport "GLSL.std.450"
223 OpMemoryModel Logical GLSL450
224 OpEntryPoint Fragment %4 "main"
225 OpExecutionMode %4 OriginUpperLeft
226 OpSource ESSL 310
227 %2 = OpTypeVoid
228 %3 = OpTypeFunction %2
229 %6 = OpTypeInt 32 1
230 %7 = OpTypePointer Function %6
231 %9 = OpConstant %6 0
232 %16 = OpConstant %6 100
233 %17 = OpTypeBool
234 %28 = OpConstant %6 1
235 %52 = OpConstantTrue %17
236 %4 = OpFunction %2 None %3
237 %5 = OpLabel
238 %8 = OpVariable %7 Function
239 %19 = OpVariable %7 Function
240 %32 = OpVariable %7 Function
241 %40 = OpVariable %7 Function
242 OpStore %8 %9
243 OpBranch %10
244 %10 = OpLabel
245 OpSelectionMerge %12 None
246 OpBranchConditional %52 %14 %12
247 %14 = OpLabel
248 %15 = OpLoad %6 %8
249 %18 = OpSLessThan %17 %15 %16
250 OpBranchConditional %18 %11 %12
251 %11 = OpLabel
252 OpStore %19 %9
253 OpBranch %20
254 %20 = OpLabel
255 OpLoopMerge %22 %23 None
256 OpBranch %24
257 %24 = OpLabel
258 %25 = OpLoad %6 %19
259 %26 = OpSLessThan %17 %25 %16
260 OpBranchConditional %26 %21 %22
261 %21 = OpLabel
262 OpBranch %23
263 %23 = OpLabel
264 %27 = OpLoad %6 %19
265 %29 = OpIAdd %6 %27 %28
266 OpStore %19 %29
267 OpBranch %20
268 %22 = OpLabel
269 OpBranch %12
270 %13 = OpLabel
271 %30 = OpLoad %6 %8
272 %31 = OpIAdd %6 %30 %28
273 OpStore %8 %31
274 OpBranch %10
275 %12 = OpLabel
276 OpStore %32 %9
277 OpBranch %33
278 %33 = OpLabel
279 OpLoopMerge %35 %36 None
280 OpBranch %37
281 %37 = OpLabel
282 %38 = OpLoad %6 %32
283 %39 = OpSLessThan %17 %38 %16
284 OpBranchConditional %39 %34 %35
285 %34 = OpLabel
286 OpStore %40 %9
287 OpBranch %41
288 %41 = OpLabel
289 OpLoopMerge %43 %44 None
290 OpBranch %45
291 %45 = OpLabel
292 %46 = OpLoad %6 %40
293 %47 = OpSLessThan %17 %46 %16
294 OpBranchConditional %47 %42 %43
295 %42 = OpLabel
296 OpBranch %44
297 %44 = OpLabel
298 %48 = OpLoad %6 %40
299 %49 = OpIAdd %6 %48 %28
300 OpStore %40 %49
301 OpBranch %41
302 %43 = OpLabel
303 OpBranch %36
304 %36 = OpLabel
305 %50 = OpLoad %6 %32
306 %51 = OpIAdd %6 %50 %28
307 OpStore %32 %51
308 OpBranch %33
309 %35 = OpLabel
310 OpReturn
311 OpFunctionEnd
312 )";
313 CheckEqual(env, after_op_0, context.get());
314
315 ASSERT_TRUE(ops[1]->PreconditionHolds());
316 ops[1]->TryToApply();
317 CheckValid(env, context.get());
318 std::string after_op_1 = R"(
319 OpCapability Shader
320 %1 = OpExtInstImport "GLSL.std.450"
321 OpMemoryModel Logical GLSL450
322 OpEntryPoint Fragment %4 "main"
323 OpExecutionMode %4 OriginUpperLeft
324 OpSource ESSL 310
325 %2 = OpTypeVoid
326 %3 = OpTypeFunction %2
327 %6 = OpTypeInt 32 1
328 %7 = OpTypePointer Function %6
329 %9 = OpConstant %6 0
330 %16 = OpConstant %6 100
331 %17 = OpTypeBool
332 %28 = OpConstant %6 1
333 %52 = OpConstantTrue %17
334 %4 = OpFunction %2 None %3
335 %5 = OpLabel
336 %8 = OpVariable %7 Function
337 %19 = OpVariable %7 Function
338 %32 = OpVariable %7 Function
339 %40 = OpVariable %7 Function
340 OpStore %8 %9
341 OpBranch %10
342 %10 = OpLabel
343 OpSelectionMerge %12 None
344 OpBranchConditional %52 %14 %12
345 %14 = OpLabel
346 %15 = OpLoad %6 %8
347 %18 = OpSLessThan %17 %15 %16
348 OpBranchConditional %18 %11 %12
349 %11 = OpLabel
350 OpStore %19 %9
351 OpBranch %20
352 %20 = OpLabel
353 OpSelectionMerge %22 None
354 OpBranchConditional %52 %24 %22
355 %24 = OpLabel
356 %25 = OpLoad %6 %19
357 %26 = OpSLessThan %17 %25 %16
358 OpBranchConditional %26 %21 %22
359 %21 = OpLabel
360 OpBranch %22
361 %23 = OpLabel
362 %27 = OpLoad %6 %19
363 %29 = OpIAdd %6 %27 %28
364 OpStore %19 %29
365 OpBranch %20
366 %22 = OpLabel
367 OpBranch %12
368 %13 = OpLabel
369 %30 = OpLoad %6 %8
370 %31 = OpIAdd %6 %30 %28
371 OpStore %8 %31
372 OpBranch %10
373 %12 = OpLabel
374 OpStore %32 %9
375 OpBranch %33
376 %33 = OpLabel
377 OpLoopMerge %35 %36 None
378 OpBranch %37
379 %37 = OpLabel
380 %38 = OpLoad %6 %32
381 %39 = OpSLessThan %17 %38 %16
382 OpBranchConditional %39 %34 %35
383 %34 = OpLabel
384 OpStore %40 %9
385 OpBranch %41
386 %41 = OpLabel
387 OpLoopMerge %43 %44 None
388 OpBranch %45
389 %45 = OpLabel
390 %46 = OpLoad %6 %40
391 %47 = OpSLessThan %17 %46 %16
392 OpBranchConditional %47 %42 %43
393 %42 = OpLabel
394 OpBranch %44
395 %44 = OpLabel
396 %48 = OpLoad %6 %40
397 %49 = OpIAdd %6 %48 %28
398 OpStore %40 %49
399 OpBranch %41
400 %43 = OpLabel
401 OpBranch %36
402 %36 = OpLabel
403 %50 = OpLoad %6 %32
404 %51 = OpIAdd %6 %50 %28
405 OpStore %32 %51
406 OpBranch %33
407 %35 = OpLabel
408 OpReturn
409 OpFunctionEnd
410 )";
411 CheckEqual(env, after_op_1, context.get());
412
413 ASSERT_TRUE(ops[2]->PreconditionHolds());
414 ops[2]->TryToApply();
415 CheckValid(env, context.get());
416 std::string after_op_2 = R"(
417 OpCapability Shader
418 %1 = OpExtInstImport "GLSL.std.450"
419 OpMemoryModel Logical GLSL450
420 OpEntryPoint Fragment %4 "main"
421 OpExecutionMode %4 OriginUpperLeft
422 OpSource ESSL 310
423 %2 = OpTypeVoid
424 %3 = OpTypeFunction %2
425 %6 = OpTypeInt 32 1
426 %7 = OpTypePointer Function %6
427 %9 = OpConstant %6 0
428 %16 = OpConstant %6 100
429 %17 = OpTypeBool
430 %28 = OpConstant %6 1
431 %52 = OpConstantTrue %17
432 %4 = OpFunction %2 None %3
433 %5 = OpLabel
434 %8 = OpVariable %7 Function
435 %19 = OpVariable %7 Function
436 %32 = OpVariable %7 Function
437 %40 = OpVariable %7 Function
438 OpStore %8 %9
439 OpBranch %10
440 %10 = OpLabel
441 OpSelectionMerge %12 None
442 OpBranchConditional %52 %14 %12
443 %14 = OpLabel
444 %15 = OpLoad %6 %8
445 %18 = OpSLessThan %17 %15 %16
446 OpBranchConditional %18 %11 %12
447 %11 = OpLabel
448 OpStore %19 %9
449 OpBranch %20
450 %20 = OpLabel
451 OpSelectionMerge %22 None
452 OpBranchConditional %52 %24 %22
453 %24 = OpLabel
454 %25 = OpLoad %6 %19
455 %26 = OpSLessThan %17 %25 %16
456 OpBranchConditional %26 %21 %22
457 %21 = OpLabel
458 OpBranch %22
459 %23 = OpLabel
460 %27 = OpLoad %6 %19
461 %29 = OpIAdd %6 %27 %28
462 OpStore %19 %29
463 OpBranch %20
464 %22 = OpLabel
465 OpBranch %12
466 %13 = OpLabel
467 %30 = OpLoad %6 %8
468 %31 = OpIAdd %6 %30 %28
469 OpStore %8 %31
470 OpBranch %10
471 %12 = OpLabel
472 OpStore %32 %9
473 OpBranch %33
474 %33 = OpLabel
475 OpSelectionMerge %35 None
476 OpBranchConditional %52 %37 %35
477 %37 = OpLabel
478 %38 = OpLoad %6 %32
479 %39 = OpSLessThan %17 %38 %16
480 OpBranchConditional %39 %34 %35
481 %34 = OpLabel
482 OpStore %40 %9
483 OpBranch %41
484 %41 = OpLabel
485 OpLoopMerge %43 %44 None
486 OpBranch %45
487 %45 = OpLabel
488 %46 = OpLoad %6 %40
489 %47 = OpSLessThan %17 %46 %16
490 OpBranchConditional %47 %42 %43
491 %42 = OpLabel
492 OpBranch %44
493 %44 = OpLabel
494 %48 = OpLoad %6 %40
495 %49 = OpIAdd %6 %48 %28
496 OpStore %40 %49
497 OpBranch %41
498 %43 = OpLabel
499 OpBranch %35
500 %36 = OpLabel
501 %50 = OpLoad %6 %32
502 %51 = OpIAdd %6 %50 %28
503 OpStore %32 %51
504 OpBranch %33
505 %35 = OpLabel
506 OpReturn
507 OpFunctionEnd
508 )";
509 CheckEqual(env, after_op_2, context.get());
510
511 ASSERT_TRUE(ops[3]->PreconditionHolds());
512 ops[3]->TryToApply();
513 CheckValid(env, context.get());
514 std::string after_op_3 = R"(
515 OpCapability Shader
516 %1 = OpExtInstImport "GLSL.std.450"
517 OpMemoryModel Logical GLSL450
518 OpEntryPoint Fragment %4 "main"
519 OpExecutionMode %4 OriginUpperLeft
520 OpSource ESSL 310
521 %2 = OpTypeVoid
522 %3 = OpTypeFunction %2
523 %6 = OpTypeInt 32 1
524 %7 = OpTypePointer Function %6
525 %9 = OpConstant %6 0
526 %16 = OpConstant %6 100
527 %17 = OpTypeBool
528 %28 = OpConstant %6 1
529 %52 = OpConstantTrue %17
530 %4 = OpFunction %2 None %3
531 %5 = OpLabel
532 %8 = OpVariable %7 Function
533 %19 = OpVariable %7 Function
534 %32 = OpVariable %7 Function
535 %40 = OpVariable %7 Function
536 OpStore %8 %9
537 OpBranch %10
538 %10 = OpLabel
539 OpSelectionMerge %12 None
540 OpBranchConditional %52 %14 %12
541 %14 = OpLabel
542 %15 = OpLoad %6 %8
543 %18 = OpSLessThan %17 %15 %16
544 OpBranchConditional %18 %11 %12
545 %11 = OpLabel
546 OpStore %19 %9
547 OpBranch %20
548 %20 = OpLabel
549 OpSelectionMerge %22 None
550 OpBranchConditional %52 %24 %22
551 %24 = OpLabel
552 %25 = OpLoad %6 %19
553 %26 = OpSLessThan %17 %25 %16
554 OpBranchConditional %26 %21 %22
555 %21 = OpLabel
556 OpBranch %22
557 %23 = OpLabel
558 %27 = OpLoad %6 %19
559 %29 = OpIAdd %6 %27 %28
560 OpStore %19 %29
561 OpBranch %20
562 %22 = OpLabel
563 OpBranch %12
564 %13 = OpLabel
565 %30 = OpLoad %6 %8
566 %31 = OpIAdd %6 %30 %28
567 OpStore %8 %31
568 OpBranch %10
569 %12 = OpLabel
570 OpStore %32 %9
571 OpBranch %33
572 %33 = OpLabel
573 OpSelectionMerge %35 None
574 OpBranchConditional %52 %37 %35
575 %37 = OpLabel
576 %38 = OpLoad %6 %32
577 %39 = OpSLessThan %17 %38 %16
578 OpBranchConditional %39 %34 %35
579 %34 = OpLabel
580 OpStore %40 %9
581 OpBranch %41
582 %41 = OpLabel
583 OpSelectionMerge %43 None
584 OpBranchConditional %52 %45 %43
585 %45 = OpLabel
586 %46 = OpLoad %6 %40
587 %47 = OpSLessThan %17 %46 %16
588 OpBranchConditional %47 %42 %43
589 %42 = OpLabel
590 OpBranch %43
591 %44 = OpLabel
592 %48 = OpLoad %6 %40
593 %49 = OpIAdd %6 %48 %28
594 OpStore %40 %49
595 OpBranch %41
596 %43 = OpLabel
597 OpBranch %35
598 %36 = OpLabel
599 %50 = OpLoad %6 %32
600 %51 = OpIAdd %6 %50 %28
601 OpStore %32 %51
602 OpBranch %33
603 %35 = OpLabel
604 OpReturn
605 OpFunctionEnd
606 )";
607 CheckEqual(env, after_op_3, context.get());
608 }
609
TEST(StructuredLoopToSelectionReductionPassTest,LoopyShader3)610 TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader3) {
611 std::string shader = R"(
612 OpCapability Shader
613 %1 = OpExtInstImport "GLSL.std.450"
614 OpMemoryModel Logical GLSL450
615 OpEntryPoint Fragment %4 "main"
616 OpExecutionMode %4 OriginUpperLeft
617 OpSource ESSL 310
618 %2 = OpTypeVoid
619 %3 = OpTypeFunction %2
620 %6 = OpTypeInt 32 1
621 %7 = OpTypePointer Function %6
622 %9 = OpConstant %6 10
623 %16 = OpConstant %6 0
624 %17 = OpTypeBool
625 %20 = OpConstant %6 1
626 %23 = OpConstant %6 3
627 %40 = OpConstant %6 5
628 %4 = OpFunction %2 None %3
629 %5 = OpLabel
630 %8 = OpVariable %7 Function
631 OpStore %8 %9
632 OpBranch %10
633 %10 = OpLabel
634 OpLoopMerge %12 %13 None
635 OpBranch %14
636 %14 = OpLabel
637 %15 = OpLoad %6 %8
638 %18 = OpSGreaterThan %17 %15 %16
639 OpBranchConditional %18 %11 %12
640 %11 = OpLabel
641 %19 = OpLoad %6 %8
642 %21 = OpISub %6 %19 %20
643 OpStore %8 %21
644 %22 = OpLoad %6 %8
645 %24 = OpSLessThan %17 %22 %23
646 OpSelectionMerge %26 None
647 OpBranchConditional %24 %25 %26
648 %25 = OpLabel
649 OpBranch %13
650 %26 = OpLabel
651 OpBranch %28
652 %28 = OpLabel
653 OpLoopMerge %30 %31 None
654 OpBranch %29
655 %29 = OpLabel
656 %32 = OpLoad %6 %8
657 %33 = OpISub %6 %32 %20
658 OpStore %8 %33
659 %34 = OpLoad %6 %8
660 %35 = OpIEqual %17 %34 %20
661 OpSelectionMerge %37 None
662 OpBranchConditional %35 %36 %37
663 %36 = OpLabel
664 OpReturn ; This return spoils everything: it means the merge does not post-dominate the header.
665 %37 = OpLabel
666 OpBranch %31
667 %31 = OpLabel
668 %39 = OpLoad %6 %8
669 %41 = OpSGreaterThan %17 %39 %40
670 OpBranchConditional %41 %28 %30
671 %30 = OpLabel
672 OpBranch %13
673 %13 = OpLabel
674 OpBranch %10
675 %12 = OpLabel
676 OpReturn
677 OpFunctionEnd
678 )";
679
680 const auto env = SPV_ENV_UNIVERSAL_1_3;
681 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
682 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
683 .GetAvailableOpportunities(context.get(), 0);
684 ASSERT_EQ(0, ops.size());
685 }
686
TEST(StructuredLoopToSelectionReductionPassTest,LoopyShader4)687 TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader4) {
688 std::string shader = R"(
689 OpCapability Shader
690 %1 = OpExtInstImport "GLSL.std.450"
691 OpMemoryModel Logical GLSL450
692 OpEntryPoint Fragment %4 "main"
693 OpExecutionMode %4 OriginUpperLeft
694 OpSource ESSL 310
695 %2 = OpTypeVoid
696 %3 = OpTypeFunction %2
697 %6 = OpTypeInt 32 1
698 %7 = OpTypePointer Function %6
699 %8 = OpTypeFunction %6 %7
700 %13 = OpConstant %6 0
701 %22 = OpTypeBool
702 %25 = OpConstant %6 1
703 %39 = OpConstant %6 100
704 %4 = OpFunction %2 None %3
705 %5 = OpLabel
706 %45 = OpVariable %7 Function
707 %46 = OpVariable %7 Function
708 %47 = OpVariable %7 Function
709 %32 = OpVariable %7 Function
710 %42 = OpVariable %7 Function
711 OpStore %32 %13
712 OpBranch %33
713 %33 = OpLabel
714 OpLoopMerge %35 %36 None
715 OpBranch %37
716 %37 = OpLabel
717 %38 = OpLoad %6 %32
718 %40 = OpSLessThan %22 %38 %39
719 OpBranchConditional %40 %34 %35
720 %34 = OpLabel
721 OpBranch %36
722 %36 = OpLabel
723 %41 = OpLoad %6 %32
724 OpStore %42 %25
725 OpStore %45 %13
726 OpStore %46 %13
727 OpBranch %48
728 %48 = OpLabel
729 OpLoopMerge %49 %50 None
730 OpBranch %51
731 %51 = OpLabel
732 %52 = OpLoad %6 %46
733 %53 = OpLoad %6 %42
734 %54 = OpSLessThan %22 %52 %53
735 OpBranchConditional %54 %55 %49
736 %55 = OpLabel
737 %56 = OpLoad %6 %45
738 %57 = OpIAdd %6 %56 %25
739 OpStore %45 %57
740 OpBranch %50
741 %50 = OpLabel
742 %58 = OpLoad %6 %46
743 %59 = OpIAdd %6 %58 %25
744 OpStore %46 %59
745 OpBranch %48
746 %49 = OpLabel
747 %60 = OpLoad %6 %45
748 OpStore %47 %60
749 %43 = OpLoad %6 %47
750 %44 = OpIAdd %6 %41 %43
751 OpStore %32 %44
752 OpBranch %33
753 %35 = OpLabel
754 OpReturn
755 OpFunctionEnd
756 )";
757
758 const auto env = SPV_ENV_UNIVERSAL_1_3;
759 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
760 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
761 .GetAvailableOpportunities(context.get(), 0);
762
763 // Initially there are two opportunities.
764 ASSERT_EQ(2, ops.size());
765
766 ASSERT_TRUE(ops[0]->PreconditionHolds());
767 ops[0]->TryToApply();
768 CheckValid(env, context.get());
769 std::string after_op_0 = R"(
770 OpCapability Shader
771 %1 = OpExtInstImport "GLSL.std.450"
772 OpMemoryModel Logical GLSL450
773 OpEntryPoint Fragment %4 "main"
774 OpExecutionMode %4 OriginUpperLeft
775 OpSource ESSL 310
776 %2 = OpTypeVoid
777 %3 = OpTypeFunction %2
778 %6 = OpTypeInt 32 1
779 %7 = OpTypePointer Function %6
780 %8 = OpTypeFunction %6 %7
781 %13 = OpConstant %6 0
782 %22 = OpTypeBool
783 %25 = OpConstant %6 1
784 %39 = OpConstant %6 100
785 %61 = OpConstantTrue %22
786 %62 = OpUndef %6
787 %4 = OpFunction %2 None %3
788 %5 = OpLabel
789 %45 = OpVariable %7 Function
790 %46 = OpVariable %7 Function
791 %47 = OpVariable %7 Function
792 %32 = OpVariable %7 Function
793 %42 = OpVariable %7 Function
794 OpStore %32 %13
795 OpBranch %33
796 %33 = OpLabel
797 OpSelectionMerge %35 None
798 OpBranchConditional %61 %37 %35
799 %37 = OpLabel
800 %38 = OpLoad %6 %32
801 %40 = OpSLessThan %22 %38 %39
802 OpBranchConditional %40 %34 %35
803 %34 = OpLabel
804 OpBranch %35
805 %36 = OpLabel
806 %41 = OpLoad %6 %32
807 OpStore %42 %25
808 OpStore %45 %13
809 OpStore %46 %13
810 OpBranch %48
811 %48 = OpLabel
812 OpLoopMerge %49 %50 None
813 OpBranch %51
814 %51 = OpLabel
815 %52 = OpLoad %6 %46
816 %53 = OpLoad %6 %42
817 %54 = OpSLessThan %22 %52 %53
818 OpBranchConditional %54 %55 %49
819 %55 = OpLabel
820 %56 = OpLoad %6 %45
821 %57 = OpIAdd %6 %56 %25
822 OpStore %45 %57
823 OpBranch %50
824 %50 = OpLabel
825 %58 = OpLoad %6 %46
826 %59 = OpIAdd %6 %58 %25
827 OpStore %46 %59
828 OpBranch %48
829 %49 = OpLabel
830 %60 = OpLoad %6 %45
831 OpStore %47 %60
832 %43 = OpLoad %6 %47
833 %44 = OpIAdd %6 %62 %43
834 OpStore %32 %44
835 OpBranch %33
836 %35 = OpLabel
837 OpReturn
838 OpFunctionEnd
839 )";
840 CheckEqual(env, after_op_0, context.get());
841
842 // Applying the first opportunity has killed the second opportunity, because
843 // there was a loop embedded in the continue target of the loop we have just
844 // eliminated; the continue-embedded loop is now unreachable.
845 ASSERT_FALSE(ops[1]->PreconditionHolds());
846 }
847
TEST(StructuredLoopToSelectionReductionPassTest,ConditionalBreak1)848 TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak1) {
849 std::string shader = R"(
850 OpCapability Shader
851 %1 = OpExtInstImport "GLSL.std.450"
852 OpMemoryModel Logical GLSL450
853 OpEntryPoint Fragment %4 "main"
854 OpExecutionMode %4 OriginUpperLeft
855 OpSource ESSL 310
856 OpName %4 "main"
857 %2 = OpTypeVoid
858 %3 = OpTypeFunction %2
859 %10 = OpTypeBool
860 %11 = OpConstantFalse %10
861 %4 = OpFunction %2 None %3
862 %5 = OpLabel
863 OpBranch %6
864 %6 = OpLabel
865 OpLoopMerge %8 %9 None
866 OpBranch %7
867 %7 = OpLabel
868 OpSelectionMerge %13 None
869 OpBranchConditional %11 %12 %13
870 %12 = OpLabel
871 OpBranch %8
872 %13 = OpLabel
873 OpBranch %9
874 %9 = OpLabel
875 OpBranchConditional %11 %6 %8
876 %8 = OpLabel
877 OpReturn
878 OpFunctionEnd
879 )";
880
881 const auto env = SPV_ENV_UNIVERSAL_1_3;
882 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
883 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
884 .GetAvailableOpportunities(context.get(), 0);
885 ASSERT_EQ(1, ops.size());
886
887 ASSERT_TRUE(ops[0]->PreconditionHolds());
888 ops[0]->TryToApply();
889 CheckValid(env, context.get());
890 std::string after_op_0 = R"(
891 OpCapability Shader
892 %1 = OpExtInstImport "GLSL.std.450"
893 OpMemoryModel Logical GLSL450
894 OpEntryPoint Fragment %4 "main"
895 OpExecutionMode %4 OriginUpperLeft
896 OpSource ESSL 310
897 OpName %4 "main"
898 %2 = OpTypeVoid
899 %3 = OpTypeFunction %2
900 %10 = OpTypeBool
901 %11 = OpConstantFalse %10
902 %14 = OpConstantTrue %10
903 %4 = OpFunction %2 None %3
904 %5 = OpLabel
905 OpBranch %6
906 %6 = OpLabel
907 OpSelectionMerge %8 None
908 OpBranchConditional %14 %7 %8
909 %7 = OpLabel
910 OpSelectionMerge %13 None
911 OpBranchConditional %11 %12 %13
912 %12 = OpLabel
913 OpBranch %13
914 %13 = OpLabel
915 OpBranch %8
916 %9 = OpLabel
917 OpBranchConditional %11 %6 %8
918 %8 = OpLabel
919 OpReturn
920 OpFunctionEnd
921 )";
922 CheckEqual(env, after_op_0, context.get());
923 }
924
TEST(StructuredLoopToSelectionReductionPassTest,ConditionalBreak2)925 TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak2) {
926 std::string shader = R"(
927 OpCapability Shader
928 %1 = OpExtInstImport "GLSL.std.450"
929 OpMemoryModel Logical GLSL450
930 OpEntryPoint Fragment %4 "main"
931 OpExecutionMode %4 OriginUpperLeft
932 OpSource ESSL 310
933 OpName %4 "main"
934 %2 = OpTypeVoid
935 %3 = OpTypeFunction %2
936 %10 = OpTypeBool
937 %11 = OpConstantFalse %10
938 %4 = OpFunction %2 None %3
939 %5 = OpLabel
940 OpBranch %6
941 %6 = OpLabel
942 OpLoopMerge %8 %9 None
943 OpBranch %7
944 %7 = OpLabel
945 OpSelectionMerge %13 None
946 OpBranchConditional %11 %8 %13
947 %13 = OpLabel
948 OpBranch %9
949 %9 = OpLabel
950 OpBranchConditional %11 %6 %8
951 %8 = OpLabel
952 OpReturn
953 OpFunctionEnd
954 )";
955
956 const auto env = SPV_ENV_UNIVERSAL_1_3;
957 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
958 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
959 .GetAvailableOpportunities(context.get(), 0);
960 ASSERT_EQ(1, ops.size());
961
962 ASSERT_TRUE(ops[0]->PreconditionHolds());
963 ops[0]->TryToApply();
964 CheckValid(env, context.get());
965 std::string after_op_0 = R"(
966 OpCapability Shader
967 %1 = OpExtInstImport "GLSL.std.450"
968 OpMemoryModel Logical GLSL450
969 OpEntryPoint Fragment %4 "main"
970 OpExecutionMode %4 OriginUpperLeft
971 OpSource ESSL 310
972 OpName %4 "main"
973 %2 = OpTypeVoid
974 %3 = OpTypeFunction %2
975 %10 = OpTypeBool
976 %11 = OpConstantFalse %10
977 %14 = OpConstantTrue %10
978 %4 = OpFunction %2 None %3
979 %5 = OpLabel
980 OpBranch %6
981 %6 = OpLabel
982 OpSelectionMerge %8 None
983 OpBranchConditional %14 %7 %8
984 %7 = OpLabel
985 OpSelectionMerge %13 None
986 OpBranchConditional %11 %13 %13
987 %13 = OpLabel
988 OpBranch %8
989 %9 = OpLabel
990 OpBranchConditional %11 %6 %8
991 %8 = OpLabel
992 OpReturn
993 OpFunctionEnd
994 )";
995 CheckEqual(env, after_op_0, context.get());
996 }
997
TEST(StructuredLoopToSelectionReductionPassTest,UnconditionalBreak)998 TEST(StructuredLoopToSelectionReductionPassTest, UnconditionalBreak) {
999 std::string shader = R"(
1000 OpCapability Shader
1001 %1 = OpExtInstImport "GLSL.std.450"
1002 OpMemoryModel Logical GLSL450
1003 OpEntryPoint Fragment %4 "main"
1004 OpExecutionMode %4 OriginUpperLeft
1005 OpSource ESSL 310
1006 OpName %4 "main"
1007 %2 = OpTypeVoid
1008 %3 = OpTypeFunction %2
1009 %4 = OpFunction %2 None %3
1010 %5 = OpLabel
1011 OpBranch %6
1012 %6 = OpLabel
1013 OpLoopMerge %8 %9 None
1014 OpBranch %7
1015 %7 = OpLabel
1016 OpBranch %8
1017 %9 = OpLabel
1018 OpBranch %6
1019 %8 = OpLabel
1020 OpReturn
1021 OpFunctionEnd
1022 )";
1023
1024 const auto env = SPV_ENV_UNIVERSAL_1_3;
1025 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
1026 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
1027 .GetAvailableOpportunities(context.get(), 0);
1028 ASSERT_EQ(1, ops.size());
1029
1030 ASSERT_TRUE(ops[0]->PreconditionHolds());
1031 ops[0]->TryToApply();
1032 CheckValid(env, context.get());
1033 std::string after_op_0 = R"(
1034 OpCapability Shader
1035 %1 = OpExtInstImport "GLSL.std.450"
1036 OpMemoryModel Logical GLSL450
1037 OpEntryPoint Fragment %4 "main"
1038 OpExecutionMode %4 OriginUpperLeft
1039 OpSource ESSL 310
1040 OpName %4 "main"
1041 %2 = OpTypeVoid
1042 %3 = OpTypeFunction %2
1043 %10 = OpTypeBool
1044 %11 = OpConstantTrue %10
1045 %4 = OpFunction %2 None %3
1046 %5 = OpLabel
1047 OpBranch %6
1048 %6 = OpLabel
1049 OpSelectionMerge %8 None
1050 OpBranchConditional %11 %7 %8
1051 %7 = OpLabel
1052 OpBranch %8
1053 %9 = OpLabel
1054 OpBranch %6
1055 %8 = OpLabel
1056 OpReturn
1057 OpFunctionEnd
1058 )";
1059 CheckEqual(env, after_op_0, context.get());
1060 }
1061
TEST(StructuredLoopToSelectionReductionPassTest,Complex)1062 TEST(StructuredLoopToSelectionReductionPassTest, Complex) {
1063 std::string shader = R"(
1064 OpCapability Shader
1065 %1 = OpExtInstImport "GLSL.std.450"
1066 OpMemoryModel Logical GLSL450
1067 OpEntryPoint Fragment %2 "main" %3
1068 OpExecutionMode %2 OriginUpperLeft
1069 OpSource ESSL 310
1070 OpMemberDecorate %4 0 Offset 0
1071 OpMemberDecorate %4 1 Offset 4
1072 OpMemberDecorate %4 2 Offset 8
1073 OpMemberDecorate %4 3 Offset 12
1074 OpDecorate %4 Block
1075 OpDecorate %5 DescriptorSet 0
1076 OpDecorate %5 Binding 0
1077 OpDecorate %3 Location 0
1078 %6 = OpTypeVoid
1079 %7 = OpTypeFunction %6
1080 %8 = OpTypeBool
1081 %9 = OpTypePointer Function %8
1082 %10 = OpTypeInt 32 1
1083 %4 = OpTypeStruct %10 %10 %10 %10
1084 %11 = OpTypePointer Uniform %4
1085 %5 = OpVariable %11 Uniform
1086 %12 = OpConstant %10 0
1087 %13 = OpTypePointer Uniform %10
1088 %14 = OpTypeInt 32 0
1089 %15 = OpConstant %14 0
1090 %16 = OpConstant %10 1
1091 %17 = OpConstant %10 2
1092 %18 = OpConstant %10 3
1093 %19 = OpTypePointer Function %10
1094 %20 = OpConstantFalse %8
1095 %21 = OpTypeFloat 32
1096 %22 = OpTypeVector %21 4
1097 %23 = OpTypePointer Output %22
1098 %3 = OpVariable %23 Output
1099 %2 = OpFunction %6 None %7
1100 %24 = OpLabel
1101 %25 = OpVariable %9 Function
1102 %26 = OpVariable %9 Function
1103 %27 = OpVariable %9 Function
1104 %28 = OpVariable %9 Function
1105 %29 = OpVariable %9 Function
1106 %30 = OpVariable %19 Function
1107 %31 = OpAccessChain %13 %5 %12
1108 %32 = OpLoad %10 %31
1109 %33 = OpINotEqual %8 %32 %15
1110 OpStore %25 %33
1111 %34 = OpAccessChain %13 %5 %16
1112 %35 = OpLoad %10 %34
1113 %36 = OpINotEqual %8 %35 %15
1114 OpStore %26 %36
1115 %37 = OpAccessChain %13 %5 %17
1116 %38 = OpLoad %10 %37
1117 %39 = OpINotEqual %8 %38 %15
1118 OpStore %27 %39
1119 %40 = OpAccessChain %13 %5 %18
1120 %41 = OpLoad %10 %40
1121 %42 = OpINotEqual %8 %41 %15
1122 OpStore %28 %42
1123 %43 = OpLoad %8 %25
1124 OpStore %29 %43
1125 OpStore %30 %12
1126 OpBranch %44
1127 %44 = OpLabel
1128 OpLoopMerge %45 %46 None
1129 OpBranch %47
1130 %47 = OpLabel
1131 %48 = OpLoad %8 %29
1132 OpBranchConditional %48 %49 %45
1133 %49 = OpLabel
1134 %50 = OpLoad %8 %25
1135 OpSelectionMerge %51 None
1136 OpBranchConditional %50 %52 %51
1137 %52 = OpLabel
1138 %53 = OpLoad %8 %26
1139 OpStore %29 %53
1140 %54 = OpLoad %10 %30
1141 %55 = OpIAdd %10 %54 %16
1142 OpStore %30 %55
1143 OpBranch %51
1144 %51 = OpLabel
1145 %56 = OpLoad %8 %26
1146 OpSelectionMerge %57 None
1147 OpBranchConditional %56 %58 %57
1148 %58 = OpLabel
1149 %59 = OpLoad %10 %30
1150 %60 = OpIAdd %10 %59 %16
1151 OpStore %30 %60
1152 %61 = OpLoad %8 %29
1153 %62 = OpLoad %8 %25
1154 %63 = OpLogicalOr %8 %61 %62
1155 OpStore %29 %63
1156 %64 = OpLoad %8 %27
1157 OpSelectionMerge %65 None
1158 OpBranchConditional %64 %66 %65
1159 %66 = OpLabel
1160 %67 = OpLoad %10 %30
1161 %68 = OpIAdd %10 %67 %17
1162 OpStore %30 %68
1163 %69 = OpLoad %8 %29
1164 %70 = OpLogicalNot %8 %69
1165 OpStore %29 %70
1166 OpBranch %46
1167 %65 = OpLabel
1168 %71 = OpLoad %8 %29
1169 %72 = OpLogicalOr %8 %71 %20
1170 OpStore %29 %72
1171 OpBranch %46
1172 %57 = OpLabel
1173 OpBranch %73
1174 %73 = OpLabel
1175 OpLoopMerge %74 %75 None
1176 OpBranch %76
1177 %76 = OpLabel
1178 %77 = OpLoad %8 %28
1179 OpSelectionMerge %78 None
1180 OpBranchConditional %77 %79 %80
1181 %79 = OpLabel
1182 %81 = OpLoad %10 %30
1183 OpSelectionMerge %82 None
1184 OpSwitch %81 %83 1 %84 2 %85
1185 %83 = OpLabel
1186 OpBranch %82
1187 %84 = OpLabel
1188 %86 = OpLoad %8 %29
1189 %87 = OpSelect %10 %86 %16 %17
1190 %88 = OpLoad %10 %30
1191 %89 = OpIAdd %10 %88 %87
1192 OpStore %30 %89
1193 OpBranch %82
1194 %85 = OpLabel
1195 OpBranch %75
1196 %82 = OpLabel
1197 %90 = OpLoad %8 %27
1198 OpSelectionMerge %91 None
1199 OpBranchConditional %90 %92 %91
1200 %92 = OpLabel
1201 OpBranch %75
1202 %91 = OpLabel
1203 OpBranch %78
1204 %80 = OpLabel
1205 OpBranch %74
1206 %78 = OpLabel
1207 OpBranch %75
1208 %75 = OpLabel
1209 %93 = OpLoad %8 %29
1210 OpBranchConditional %93 %73 %74
1211 %74 = OpLabel
1212 OpBranch %46
1213 %46 = OpLabel
1214 OpBranch %44
1215 %45 = OpLabel
1216 %94 = OpLoad %10 %30
1217 %95 = OpConvertSToF %21 %94
1218 %96 = OpCompositeConstruct %22 %95 %95 %95 %95
1219 OpStore %3 %96
1220 OpReturn
1221 OpFunctionEnd
1222 )";
1223
1224 const auto env = SPV_ENV_UNIVERSAL_1_3;
1225 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
1226 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
1227 .GetAvailableOpportunities(context.get(), 0);
1228
1229 ASSERT_EQ(2, ops.size());
1230 ASSERT_TRUE(ops[0]->PreconditionHolds());
1231 ops[0]->TryToApply();
1232 CheckValid(env, context.get());
1233 std::string after_op_0 = R"(
1234 OpCapability Shader
1235 %1 = OpExtInstImport "GLSL.std.450"
1236 OpMemoryModel Logical GLSL450
1237 OpEntryPoint Fragment %2 "main" %3
1238 OpExecutionMode %2 OriginUpperLeft
1239 OpSource ESSL 310
1240 OpMemberDecorate %4 0 Offset 0
1241 OpMemberDecorate %4 1 Offset 4
1242 OpMemberDecorate %4 2 Offset 8
1243 OpMemberDecorate %4 3 Offset 12
1244 OpDecorate %4 Block
1245 OpDecorate %5 DescriptorSet 0
1246 OpDecorate %5 Binding 0
1247 OpDecorate %3 Location 0
1248 %6 = OpTypeVoid
1249 %7 = OpTypeFunction %6
1250 %8 = OpTypeBool
1251 %9 = OpTypePointer Function %8
1252 %10 = OpTypeInt 32 1
1253 %4 = OpTypeStruct %10 %10 %10 %10
1254 %11 = OpTypePointer Uniform %4
1255 %5 = OpVariable %11 Uniform
1256 %12 = OpConstant %10 0
1257 %13 = OpTypePointer Uniform %10
1258 %14 = OpTypeInt 32 0
1259 %15 = OpConstant %14 0
1260 %16 = OpConstant %10 1
1261 %17 = OpConstant %10 2
1262 %18 = OpConstant %10 3
1263 %19 = OpTypePointer Function %10
1264 %20 = OpConstantFalse %8
1265 %21 = OpTypeFloat 32
1266 %22 = OpTypeVector %21 4
1267 %23 = OpTypePointer Output %22
1268 %3 = OpVariable %23 Output
1269 %97 = OpConstantTrue %8
1270 %2 = OpFunction %6 None %7
1271 %24 = OpLabel
1272 %25 = OpVariable %9 Function
1273 %26 = OpVariable %9 Function
1274 %27 = OpVariable %9 Function
1275 %28 = OpVariable %9 Function
1276 %29 = OpVariable %9 Function
1277 %30 = OpVariable %19 Function
1278 %31 = OpAccessChain %13 %5 %12
1279 %32 = OpLoad %10 %31
1280 %33 = OpINotEqual %8 %32 %15
1281 OpStore %25 %33
1282 %34 = OpAccessChain %13 %5 %16
1283 %35 = OpLoad %10 %34
1284 %36 = OpINotEqual %8 %35 %15
1285 OpStore %26 %36
1286 %37 = OpAccessChain %13 %5 %17
1287 %38 = OpLoad %10 %37
1288 %39 = OpINotEqual %8 %38 %15
1289 OpStore %27 %39
1290 %40 = OpAccessChain %13 %5 %18
1291 %41 = OpLoad %10 %40
1292 %42 = OpINotEqual %8 %41 %15
1293 OpStore %28 %42
1294 %43 = OpLoad %8 %25
1295 OpStore %29 %43
1296 OpStore %30 %12
1297 OpBranch %44
1298 %44 = OpLabel
1299 OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None
1300 OpBranchConditional %97 %47 %45 ; Was OpBranch %47
1301 %47 = OpLabel
1302 %48 = OpLoad %8 %29
1303 OpBranchConditional %48 %49 %45
1304 %49 = OpLabel
1305 %50 = OpLoad %8 %25
1306 OpSelectionMerge %51 None
1307 OpBranchConditional %50 %52 %51
1308 %52 = OpLabel
1309 %53 = OpLoad %8 %26
1310 OpStore %29 %53
1311 %54 = OpLoad %10 %30
1312 %55 = OpIAdd %10 %54 %16
1313 OpStore %30 %55
1314 OpBranch %51
1315 %51 = OpLabel
1316 %56 = OpLoad %8 %26
1317 OpSelectionMerge %57 None
1318 OpBranchConditional %56 %58 %57
1319 %58 = OpLabel
1320 %59 = OpLoad %10 %30
1321 %60 = OpIAdd %10 %59 %16
1322 OpStore %30 %60
1323 %61 = OpLoad %8 %29
1324 %62 = OpLoad %8 %25
1325 %63 = OpLogicalOr %8 %61 %62
1326 OpStore %29 %63
1327 %64 = OpLoad %8 %27
1328 OpSelectionMerge %65 None
1329 OpBranchConditional %64 %66 %65
1330 %66 = OpLabel
1331 %67 = OpLoad %10 %30
1332 %68 = OpIAdd %10 %67 %17
1333 OpStore %30 %68
1334 %69 = OpLoad %8 %29
1335 %70 = OpLogicalNot %8 %69
1336 OpStore %29 %70
1337 OpBranch %65 ; Was OpBranch %46
1338 %65 = OpLabel
1339 %71 = OpLoad %8 %29
1340 %72 = OpLogicalOr %8 %71 %20
1341 OpStore %29 %72
1342 OpBranch %57 ; Was OpBranch %46
1343 %57 = OpLabel
1344 OpBranch %73
1345 %73 = OpLabel
1346 OpLoopMerge %74 %75 None
1347 OpBranch %76
1348 %76 = OpLabel
1349 %77 = OpLoad %8 %28
1350 OpSelectionMerge %78 None
1351 OpBranchConditional %77 %79 %80
1352 %79 = OpLabel
1353 %81 = OpLoad %10 %30
1354 OpSelectionMerge %82 None
1355 OpSwitch %81 %83 1 %84 2 %85
1356 %83 = OpLabel
1357 OpBranch %82
1358 %84 = OpLabel
1359 %86 = OpLoad %8 %29
1360 %87 = OpSelect %10 %86 %16 %17
1361 %88 = OpLoad %10 %30
1362 %89 = OpIAdd %10 %88 %87
1363 OpStore %30 %89
1364 OpBranch %82
1365 %85 = OpLabel
1366 OpBranch %75
1367 %82 = OpLabel
1368 %90 = OpLoad %8 %27
1369 OpSelectionMerge %91 None
1370 OpBranchConditional %90 %92 %91
1371 %92 = OpLabel
1372 OpBranch %75
1373 %91 = OpLabel
1374 OpBranch %78
1375 %80 = OpLabel
1376 OpBranch %74
1377 %78 = OpLabel
1378 OpBranch %75
1379 %75 = OpLabel
1380 %93 = OpLoad %8 %29
1381 OpBranchConditional %93 %73 %74
1382 %74 = OpLabel
1383 OpBranch %45 ; Was OpBranch %46
1384 %46 = OpLabel
1385 OpBranch %44
1386 %45 = OpLabel
1387 %94 = OpLoad %10 %30
1388 %95 = OpConvertSToF %21 %94
1389 %96 = OpCompositeConstruct %22 %95 %95 %95 %95
1390 OpStore %3 %96
1391 OpReturn
1392 OpFunctionEnd
1393 )";
1394 CheckEqual(env, after_op_0, context.get());
1395 ASSERT_TRUE(ops[1]->PreconditionHolds());
1396 ops[1]->TryToApply();
1397 CheckValid(env, context.get());
1398
1399 std::string after_op_1 = R"(
1400 OpCapability Shader
1401 %1 = OpExtInstImport "GLSL.std.450"
1402 OpMemoryModel Logical GLSL450
1403 OpEntryPoint Fragment %2 "main" %3
1404 OpExecutionMode %2 OriginUpperLeft
1405 OpSource ESSL 310
1406 OpMemberDecorate %4 0 Offset 0
1407 OpMemberDecorate %4 1 Offset 4
1408 OpMemberDecorate %4 2 Offset 8
1409 OpMemberDecorate %4 3 Offset 12
1410 OpDecorate %4 Block
1411 OpDecorate %5 DescriptorSet 0
1412 OpDecorate %5 Binding 0
1413 OpDecorate %3 Location 0
1414 %6 = OpTypeVoid
1415 %7 = OpTypeFunction %6
1416 %8 = OpTypeBool
1417 %9 = OpTypePointer Function %8
1418 %10 = OpTypeInt 32 1
1419 %4 = OpTypeStruct %10 %10 %10 %10
1420 %11 = OpTypePointer Uniform %4
1421 %5 = OpVariable %11 Uniform
1422 %12 = OpConstant %10 0
1423 %13 = OpTypePointer Uniform %10
1424 %14 = OpTypeInt 32 0
1425 %15 = OpConstant %14 0
1426 %16 = OpConstant %10 1
1427 %17 = OpConstant %10 2
1428 %18 = OpConstant %10 3
1429 %19 = OpTypePointer Function %10
1430 %20 = OpConstantFalse %8
1431 %21 = OpTypeFloat 32
1432 %22 = OpTypeVector %21 4
1433 %23 = OpTypePointer Output %22
1434 %3 = OpVariable %23 Output
1435 %97 = OpConstantTrue %8
1436 %2 = OpFunction %6 None %7
1437 %24 = OpLabel
1438 %25 = OpVariable %9 Function
1439 %26 = OpVariable %9 Function
1440 %27 = OpVariable %9 Function
1441 %28 = OpVariable %9 Function
1442 %29 = OpVariable %9 Function
1443 %30 = OpVariable %19 Function
1444 %31 = OpAccessChain %13 %5 %12
1445 %32 = OpLoad %10 %31
1446 %33 = OpINotEqual %8 %32 %15
1447 OpStore %25 %33
1448 %34 = OpAccessChain %13 %5 %16
1449 %35 = OpLoad %10 %34
1450 %36 = OpINotEqual %8 %35 %15
1451 OpStore %26 %36
1452 %37 = OpAccessChain %13 %5 %17
1453 %38 = OpLoad %10 %37
1454 %39 = OpINotEqual %8 %38 %15
1455 OpStore %27 %39
1456 %40 = OpAccessChain %13 %5 %18
1457 %41 = OpLoad %10 %40
1458 %42 = OpINotEqual %8 %41 %15
1459 OpStore %28 %42
1460 %43 = OpLoad %8 %25
1461 OpStore %29 %43
1462 OpStore %30 %12
1463 OpBranch %44
1464 %44 = OpLabel
1465 OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None
1466 OpBranchConditional %97 %47 %45 ; Was OpBranch %47
1467 %47 = OpLabel
1468 %48 = OpLoad %8 %29
1469 OpBranchConditional %48 %49 %45
1470 %49 = OpLabel
1471 %50 = OpLoad %8 %25
1472 OpSelectionMerge %51 None
1473 OpBranchConditional %50 %52 %51
1474 %52 = OpLabel
1475 %53 = OpLoad %8 %26
1476 OpStore %29 %53
1477 %54 = OpLoad %10 %30
1478 %55 = OpIAdd %10 %54 %16
1479 OpStore %30 %55
1480 OpBranch %51
1481 %51 = OpLabel
1482 %56 = OpLoad %8 %26
1483 OpSelectionMerge %57 None
1484 OpBranchConditional %56 %58 %57
1485 %58 = OpLabel
1486 %59 = OpLoad %10 %30
1487 %60 = OpIAdd %10 %59 %16
1488 OpStore %30 %60
1489 %61 = OpLoad %8 %29
1490 %62 = OpLoad %8 %25
1491 %63 = OpLogicalOr %8 %61 %62
1492 OpStore %29 %63
1493 %64 = OpLoad %8 %27
1494 OpSelectionMerge %65 None
1495 OpBranchConditional %64 %66 %65
1496 %66 = OpLabel
1497 %67 = OpLoad %10 %30
1498 %68 = OpIAdd %10 %67 %17
1499 OpStore %30 %68
1500 %69 = OpLoad %8 %29
1501 %70 = OpLogicalNot %8 %69
1502 OpStore %29 %70
1503 OpBranch %65 ; Was OpBranch %46
1504 %65 = OpLabel
1505 %71 = OpLoad %8 %29
1506 %72 = OpLogicalOr %8 %71 %20
1507 OpStore %29 %72
1508 OpBranch %57 ; Was OpBranch %46
1509 %57 = OpLabel
1510 OpBranch %73
1511 %73 = OpLabel
1512 OpSelectionMerge %74 None ; Was OpLoopMerge %74 %75 None
1513 OpBranchConditional %97 %76 %74 ; Was OpBranch %76
1514 %76 = OpLabel
1515 %77 = OpLoad %8 %28
1516 OpSelectionMerge %78 None
1517 OpBranchConditional %77 %79 %80
1518 %79 = OpLabel
1519 %81 = OpLoad %10 %30
1520 OpSelectionMerge %82 None
1521 OpSwitch %81 %83 1 %84 2 %85
1522 %83 = OpLabel
1523 OpBranch %82
1524 %84 = OpLabel
1525 %86 = OpLoad %8 %29
1526 %87 = OpSelect %10 %86 %16 %17
1527 %88 = OpLoad %10 %30
1528 %89 = OpIAdd %10 %88 %87
1529 OpStore %30 %89
1530 OpBranch %82
1531 %85 = OpLabel
1532 OpBranch %82
1533 %82 = OpLabel
1534 %90 = OpLoad %8 %27
1535 OpSelectionMerge %91 None
1536 OpBranchConditional %90 %92 %91
1537 %92 = OpLabel
1538 OpBranch %91
1539 %91 = OpLabel
1540 OpBranch %78
1541 %80 = OpLabel
1542 OpBranch %78 ; Was OpBranch %74
1543 %78 = OpLabel
1544 OpBranch %74
1545 %75 = OpLabel
1546 %93 = OpLoad %8 %29
1547 OpBranchConditional %93 %73 %74
1548 %74 = OpLabel
1549 OpBranch %45 ; Was OpBranch %46
1550 %46 = OpLabel
1551 OpBranch %44
1552 %45 = OpLabel
1553 %94 = OpLoad %10 %30
1554 %95 = OpConvertSToF %21 %94
1555 %96 = OpCompositeConstruct %22 %95 %95 %95 %95
1556 OpStore %3 %96
1557 OpReturn
1558 OpFunctionEnd
1559 )";
1560 CheckEqual(env, after_op_1, context.get());
1561 }
1562
TEST(StructuredLoopToSelectionReductionPassTest,ComplexOptimized)1563 TEST(StructuredLoopToSelectionReductionPassTest, ComplexOptimized) {
1564 std::string shader = R"(
1565 OpCapability Shader
1566 %1 = OpExtInstImport "GLSL.std.450"
1567 OpMemoryModel Logical GLSL450
1568 OpEntryPoint Fragment %2 "main" %3
1569 OpExecutionMode %2 OriginUpperLeft
1570 OpSource ESSL 310
1571 OpMemberDecorate %4 0 Offset 0
1572 OpMemberDecorate %4 1 Offset 4
1573 OpMemberDecorate %4 2 Offset 8
1574 OpMemberDecorate %4 3 Offset 12
1575 OpDecorate %4 Block
1576 OpDecorate %5 DescriptorSet 0
1577 OpDecorate %5 Binding 0
1578 OpDecorate %3 Location 0
1579 %6 = OpTypeVoid
1580 %7 = OpTypeFunction %6
1581 %8 = OpTypeBool
1582 %10 = OpTypeInt 32 1
1583 %4 = OpTypeStruct %10 %10 %10 %10
1584 %11 = OpTypePointer Uniform %4
1585 %5 = OpVariable %11 Uniform
1586 %12 = OpConstant %10 0
1587 %13 = OpTypePointer Uniform %10
1588 %14 = OpTypeInt 32 0
1589 %15 = OpConstant %14 0
1590 %16 = OpConstant %10 1
1591 %17 = OpConstant %10 2
1592 %18 = OpConstant %10 3
1593 %20 = OpConstantFalse %8
1594 %21 = OpTypeFloat 32
1595 %22 = OpTypeVector %21 4
1596 %23 = OpTypePointer Output %22
1597 %3 = OpVariable %23 Output
1598 %2 = OpFunction %6 None %7
1599 %24 = OpLabel
1600 %31 = OpAccessChain %13 %5 %12
1601 %32 = OpLoad %10 %31
1602 %33 = OpINotEqual %8 %32 %15
1603 %34 = OpAccessChain %13 %5 %16
1604 %35 = OpLoad %10 %34
1605 %36 = OpINotEqual %8 %35 %15
1606 %37 = OpAccessChain %13 %5 %17
1607 %38 = OpLoad %10 %37
1608 %39 = OpINotEqual %8 %38 %15
1609 %40 = OpAccessChain %13 %5 %18
1610 %41 = OpLoad %10 %40
1611 %42 = OpINotEqual %8 %41 %15
1612 OpBranch %44
1613 %44 = OpLabel
1614 %98 = OpPhi %10 %12 %24 %107 %46
1615 %97 = OpPhi %8 %33 %24 %105 %46
1616 OpLoopMerge %45 %46 None
1617 OpBranchConditional %97 %49 %45
1618 %49 = OpLabel
1619 OpSelectionMerge %51 None
1620 OpBranchConditional %33 %52 %51
1621 %52 = OpLabel
1622 %55 = OpIAdd %10 %98 %16
1623 OpBranch %51
1624 %51 = OpLabel
1625 %100 = OpPhi %10 %98 %49 %55 %52
1626 %113 = OpSelect %8 %33 %36 %97
1627 OpSelectionMerge %57 None
1628 OpBranchConditional %36 %58 %57
1629 %58 = OpLabel
1630 %60 = OpIAdd %10 %100 %16
1631 %63 = OpLogicalOr %8 %113 %33
1632 OpSelectionMerge %65 None
1633 OpBranchConditional %39 %66 %65
1634 %66 = OpLabel
1635 %68 = OpIAdd %10 %100 %18
1636 %70 = OpLogicalNot %8 %63
1637 OpBranch %46
1638 %65 = OpLabel
1639 %72 = OpLogicalOr %8 %63 %20
1640 OpBranch %46
1641 %57 = OpLabel
1642 OpBranch %73
1643 %73 = OpLabel
1644 %99 = OpPhi %10 %100 %57 %109 %75
1645 OpLoopMerge %74 %75 None
1646 OpBranch %76
1647 %76 = OpLabel
1648 OpSelectionMerge %78 None
1649 OpBranchConditional %42 %79 %80
1650 %79 = OpLabel
1651 OpSelectionMerge %82 None
1652 OpSwitch %99 %83 1 %84 2 %85
1653 %83 = OpLabel
1654 OpBranch %82
1655 %84 = OpLabel
1656 %87 = OpSelect %10 %113 %16 %17
1657 %89 = OpIAdd %10 %99 %87
1658 OpBranch %82
1659 %85 = OpLabel
1660 OpBranch %75
1661 %82 = OpLabel
1662 %110 = OpPhi %10 %99 %83 %89 %84
1663 OpSelectionMerge %91 None
1664 OpBranchConditional %39 %92 %91
1665 %92 = OpLabel
1666 OpBranch %75
1667 %91 = OpLabel
1668 OpBranch %78
1669 %80 = OpLabel
1670 OpBranch %74
1671 %78 = OpLabel
1672 OpBranch %75
1673 %75 = OpLabel
1674 %109 = OpPhi %10 %99 %85 %110 %92 %110 %78
1675 OpBranchConditional %113 %73 %74
1676 %74 = OpLabel
1677 %108 = OpPhi %10 %99 %80 %109 %75
1678 OpBranch %46
1679 %46 = OpLabel
1680 %107 = OpPhi %10 %68 %66 %60 %65 %108 %74
1681 %105 = OpPhi %8 %70 %66 %72 %65 %113 %74
1682 OpBranch %44
1683 %45 = OpLabel
1684 %95 = OpConvertSToF %21 %98
1685 %96 = OpCompositeConstruct %22 %95 %95 %95 %95
1686 OpStore %3 %96
1687 OpReturn
1688 OpFunctionEnd
1689 )";
1690
1691 const auto env = SPV_ENV_UNIVERSAL_1_3;
1692 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
1693 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
1694 .GetAvailableOpportunities(context.get(), 0);
1695
1696 ASSERT_EQ(2, ops.size());
1697 ASSERT_TRUE(ops[0]->PreconditionHolds());
1698 ops[0]->TryToApply();
1699 CheckValid(env, context.get());
1700 std::string after_op_0 = R"(
1701 OpCapability Shader
1702 %1 = OpExtInstImport "GLSL.std.450"
1703 OpMemoryModel Logical GLSL450
1704 OpEntryPoint Fragment %2 "main" %3
1705 OpExecutionMode %2 OriginUpperLeft
1706 OpSource ESSL 310
1707 OpMemberDecorate %4 0 Offset 0
1708 OpMemberDecorate %4 1 Offset 4
1709 OpMemberDecorate %4 2 Offset 8
1710 OpMemberDecorate %4 3 Offset 12
1711 OpDecorate %4 Block
1712 OpDecorate %5 DescriptorSet 0
1713 OpDecorate %5 Binding 0
1714 OpDecorate %3 Location 0
1715 %6 = OpTypeVoid
1716 %7 = OpTypeFunction %6
1717 %8 = OpTypeBool
1718 %10 = OpTypeInt 32 1
1719 %4 = OpTypeStruct %10 %10 %10 %10
1720 %11 = OpTypePointer Uniform %4
1721 %5 = OpVariable %11 Uniform
1722 %12 = OpConstant %10 0
1723 %13 = OpTypePointer Uniform %10
1724 %14 = OpTypeInt 32 0
1725 %15 = OpConstant %14 0
1726 %16 = OpConstant %10 1
1727 %17 = OpConstant %10 2
1728 %18 = OpConstant %10 3
1729 %20 = OpConstantFalse %8
1730 %21 = OpTypeFloat 32
1731 %22 = OpTypeVector %21 4
1732 %23 = OpTypePointer Output %22
1733 %3 = OpVariable %23 Output
1734 %114 = OpUndef %10
1735 %115 = OpUndef %8
1736 %2 = OpFunction %6 None %7
1737 %24 = OpLabel
1738 %31 = OpAccessChain %13 %5 %12
1739 %32 = OpLoad %10 %31
1740 %33 = OpINotEqual %8 %32 %15
1741 %34 = OpAccessChain %13 %5 %16
1742 %35 = OpLoad %10 %34
1743 %36 = OpINotEqual %8 %35 %15
1744 %37 = OpAccessChain %13 %5 %17
1745 %38 = OpLoad %10 %37
1746 %39 = OpINotEqual %8 %38 %15
1747 %40 = OpAccessChain %13 %5 %18
1748 %41 = OpLoad %10 %40
1749 %42 = OpINotEqual %8 %41 %15
1750 OpBranch %44
1751 %44 = OpLabel
1752 %98 = OpPhi %10 %12 %24 %114 %46
1753 %97 = OpPhi %8 %33 %24 %115 %46
1754 OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None
1755 OpBranchConditional %97 %49 %45
1756 %49 = OpLabel
1757 OpSelectionMerge %51 None
1758 OpBranchConditional %33 %52 %51
1759 %52 = OpLabel
1760 %55 = OpIAdd %10 %98 %16
1761 OpBranch %51
1762 %51 = OpLabel
1763 %100 = OpPhi %10 %98 %49 %55 %52
1764 %113 = OpSelect %8 %33 %36 %97
1765 OpSelectionMerge %57 None
1766 OpBranchConditional %36 %58 %57
1767 %58 = OpLabel
1768 %60 = OpIAdd %10 %100 %16
1769 %63 = OpLogicalOr %8 %113 %33
1770 OpSelectionMerge %65 None
1771 OpBranchConditional %39 %66 %65
1772 %66 = OpLabel
1773 %68 = OpIAdd %10 %100 %18
1774 %70 = OpLogicalNot %8 %63
1775 OpBranch %65 ; Was OpBranch %46
1776 %65 = OpLabel
1777 %72 = OpLogicalOr %8 %63 %20
1778 OpBranch %57 ; Was OpBranch %46
1779 %57 = OpLabel
1780 OpBranch %73
1781 %73 = OpLabel
1782 %99 = OpPhi %10 %100 %57 %109 %75
1783 OpLoopMerge %74 %75 None
1784 OpBranch %76
1785 %76 = OpLabel
1786 OpSelectionMerge %78 None
1787 OpBranchConditional %42 %79 %80
1788 %79 = OpLabel
1789 OpSelectionMerge %82 None
1790 OpSwitch %99 %83 1 %84 2 %85
1791 %83 = OpLabel
1792 OpBranch %82
1793 %84 = OpLabel
1794 %87 = OpSelect %10 %113 %16 %17
1795 %89 = OpIAdd %10 %99 %87
1796 OpBranch %82
1797 %85 = OpLabel
1798 OpBranch %75
1799 %82 = OpLabel
1800 %110 = OpPhi %10 %99 %83 %89 %84
1801 OpSelectionMerge %91 None
1802 OpBranchConditional %39 %92 %91
1803 %92 = OpLabel
1804 OpBranch %75
1805 %91 = OpLabel
1806 OpBranch %78
1807 %80 = OpLabel
1808 OpBranch %74
1809 %78 = OpLabel
1810 OpBranch %75
1811 %75 = OpLabel
1812 %109 = OpPhi %10 %99 %85 %110 %92 %110 %78
1813 OpBranchConditional %113 %73 %74
1814 %74 = OpLabel
1815 %108 = OpPhi %10 %99 %80 %109 %75
1816 OpBranch %45 ; Was OpBranch %46
1817 %46 = OpLabel
1818 %107 = OpPhi %10 ; Was OpPhi %10 %68 %66 %60 %65 %108 %74
1819 %105 = OpPhi %8 ; Was OpPhi %8 %70 %66 %72 %65 %113 %74
1820 OpBranch %44
1821 %45 = OpLabel
1822 %95 = OpConvertSToF %21 %98
1823 %96 = OpCompositeConstruct %22 %95 %95 %95 %95
1824 OpStore %3 %96
1825 OpReturn
1826 OpFunctionEnd
1827 )";
1828 CheckEqual(env, after_op_0, context.get());
1829
1830 ASSERT_TRUE(ops[1]->PreconditionHolds());
1831 ops[1]->TryToApply();
1832 CheckValid(env, context.get());
1833 std::string after_op_1 = R"(
1834 OpCapability Shader
1835 %1 = OpExtInstImport "GLSL.std.450"
1836 OpMemoryModel Logical GLSL450
1837 OpEntryPoint Fragment %2 "main" %3
1838 OpExecutionMode %2 OriginUpperLeft
1839 OpSource ESSL 310
1840 OpMemberDecorate %4 0 Offset 0
1841 OpMemberDecorate %4 1 Offset 4
1842 OpMemberDecorate %4 2 Offset 8
1843 OpMemberDecorate %4 3 Offset 12
1844 OpDecorate %4 Block
1845 OpDecorate %5 DescriptorSet 0
1846 OpDecorate %5 Binding 0
1847 OpDecorate %3 Location 0
1848 %6 = OpTypeVoid
1849 %7 = OpTypeFunction %6
1850 %8 = OpTypeBool
1851 %10 = OpTypeInt 32 1
1852 %4 = OpTypeStruct %10 %10 %10 %10
1853 %11 = OpTypePointer Uniform %4
1854 %5 = OpVariable %11 Uniform
1855 %12 = OpConstant %10 0
1856 %13 = OpTypePointer Uniform %10
1857 %14 = OpTypeInt 32 0
1858 %15 = OpConstant %14 0
1859 %16 = OpConstant %10 1
1860 %17 = OpConstant %10 2
1861 %18 = OpConstant %10 3
1862 %20 = OpConstantFalse %8
1863 %21 = OpTypeFloat 32
1864 %22 = OpTypeVector %21 4
1865 %23 = OpTypePointer Output %22
1866 %3 = OpVariable %23 Output
1867 %114 = OpUndef %10
1868 %115 = OpUndef %8
1869 %116 = OpConstantTrue %8
1870 %2 = OpFunction %6 None %7
1871 %24 = OpLabel
1872 %31 = OpAccessChain %13 %5 %12
1873 %32 = OpLoad %10 %31
1874 %33 = OpINotEqual %8 %32 %15
1875 %34 = OpAccessChain %13 %5 %16
1876 %35 = OpLoad %10 %34
1877 %36 = OpINotEqual %8 %35 %15
1878 %37 = OpAccessChain %13 %5 %17
1879 %38 = OpLoad %10 %37
1880 %39 = OpINotEqual %8 %38 %15
1881 %40 = OpAccessChain %13 %5 %18
1882 %41 = OpLoad %10 %40
1883 %42 = OpINotEqual %8 %41 %15
1884 OpBranch %44
1885 %44 = OpLabel
1886 %98 = OpPhi %10 %12 %24 %114 %46
1887 %97 = OpPhi %8 %33 %24 %115 %46
1888 OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None
1889 OpBranchConditional %97 %49 %45
1890 %49 = OpLabel
1891 OpSelectionMerge %51 None
1892 OpBranchConditional %33 %52 %51
1893 %52 = OpLabel
1894 %55 = OpIAdd %10 %98 %16
1895 OpBranch %51
1896 %51 = OpLabel
1897 %100 = OpPhi %10 %98 %49 %55 %52
1898 %113 = OpSelect %8 %33 %36 %97
1899 OpSelectionMerge %57 None
1900 OpBranchConditional %36 %58 %57
1901 %58 = OpLabel
1902 %60 = OpIAdd %10 %100 %16
1903 %63 = OpLogicalOr %8 %113 %33
1904 OpSelectionMerge %65 None
1905 OpBranchConditional %39 %66 %65
1906 %66 = OpLabel
1907 %68 = OpIAdd %10 %100 %18
1908 %70 = OpLogicalNot %8 %63
1909 OpBranch %65 ; Was OpBranch %46
1910 %65 = OpLabel
1911 %72 = OpLogicalOr %8 %63 %20
1912 OpBranch %57 ; Was OpBranch %46
1913 %57 = OpLabel
1914 OpBranch %73
1915 %73 = OpLabel
1916 %99 = OpPhi %10 %100 %57 %114 %75
1917 OpSelectionMerge %74 None ; Was OpLoopMerge %74 %75 None
1918 OpBranchConditional %116 %76 %74
1919 %76 = OpLabel
1920 OpSelectionMerge %78 None
1921 OpBranchConditional %42 %79 %80
1922 %79 = OpLabel
1923 OpSelectionMerge %82 None
1924 OpSwitch %99 %83 1 %84 2 %85
1925 %83 = OpLabel
1926 OpBranch %82
1927 %84 = OpLabel
1928 %87 = OpSelect %10 %113 %16 %17
1929 %89 = OpIAdd %10 %99 %87
1930 OpBranch %82
1931 %85 = OpLabel
1932 OpBranch %82 ; Was OpBranch %75
1933 %82 = OpLabel
1934 %110 = OpPhi %10 %99 %83 %89 %84 %114 %85 ; Was OpPhi %10 %99 %83 %89 %84
1935 OpSelectionMerge %91 None
1936 OpBranchConditional %39 %92 %91
1937 %92 = OpLabel
1938 OpBranch %91 ; OpBranch %75
1939 %91 = OpLabel
1940 OpBranch %78
1941 %80 = OpLabel
1942 OpBranch %78 ; Was OpBranch %74
1943 %78 = OpLabel
1944 OpBranch %74 ; Was OpBranch %75
1945 %75 = OpLabel
1946 %109 = OpPhi %10 ; Was OpPhi %10 %99 %85 %110 %92 %110 %78
1947 OpBranchConditional %115 %73 %74
1948 %74 = OpLabel
1949 %108 = OpPhi %10 %114 %75 %114 %78 %114 %73 ; Was OpPhi %10 %99 %80 %109 %75
1950 OpBranch %45 ; Was OpBranch %46
1951 %46 = OpLabel
1952 %107 = OpPhi %10 ; Was OpPhi %10 %68 %66 %60 %65 %108 %74
1953 %105 = OpPhi %8 ; Was OpPhi %8 %70 %66 %72 %65 %113 %74
1954 OpBranch %44
1955 %45 = OpLabel
1956 %95 = OpConvertSToF %21 %98
1957 %96 = OpCompositeConstruct %22 %95 %95 %95 %95
1958 OpStore %3 %96
1959 OpReturn
1960 OpFunctionEnd
1961 )";
1962 CheckEqual(env, after_op_1, context.get());
1963 }
1964
TEST(StructuredLoopToSelectionReductionPassTest,DominanceIssue)1965 TEST(StructuredLoopToSelectionReductionPassTest, DominanceIssue) {
1966 // Exposes a scenario where redirecting edges results in uses of ids being
1967 // non-dominated. We replace such uses with OpUndef to account for this.
1968 std::string shader = R"(
1969 OpCapability Shader
1970 %1 = OpExtInstImport "GLSL.std.450"
1971 OpMemoryModel Logical GLSL450
1972 OpEntryPoint Fragment %4 "main"
1973 OpExecutionMode %4 OriginUpperLeft
1974 OpSource ESSL 310
1975 %2 = OpTypeVoid
1976 %3 = OpTypeFunction %2
1977 %5 = OpTypeInt 32 1
1978 %7 = OpTypePointer Function %5
1979 %6 = OpTypeBool
1980 %8 = OpConstantTrue %6
1981 %9 = OpConstant %5 10
1982 %10 = OpConstant %5 20
1983 %11 = OpConstant %5 30
1984 %4 = OpFunction %2 None %3
1985 %12 = OpLabel
1986 OpBranch %13
1987 %13 = OpLabel
1988 OpLoopMerge %14 %15 None
1989 OpBranch %16
1990 %16 = OpLabel
1991 OpSelectionMerge %17 None
1992 OpBranchConditional %8 %18 %19
1993 %18 = OpLabel
1994 OpBranch %14
1995 %19 = OpLabel
1996 %20 = OpIAdd %5 %9 %10
1997 OpBranch %17
1998 %17 = OpLabel
1999 %21 = OpIAdd %5 %20 %11
2000 OpBranchConditional %8 %14 %15
2001 %15 = OpLabel
2002 OpBranch %13
2003 %14 = OpLabel
2004 OpReturn
2005 OpFunctionEnd
2006 )";
2007
2008 const auto env = SPV_ENV_UNIVERSAL_1_3;
2009 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2010 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2011 .GetAvailableOpportunities(context.get(), 0);
2012 ASSERT_EQ(1, ops.size());
2013
2014 ASSERT_TRUE(ops[0]->PreconditionHolds());
2015 ops[0]->TryToApply();
2016 CheckValid(env, context.get());
2017
2018 std::string expected = R"(
2019 OpCapability Shader
2020 %1 = OpExtInstImport "GLSL.std.450"
2021 OpMemoryModel Logical GLSL450
2022 OpEntryPoint Fragment %4 "main"
2023 OpExecutionMode %4 OriginUpperLeft
2024 OpSource ESSL 310
2025 %2 = OpTypeVoid
2026 %3 = OpTypeFunction %2
2027 %5 = OpTypeInt 32 1
2028 %7 = OpTypePointer Function %5
2029 %6 = OpTypeBool
2030 %8 = OpConstantTrue %6
2031 %9 = OpConstant %5 10
2032 %10 = OpConstant %5 20
2033 %11 = OpConstant %5 30
2034 %22 = OpUndef %5
2035 %4 = OpFunction %2 None %3
2036 %12 = OpLabel
2037 OpBranch %13
2038 %13 = OpLabel
2039 OpSelectionMerge %14 None
2040 OpBranchConditional %8 %16 %14
2041 %16 = OpLabel
2042 OpSelectionMerge %17 None
2043 OpBranchConditional %8 %18 %19
2044 %18 = OpLabel
2045 OpBranch %17
2046 %19 = OpLabel
2047 %20 = OpIAdd %5 %9 %10
2048 OpBranch %17
2049 %17 = OpLabel
2050 %21 = OpIAdd %5 %22 %11
2051 OpBranchConditional %8 %14 %14
2052 %15 = OpLabel
2053 OpBranch %13
2054 %14 = OpLabel
2055 OpReturn
2056 OpFunctionEnd
2057 )";
2058 CheckEqual(env, expected, context.get());
2059 }
2060
TEST(StructuredLoopToSelectionReductionPassTest,AccessChainIssue)2061 TEST(StructuredLoopToSelectionReductionPassTest, AccessChainIssue) {
2062 // Exposes a scenario where redirecting edges results in a use of an id
2063 // generated by an access chain being non-dominated.
2064 std::string shader = R"(
2065 OpCapability Shader
2066 %1 = OpExtInstImport "GLSL.std.450"
2067 OpMemoryModel Logical GLSL450
2068 OpEntryPoint Fragment %4 "main" %56
2069 OpExecutionMode %4 OriginUpperLeft
2070 OpSource ESSL 310
2071 OpMemberDecorate %28 0 Offset 0
2072 OpDecorate %28 Block
2073 OpDecorate %30 DescriptorSet 0
2074 OpDecorate %30 Binding 0
2075 OpDecorate %56 Location 0
2076 %2 = OpTypeVoid
2077 %3 = OpTypeFunction %2
2078 %6 = OpTypeFloat 32
2079 %7 = OpTypeVector %6 2
2080 %8 = OpTypePointer Function %7
2081 %60 = OpTypePointer Private %7
2082 %10 = OpConstant %6 0
2083 %11 = OpConstantComposite %7 %10 %10
2084 %12 = OpTypePointer Function %6
2085 %59 = OpTypePointer Private %6
2086 %14 = OpTypeInt 32 1
2087 %15 = OpTypePointer Function %14
2088 %17 = OpConstant %14 0
2089 %24 = OpConstant %14 100
2090 %25 = OpTypeBool
2091 %28 = OpTypeStruct %6
2092 %29 = OpTypePointer Uniform %28
2093 %30 = OpVariable %29 Uniform
2094 %31 = OpTypePointer Uniform %6
2095 %39 = OpTypeInt 32 0
2096 %40 = OpConstant %39 1
2097 %45 = OpConstant %39 0
2098 %52 = OpConstant %14 1
2099 %54 = OpTypeVector %6 4
2100 %55 = OpTypePointer Output %54
2101 %56 = OpVariable %55 Output
2102 %9 = OpVariable %60 Private
2103 %4 = OpFunction %2 None %3
2104 %5 = OpLabel
2105 %13 = OpVariable %12 Function
2106 %16 = OpVariable %15 Function
2107 %38 = OpVariable %12 Function
2108 OpStore %9 %11
2109 OpStore %13 %10
2110 OpStore %16 %17
2111 OpBranch %18
2112 %18 = OpLabel
2113 OpLoopMerge %20 %21 None
2114 OpBranch %22
2115 %22 = OpLabel
2116 %23 = OpLoad %14 %16
2117 %26 = OpSLessThan %25 %23 %24
2118 OpBranchConditional %26 %19 %20
2119 %19 = OpLabel
2120 %27 = OpLoad %14 %16
2121 %32 = OpAccessChain %31 %30 %17
2122 %33 = OpLoad %6 %32
2123 %34 = OpConvertFToS %14 %33
2124 %35 = OpSLessThan %25 %27 %34
2125 OpSelectionMerge %37 None
2126 OpBranchConditional %35 %36 %44
2127 %36 = OpLabel
2128 %41 = OpAccessChain %59 %9 %40
2129 %42 = OpLoad %6 %41
2130 OpStore %38 %42
2131 OpBranch %20
2132 %44 = OpLabel
2133 %46 = OpAccessChain %59 %9 %45
2134 OpBranch %37
2135 %37 = OpLabel
2136 %47 = OpLoad %6 %46
2137 OpStore %38 %47
2138 %48 = OpLoad %6 %38
2139 %49 = OpLoad %6 %13
2140 %50 = OpFAdd %6 %49 %48
2141 OpStore %13 %50
2142 OpBranch %21
2143 %21 = OpLabel
2144 %51 = OpLoad %14 %16
2145 %53 = OpIAdd %14 %51 %52
2146 OpStore %16 %53
2147 OpBranch %18
2148 %20 = OpLabel
2149 %57 = OpLoad %6 %13
2150 %58 = OpCompositeConstruct %54 %57 %57 %57 %57
2151 OpStore %56 %58
2152 OpReturn
2153 OpFunctionEnd
2154 )";
2155
2156 const auto env = SPV_ENV_UNIVERSAL_1_3;
2157 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2158 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2159 .GetAvailableOpportunities(context.get(), 0);
2160 ASSERT_EQ(1, ops.size());
2161
2162 ASSERT_TRUE(ops[0]->PreconditionHolds());
2163 ops[0]->TryToApply();
2164 CheckValid(env, context.get());
2165
2166 std::string expected = R"(
2167 OpCapability Shader
2168 %1 = OpExtInstImport "GLSL.std.450"
2169 OpMemoryModel Logical GLSL450
2170 OpEntryPoint Fragment %4 "main" %56
2171 OpExecutionMode %4 OriginUpperLeft
2172 OpSource ESSL 310
2173 OpMemberDecorate %28 0 Offset 0
2174 OpDecorate %28 Block
2175 OpDecorate %30 DescriptorSet 0
2176 OpDecorate %30 Binding 0
2177 OpDecorate %56 Location 0
2178 %2 = OpTypeVoid
2179 %3 = OpTypeFunction %2
2180 %6 = OpTypeFloat 32
2181 %7 = OpTypeVector %6 2
2182 %8 = OpTypePointer Function %7
2183 %60 = OpTypePointer Private %7
2184 %10 = OpConstant %6 0
2185 %11 = OpConstantComposite %7 %10 %10
2186 %12 = OpTypePointer Function %6
2187 %59 = OpTypePointer Private %6
2188 %14 = OpTypeInt 32 1
2189 %15 = OpTypePointer Function %14
2190 %17 = OpConstant %14 0
2191 %24 = OpConstant %14 100
2192 %25 = OpTypeBool
2193 %28 = OpTypeStruct %6
2194 %29 = OpTypePointer Uniform %28
2195 %30 = OpVariable %29 Uniform
2196 %31 = OpTypePointer Uniform %6
2197 %39 = OpTypeInt 32 0
2198 %40 = OpConstant %39 1
2199 %45 = OpConstant %39 0
2200 %52 = OpConstant %14 1
2201 %54 = OpTypeVector %6 4
2202 %55 = OpTypePointer Output %54
2203 %56 = OpVariable %55 Output
2204 %9 = OpVariable %60 Private
2205 %61 = OpConstantTrue %25
2206 %62 = OpVariable %59 Private
2207 %4 = OpFunction %2 None %3
2208 %5 = OpLabel
2209 %13 = OpVariable %12 Function
2210 %16 = OpVariable %15 Function
2211 %38 = OpVariable %12 Function
2212 OpStore %9 %11
2213 OpStore %13 %10
2214 OpStore %16 %17
2215 OpBranch %18
2216 %18 = OpLabel
2217 OpSelectionMerge %20 None
2218 OpBranchConditional %61 %22 %20
2219 %22 = OpLabel
2220 %23 = OpLoad %14 %16
2221 %26 = OpSLessThan %25 %23 %24
2222 OpBranchConditional %26 %19 %20
2223 %19 = OpLabel
2224 %27 = OpLoad %14 %16
2225 %32 = OpAccessChain %31 %30 %17
2226 %33 = OpLoad %6 %32
2227 %34 = OpConvertFToS %14 %33
2228 %35 = OpSLessThan %25 %27 %34
2229 OpSelectionMerge %37 None
2230 OpBranchConditional %35 %36 %44
2231 %36 = OpLabel
2232 %41 = OpAccessChain %59 %9 %40
2233 %42 = OpLoad %6 %41
2234 OpStore %38 %42
2235 OpBranch %37
2236 %44 = OpLabel
2237 %46 = OpAccessChain %59 %9 %45
2238 OpBranch %37
2239 %37 = OpLabel
2240 %47 = OpLoad %6 %62
2241 OpStore %38 %47
2242 %48 = OpLoad %6 %38
2243 %49 = OpLoad %6 %13
2244 %50 = OpFAdd %6 %49 %48
2245 OpStore %13 %50
2246 OpBranch %20
2247 %21 = OpLabel
2248 %51 = OpLoad %14 %16
2249 %53 = OpIAdd %14 %51 %52
2250 OpStore %16 %53
2251 OpBranch %18
2252 %20 = OpLabel
2253 %57 = OpLoad %6 %13
2254 %58 = OpCompositeConstruct %54 %57 %57 %57 %57
2255 OpStore %56 %58
2256 OpReturn
2257 OpFunctionEnd
2258 )";
2259 CheckEqual(env, expected, context.get());
2260 }
2261
TEST(StructuredLoopToSelectionReductionPassTest,DominanceAndPhiIssue)2262 TEST(StructuredLoopToSelectionReductionPassTest, DominanceAndPhiIssue) {
2263 // Exposes an interesting scenario where a use in a phi stops being dominated
2264 // by the block with which it is associated in the phi.
2265 std::string shader = R"(
2266 OpCapability Shader
2267 %1 = OpExtInstImport "GLSL.std.450"
2268 OpMemoryModel Logical GLSL450
2269 OpEntryPoint Fragment %4 "main"
2270 OpExecutionMode %4 OriginUpperLeft
2271 OpSource ESSL 310
2272 %2 = OpTypeVoid
2273 %3 = OpTypeFunction %2
2274 %17 = OpTypeBool
2275 %18 = OpConstantTrue %17
2276 %19 = OpConstantFalse %17
2277 %20 = OpTypeInt 32 1
2278 %21 = OpConstant %20 5
2279 %22 = OpConstant %20 6
2280 %4 = OpFunction %2 None %3
2281 %5 = OpLabel
2282 OpBranch %6
2283 %6 = OpLabel
2284 OpLoopMerge %16 %15 None
2285 OpBranch %7
2286 %7 = OpLabel
2287 OpSelectionMerge %13 None
2288 OpBranchConditional %18 %8 %9
2289 %8 = OpLabel
2290 OpSelectionMerge %12 None
2291 OpBranchConditional %18 %10 %11
2292 %9 = OpLabel
2293 OpBranch %16
2294 %10 = OpLabel
2295 OpBranch %16
2296 %11 = OpLabel
2297 %23 = OpIAdd %20 %21 %22
2298 OpBranch %12
2299 %12 = OpLabel
2300 OpBranch %13
2301 %13 = OpLabel
2302 OpBranch %14
2303 %14 = OpLabel
2304 %24 = OpPhi %20 %23 %13
2305 OpBranchConditional %19 %15 %16
2306 %15 = OpLabel
2307 OpBranch %6
2308 %16 = OpLabel
2309 OpReturn
2310 OpFunctionEnd
2311 )";
2312
2313 const auto env = SPV_ENV_UNIVERSAL_1_3;
2314 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2315 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2316 .GetAvailableOpportunities(context.get(), 0);
2317 ASSERT_EQ(1, ops.size());
2318
2319 ASSERT_TRUE(ops[0]->PreconditionHolds());
2320 ops[0]->TryToApply();
2321
2322 CheckValid(env, context.get());
2323
2324 std::string expected = R"(
2325 OpCapability Shader
2326 %1 = OpExtInstImport "GLSL.std.450"
2327 OpMemoryModel Logical GLSL450
2328 OpEntryPoint Fragment %4 "main"
2329 OpExecutionMode %4 OriginUpperLeft
2330 OpSource ESSL 310
2331 %2 = OpTypeVoid
2332 %3 = OpTypeFunction %2
2333 %17 = OpTypeBool
2334 %18 = OpConstantTrue %17
2335 %19 = OpConstantFalse %17
2336 %20 = OpTypeInt 32 1
2337 %21 = OpConstant %20 5
2338 %22 = OpConstant %20 6
2339 %25 = OpUndef %20
2340 %4 = OpFunction %2 None %3
2341 %5 = OpLabel
2342 OpBranch %6
2343 %6 = OpLabel
2344 OpSelectionMerge %16 None
2345 OpBranchConditional %18 %7 %16
2346 %7 = OpLabel
2347 OpSelectionMerge %13 None
2348 OpBranchConditional %18 %8 %9
2349 %8 = OpLabel
2350 OpSelectionMerge %12 None
2351 OpBranchConditional %18 %10 %11
2352 %9 = OpLabel
2353 OpBranch %13
2354 %10 = OpLabel
2355 OpBranch %12
2356 %11 = OpLabel
2357 %23 = OpIAdd %20 %21 %22
2358 OpBranch %12
2359 %12 = OpLabel
2360 OpBranch %13
2361 %13 = OpLabel
2362 OpBranch %14
2363 %14 = OpLabel
2364 %24 = OpPhi %20 %25 %13
2365 OpBranchConditional %19 %16 %16
2366 %15 = OpLabel
2367 OpBranch %6
2368 %16 = OpLabel
2369 OpReturn
2370 OpFunctionEnd
2371 )";
2372 CheckEqual(env, expected, context.get());
2373 }
2374
TEST(StructuredLoopToSelectionReductionPassTest,OpLineBeforeOpPhi)2375 TEST(StructuredLoopToSelectionReductionPassTest, OpLineBeforeOpPhi) {
2376 // Test to ensure the pass knows OpLine and OpPhi instructions can be
2377 // interleaved.
2378 std::string shader = R"(
2379 OpCapability Shader
2380 %1 = OpExtInstImport "GLSL.std.450"
2381 OpMemoryModel Logical GLSL450
2382 OpEntryPoint Fragment %2 "main"
2383 OpExecutionMode %2 OriginUpperLeft
2384 OpSource ESSL 310
2385 %3 = OpString "somefile"
2386 %4 = OpTypeVoid
2387 %5 = OpTypeFunction %4
2388 %6 = OpTypeInt 32 1
2389 %7 = OpConstant %6 10
2390 %8 = OpConstant %6 20
2391 %9 = OpConstant %6 30
2392 %10 = OpTypeBool
2393 %11 = OpConstantTrue %10
2394 %2 = OpFunction %4 None %5
2395 %12 = OpLabel
2396 OpBranch %13
2397 %13 = OpLabel
2398 OpLoopMerge %14 %15 None
2399 OpBranch %16
2400 %16 = OpLabel
2401 OpSelectionMerge %17 None
2402 OpBranchConditional %11 %18 %19
2403 %18 = OpLabel
2404 %20 = OpIAdd %6 %7 %8
2405 %21 = OpIAdd %6 %7 %9
2406 OpBranch %17
2407 %19 = OpLabel
2408 OpBranch %14
2409 %17 = OpLabel
2410 %22 = OpPhi %6 %20 %18
2411 OpLine %3 0 0
2412 %23 = OpPhi %6 %21 %18
2413 OpBranch %15
2414 %15 = OpLabel
2415 OpBranch %13
2416 %14 = OpLabel
2417 OpReturn
2418 OpFunctionEnd
2419 )";
2420
2421 const auto env = SPV_ENV_UNIVERSAL_1_3;
2422 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2423 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2424 .GetAvailableOpportunities(context.get(), 0);
2425 ASSERT_EQ(1, ops.size());
2426
2427 ASSERT_TRUE(ops[0]->PreconditionHolds());
2428 ops[0]->TryToApply();
2429
2430 CheckValid(env, context.get());
2431
2432 std::string expected = R"(
2433 OpCapability Shader
2434 %1 = OpExtInstImport "GLSL.std.450"
2435 OpMemoryModel Logical GLSL450
2436 OpEntryPoint Fragment %2 "main"
2437 OpExecutionMode %2 OriginUpperLeft
2438 OpSource ESSL 310
2439 %3 = OpString "somefile"
2440 %4 = OpTypeVoid
2441 %5 = OpTypeFunction %4
2442 %6 = OpTypeInt 32 1
2443 %7 = OpConstant %6 10
2444 %8 = OpConstant %6 20
2445 %9 = OpConstant %6 30
2446 %10 = OpTypeBool
2447 %11 = OpConstantTrue %10
2448 %24 = OpUndef %6
2449 %2 = OpFunction %4 None %5
2450 %12 = OpLabel
2451 OpBranch %13
2452 %13 = OpLabel
2453 OpSelectionMerge %14 None
2454 OpBranchConditional %11 %16 %14
2455 %16 = OpLabel
2456 OpSelectionMerge %17 None
2457 OpBranchConditional %11 %18 %19
2458 %18 = OpLabel
2459 %20 = OpIAdd %6 %7 %8
2460 %21 = OpIAdd %6 %7 %9
2461 OpBranch %17
2462 %19 = OpLabel
2463 OpBranch %17
2464 %17 = OpLabel
2465 %22 = OpPhi %6 %20 %18 %24 %19
2466 OpLine %3 0 0
2467 %23 = OpPhi %6 %21 %18 %24 %19
2468 OpBranch %14
2469 %15 = OpLabel
2470 OpBranch %13
2471 %14 = OpLabel
2472 OpReturn
2473 OpFunctionEnd
2474 )";
2475 CheckEqual(env, expected, context.get());
2476 }
2477
TEST(StructuredLoopToSelectionReductionPassTest,SelectionMergeIsContinueTarget)2478 TEST(StructuredLoopToSelectionReductionPassTest,
2479 SelectionMergeIsContinueTarget) {
2480 // Example where a loop's continue target is also the target of a selection.
2481 // In this scenario we cautiously do not apply the transformation.
2482 std::string shader = R"(
2483 OpCapability Shader
2484 OpMemoryModel Logical GLSL450
2485 OpEntryPoint Vertex %1 "main"
2486 %2 = OpTypeVoid
2487 %3 = OpTypeBool
2488 %4 = OpTypeFunction %2
2489 %1 = OpFunction %2 None %4
2490 %5 = OpLabel
2491 %6 = OpUndef %3
2492 OpBranch %7
2493 %7 = OpLabel
2494 %8 = OpPhi %3 %6 %5 %9 %10
2495 OpLoopMerge %11 %10 None
2496 OpBranch %12
2497 %12 = OpLabel
2498 %13 = OpUndef %3
2499 OpSelectionMerge %10 None
2500 OpBranchConditional %13 %14 %10
2501 %14 = OpLabel
2502 OpBranch %10
2503 %10 = OpLabel
2504 %9 = OpUndef %3
2505 OpBranchConditional %9 %7 %11
2506 %11 = OpLabel
2507 OpReturn
2508 OpFunctionEnd
2509 )";
2510
2511 const auto env = SPV_ENV_UNIVERSAL_1_3;
2512 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2513 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2514 .GetAvailableOpportunities(context.get(), 0);
2515
2516 // There should be no opportunities.
2517 ASSERT_EQ(0, ops.size());
2518 }
2519
TEST(StructuredLoopToSelectionReductionPassTest,SwitchSelectionMergeIsContinueTarget)2520 TEST(StructuredLoopToSelectionReductionPassTest,
2521 SwitchSelectionMergeIsContinueTarget) {
2522 // Another example where a loop's continue target is also the target of a
2523 // selection; this time a selection associated with an OpSwitch. We
2524 // cautiously do not apply the transformation.
2525 std::string shader = R"(
2526 OpCapability Shader
2527 OpMemoryModel Logical GLSL450
2528 OpEntryPoint Vertex %1 "main"
2529 %2 = OpTypeVoid
2530 %3 = OpTypeBool
2531 %5 = OpTypeInt 32 1
2532 %4 = OpTypeFunction %2
2533 %6 = OpConstant %5 2
2534 %7 = OpConstantTrue %3
2535 %1 = OpFunction %2 None %4
2536 %8 = OpLabel
2537 OpBranch %9
2538 %9 = OpLabel
2539 OpLoopMerge %14 %15 None
2540 OpBranchConditional %7 %10 %14
2541 %10 = OpLabel
2542 OpSelectionMerge %15 None
2543 OpSwitch %6 %12 1 %11 2 %11 3 %15
2544 %11 = OpLabel
2545 OpBranch %12
2546 %12 = OpLabel
2547 OpBranch %15
2548 %15 = OpLabel
2549 OpBranch %9
2550 %14 = OpLabel
2551 OpReturn
2552 OpFunctionEnd
2553 )";
2554
2555 const auto env = SPV_ENV_UNIVERSAL_1_3;
2556 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2557 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2558 .GetAvailableOpportunities(context.get(), 0);
2559
2560 // There should be no opportunities.
2561 ASSERT_EQ(0, ops.size());
2562 }
2563
TEST(StructuredLoopToSelectionReductionPassTest,ContinueTargetIsSwitchTarget)2564 TEST(StructuredLoopToSelectionReductionPassTest, ContinueTargetIsSwitchTarget) {
2565 std::string shader = R"(
2566 OpCapability Shader
2567 OpMemoryModel Logical GLSL450
2568 OpEntryPoint Vertex %1 "main"
2569 %2 = OpTypeVoid
2570 %3 = OpTypeBool
2571 %5 = OpTypeInt 32 1
2572 %4 = OpTypeFunction %2
2573 %6 = OpConstant %5 2
2574 %7 = OpConstantTrue %3
2575 %1 = OpFunction %2 None %4
2576 %8 = OpLabel
2577 OpBranch %9
2578 %9 = OpLabel
2579 OpLoopMerge %14 %12 None
2580 OpBranchConditional %7 %10 %14
2581 %10 = OpLabel
2582 OpSelectionMerge %15 None
2583 OpSwitch %6 %12 1 %11 2 %11 3 %15
2584 %11 = OpLabel
2585 OpBranch %12
2586 %12 = OpLabel
2587 OpBranch %9
2588 %15 = OpLabel
2589 OpBranch %14
2590 %14 = OpLabel
2591 OpReturn
2592 OpFunctionEnd
2593 )";
2594
2595 const auto env = SPV_ENV_UNIVERSAL_1_3;
2596 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2597 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2598 .GetAvailableOpportunities(context.get(), 0);
2599
2600 ASSERT_EQ(1, ops.size());
2601 ASSERT_TRUE(ops[0]->PreconditionHolds());
2602 ops[0]->TryToApply();
2603
2604 CheckValid(env, context.get());
2605
2606 std::string expected = R"(
2607 OpCapability Shader
2608 OpMemoryModel Logical GLSL450
2609 OpEntryPoint Vertex %1 "main"
2610 %2 = OpTypeVoid
2611 %3 = OpTypeBool
2612 %5 = OpTypeInt 32 1
2613 %4 = OpTypeFunction %2
2614 %6 = OpConstant %5 2
2615 %7 = OpConstantTrue %3
2616 %1 = OpFunction %2 None %4
2617 %8 = OpLabel
2618 OpBranch %9
2619 %9 = OpLabel
2620 OpSelectionMerge %14 None
2621 OpBranchConditional %7 %10 %14
2622 %10 = OpLabel
2623 OpSelectionMerge %15 None
2624 OpSwitch %6 %15 1 %11 2 %11 3 %15
2625 %11 = OpLabel
2626 OpBranch %15
2627 %12 = OpLabel
2628 OpBranch %9
2629 %15 = OpLabel
2630 OpBranch %14
2631 %14 = OpLabel
2632 OpReturn
2633 OpFunctionEnd
2634 )";
2635 CheckEqual(env, expected, context.get());
2636 }
2637
TEST(StructuredLoopToSelectionReductionPassTest,MultipleSwitchTargetsAreContinueTarget)2638 TEST(StructuredLoopToSelectionReductionPassTest,
2639 MultipleSwitchTargetsAreContinueTarget) {
2640 std::string shader = R"(
2641 OpCapability Shader
2642 OpMemoryModel Logical GLSL450
2643 OpEntryPoint Vertex %1 "main"
2644 %2 = OpTypeVoid
2645 %3 = OpTypeBool
2646 %5 = OpTypeInt 32 1
2647 %4 = OpTypeFunction %2
2648 %6 = OpConstant %5 2
2649 %7 = OpConstantTrue %3
2650 %1 = OpFunction %2 None %4
2651 %8 = OpLabel
2652 OpBranch %9
2653 %9 = OpLabel
2654 OpLoopMerge %14 %12 None
2655 OpBranchConditional %7 %10 %14
2656 %10 = OpLabel
2657 OpSelectionMerge %15 None
2658 OpSwitch %6 %11 1 %12 2 %12 3 %15
2659 %11 = OpLabel
2660 OpBranch %12
2661 %12 = OpLabel
2662 OpBranch %9
2663 %15 = OpLabel
2664 OpBranch %14
2665 %14 = OpLabel
2666 OpReturn
2667 OpFunctionEnd
2668 )";
2669
2670 const auto env = SPV_ENV_UNIVERSAL_1_3;
2671 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2672 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2673 .GetAvailableOpportunities(context.get(), 0);
2674
2675 ASSERT_EQ(1, ops.size());
2676 ASSERT_TRUE(ops[0]->PreconditionHolds());
2677 ops[0]->TryToApply();
2678
2679 CheckValid(env, context.get());
2680
2681 std::string expected = R"(
2682 OpCapability Shader
2683 OpMemoryModel Logical GLSL450
2684 OpEntryPoint Vertex %1 "main"
2685 %2 = OpTypeVoid
2686 %3 = OpTypeBool
2687 %5 = OpTypeInt 32 1
2688 %4 = OpTypeFunction %2
2689 %6 = OpConstant %5 2
2690 %7 = OpConstantTrue %3
2691 %1 = OpFunction %2 None %4
2692 %8 = OpLabel
2693 OpBranch %9
2694 %9 = OpLabel
2695 OpSelectionMerge %14 None
2696 OpBranchConditional %7 %10 %14
2697 %10 = OpLabel
2698 OpSelectionMerge %15 None
2699 OpSwitch %6 %11 1 %15 2 %15 3 %15
2700 %11 = OpLabel
2701 OpBranch %15
2702 %12 = OpLabel
2703 OpBranch %9
2704 %15 = OpLabel
2705 OpBranch %14
2706 %14 = OpLabel
2707 OpReturn
2708 OpFunctionEnd
2709 )";
2710 CheckEqual(env, expected, context.get());
2711 }
2712
TEST(StructuredLoopToSelectionReductionPassTest,LoopBranchesStraightToMerge)2713 TEST(StructuredLoopToSelectionReductionPassTest, LoopBranchesStraightToMerge) {
2714 std::string shader = R"(
2715 OpCapability Shader
2716 OpMemoryModel Logical GLSL450
2717 OpEntryPoint Vertex %1 "main"
2718 %2 = OpTypeVoid
2719 %4 = OpTypeFunction %2
2720 %1 = OpFunction %2 None %4
2721 %8 = OpLabel
2722 OpBranch %9
2723 %9 = OpLabel
2724 OpLoopMerge %14 %12 None
2725 OpBranch %14
2726 %12 = OpLabel
2727 OpBranch %9
2728 %14 = OpLabel
2729 OpReturn
2730 OpFunctionEnd
2731 )";
2732
2733 const auto env = SPV_ENV_UNIVERSAL_1_3;
2734 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2735 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2736 .GetAvailableOpportunities(context.get(), 0);
2737
2738 ASSERT_EQ(1, ops.size());
2739 ASSERT_TRUE(ops[0]->PreconditionHolds());
2740 ops[0]->TryToApply();
2741
2742 CheckValid(env, context.get());
2743
2744 std::string expected = R"(
2745 OpCapability Shader
2746 OpMemoryModel Logical GLSL450
2747 OpEntryPoint Vertex %1 "main"
2748 %2 = OpTypeVoid
2749 %4 = OpTypeFunction %2
2750 %15 = OpTypeBool
2751 %16 = OpConstantTrue %15
2752 %1 = OpFunction %2 None %4
2753 %8 = OpLabel
2754 OpBranch %9
2755 %9 = OpLabel
2756 OpSelectionMerge %14 None
2757 OpBranchConditional %16 %14 %14
2758 %12 = OpLabel
2759 OpBranch %9
2760 %14 = OpLabel
2761 OpReturn
2762 OpFunctionEnd
2763 )";
2764 CheckEqual(env, expected, context.get());
2765 }
2766
TEST(StructuredLoopToSelectionReductionPassTest,LoopConditionallyJumpsToMergeOrContinue)2767 TEST(StructuredLoopToSelectionReductionPassTest,
2768 LoopConditionallyJumpsToMergeOrContinue) {
2769 std::string shader = R"(
2770 OpCapability Shader
2771 OpMemoryModel Logical GLSL450
2772 OpEntryPoint Vertex %1 "main"
2773 %2 = OpTypeVoid
2774 %3 = OpTypeBool
2775 %4 = OpTypeFunction %2
2776 %7 = OpConstantTrue %3
2777 %1 = OpFunction %2 None %4
2778 %8 = OpLabel
2779 OpBranch %9
2780 %9 = OpLabel
2781 OpLoopMerge %14 %12 None
2782 OpBranchConditional %7 %14 %12
2783 %12 = OpLabel
2784 OpBranch %9
2785 %14 = OpLabel
2786 OpReturn
2787 OpFunctionEnd
2788 )";
2789
2790 const auto env = SPV_ENV_UNIVERSAL_1_3;
2791 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2792 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2793 .GetAvailableOpportunities(context.get(), 0);
2794
2795 ASSERT_EQ(1, ops.size());
2796 ASSERT_TRUE(ops[0]->PreconditionHolds());
2797 ops[0]->TryToApply();
2798
2799 CheckValid(env, context.get());
2800
2801 std::string expected = R"(
2802 OpCapability Shader
2803 OpMemoryModel Logical GLSL450
2804 OpEntryPoint Vertex %1 "main"
2805 %2 = OpTypeVoid
2806 %3 = OpTypeBool
2807 %4 = OpTypeFunction %2
2808 %7 = OpConstantTrue %3
2809 %1 = OpFunction %2 None %4
2810 %8 = OpLabel
2811 OpBranch %9
2812 %9 = OpLabel
2813 OpSelectionMerge %14 None
2814 OpBranchConditional %7 %14 %14
2815 %12 = OpLabel
2816 OpBranch %9
2817 %14 = OpLabel
2818 OpReturn
2819 OpFunctionEnd
2820 )";
2821 CheckEqual(env, expected, context.get());
2822 }
2823
TEST(StructuredLoopToSelectionReductionPassTest,MultipleAccessChains)2824 TEST(StructuredLoopToSelectionReductionPassTest, MultipleAccessChains) {
2825 std::string shader = R"(
2826 OpCapability Shader
2827 %1 = OpExtInstImport "GLSL.std.450"
2828 OpMemoryModel Logical GLSL450
2829 OpEntryPoint Fragment %4 "main"
2830 OpExecutionMode %4 OriginUpperLeft
2831 OpSource ESSL 310
2832 %2 = OpTypeVoid
2833 %3 = OpTypeFunction %2
2834 %6 = OpTypeInt 32 1
2835 %7 = OpTypeStruct %6
2836 %8 = OpTypeStruct %7
2837 %9 = OpTypePointer Function %8
2838 %11 = OpConstant %6 3
2839 %12 = OpConstantComposite %7 %11
2840 %13 = OpConstantComposite %8 %12
2841 %14 = OpTypePointer Function %7
2842 %16 = OpConstant %6 0
2843 %19 = OpTypePointer Function %6
2844 %15 = OpTypeBool
2845 %18 = OpConstantTrue %15
2846 %4 = OpFunction %2 None %3
2847 %5 = OpLabel
2848 %10 = OpVariable %9 Function
2849 %20 = OpVariable %19 Function
2850 OpStore %10 %13
2851 OpBranch %23
2852 %23 = OpLabel
2853 OpLoopMerge %25 %26 None
2854 OpBranch %27
2855 %27 = OpLabel
2856 OpSelectionMerge %28 None
2857 OpBranchConditional %18 %29 %25
2858 %29 = OpLabel
2859 %17 = OpAccessChain %14 %10 %16
2860 OpBranch %28
2861 %28 = OpLabel
2862 %21 = OpAccessChain %19 %17 %16
2863 %22 = OpLoad %6 %21
2864 %24 = OpAccessChain %19 %10 %16 %16
2865 OpStore %24 %22
2866 OpBranch %25
2867 %26 = OpLabel
2868 OpBranch %23
2869 %25 = OpLabel
2870 OpReturn
2871 OpFunctionEnd
2872 )";
2873
2874 const auto env = SPV_ENV_UNIVERSAL_1_3;
2875 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2876 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2877 .GetAvailableOpportunities(context.get(), 0);
2878
2879 ASSERT_EQ(1, ops.size());
2880 ASSERT_TRUE(ops[0]->PreconditionHolds());
2881 ops[0]->TryToApply();
2882
2883 CheckValid(env, context.get());
2884
2885 std::string expected = R"(
2886 OpCapability Shader
2887 %1 = OpExtInstImport "GLSL.std.450"
2888 OpMemoryModel Logical GLSL450
2889 OpEntryPoint Fragment %4 "main"
2890 OpExecutionMode %4 OriginUpperLeft
2891 OpSource ESSL 310
2892 %2 = OpTypeVoid
2893 %3 = OpTypeFunction %2
2894 %6 = OpTypeInt 32 1
2895 %7 = OpTypeStruct %6
2896 %8 = OpTypeStruct %7
2897 %9 = OpTypePointer Function %8
2898 %11 = OpConstant %6 3
2899 %12 = OpConstantComposite %7 %11
2900 %13 = OpConstantComposite %8 %12
2901 %14 = OpTypePointer Function %7
2902 %16 = OpConstant %6 0
2903 %19 = OpTypePointer Function %6
2904 %15 = OpTypeBool
2905 %18 = OpConstantTrue %15
2906 %4 = OpFunction %2 None %3
2907 %5 = OpLabel
2908 %10 = OpVariable %9 Function
2909 %20 = OpVariable %19 Function
2910 %30 = OpVariable %14 Function
2911 OpStore %10 %13
2912 OpBranch %23
2913 %23 = OpLabel
2914 OpSelectionMerge %25 None
2915 OpBranchConditional %18 %27 %25
2916 %27 = OpLabel
2917 OpSelectionMerge %28 None
2918 OpBranchConditional %18 %29 %28
2919 %29 = OpLabel
2920 %17 = OpAccessChain %14 %10 %16
2921 OpBranch %28
2922 %28 = OpLabel
2923 %21 = OpAccessChain %19 %30 %16
2924 %22 = OpLoad %6 %21
2925 %24 = OpAccessChain %19 %10 %16 %16
2926 OpStore %24 %22
2927 OpBranch %25
2928 %26 = OpLabel
2929 OpBranch %23
2930 %25 = OpLabel
2931 OpReturn
2932 OpFunctionEnd
2933 )";
2934 CheckEqual(env, expected, context.get());
2935 }
2936
TEST(StructuredLoopToSelectionReductionPassTest,UnreachableInnerLoopContinueBranchingToOuterLoopMerge)2937 TEST(StructuredLoopToSelectionReductionPassTest,
2938 UnreachableInnerLoopContinueBranchingToOuterLoopMerge) {
2939 std::string shader = R"(
2940 OpCapability Shader
2941 %1 = OpExtInstImport "GLSL.std.450"
2942 OpMemoryModel Logical GLSL450
2943 OpEntryPoint Fragment %2 "main"
2944 OpExecutionMode %2 OriginUpperLeft
2945 OpSource ESSL 310
2946 %3 = OpTypeVoid
2947 %4 = OpTypeFunction %3
2948 %5 = OpTypeBool
2949 %6 = OpConstantTrue %5
2950 %2 = OpFunction %3 None %4
2951 %7 = OpLabel
2952 OpBranch %8
2953 %8 = OpLabel
2954 OpLoopMerge %9 %10 None
2955 OpBranch %11
2956 %11 = OpLabel
2957 OpLoopMerge %12 %13 None
2958 OpBranch %12
2959 %13 = OpLabel
2960 OpBranchConditional %6 %9 %11
2961 %12 = OpLabel
2962 OpBranch %10
2963 %10 = OpLabel
2964 OpBranchConditional %6 %9 %8
2965 %9 = OpLabel
2966 OpReturn
2967 OpFunctionEnd
2968 )";
2969
2970 const auto env = SPV_ENV_UNIVERSAL_1_3;
2971 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
2972 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
2973 .GetAvailableOpportunities(context.get(), 0);
2974
2975 ASSERT_EQ(2, ops.size());
2976 ASSERT_TRUE(ops[0]->PreconditionHolds());
2977 ops[0]->TryToApply();
2978
2979 CheckValid(env, context.get());
2980
2981 std::string after_op_0 = R"(
2982 OpCapability Shader
2983 %1 = OpExtInstImport "GLSL.std.450"
2984 OpMemoryModel Logical GLSL450
2985 OpEntryPoint Fragment %2 "main"
2986 OpExecutionMode %2 OriginUpperLeft
2987 OpSource ESSL 310
2988 %3 = OpTypeVoid
2989 %4 = OpTypeFunction %3
2990 %5 = OpTypeBool
2991 %6 = OpConstantTrue %5
2992 %2 = OpFunction %3 None %4
2993 %7 = OpLabel
2994 OpBranch %8
2995 %8 = OpLabel
2996 OpSelectionMerge %9 None
2997 OpBranchConditional %6 %11 %9
2998 %11 = OpLabel
2999 OpLoopMerge %12 %13 None
3000 OpBranch %12
3001 %13 = OpLabel
3002 OpBranchConditional %6 %9 %11
3003 %12 = OpLabel
3004 OpBranch %9
3005 %10 = OpLabel
3006 OpBranchConditional %6 %9 %8
3007 %9 = OpLabel
3008 OpReturn
3009 OpFunctionEnd
3010 )";
3011 CheckEqual(env, after_op_0, context.get());
3012
3013 ASSERT_TRUE(ops[1]->PreconditionHolds());
3014 ops[1]->TryToApply();
3015
3016 CheckValid(env, context.get());
3017
3018 std::string after_op_1 = R"(
3019 OpCapability Shader
3020 %1 = OpExtInstImport "GLSL.std.450"
3021 OpMemoryModel Logical GLSL450
3022 OpEntryPoint Fragment %2 "main"
3023 OpExecutionMode %2 OriginUpperLeft
3024 OpSource ESSL 310
3025 %3 = OpTypeVoid
3026 %4 = OpTypeFunction %3
3027 %5 = OpTypeBool
3028 %6 = OpConstantTrue %5
3029 %2 = OpFunction %3 None %4
3030 %7 = OpLabel
3031 OpBranch %8
3032 %8 = OpLabel
3033 OpSelectionMerge %9 None
3034 OpBranchConditional %6 %11 %9
3035 %11 = OpLabel
3036 OpSelectionMerge %12 None
3037 OpBranchConditional %6 %12 %12
3038 %13 = OpLabel
3039 OpBranchConditional %6 %9 %11
3040 %12 = OpLabel
3041 OpBranch %9
3042 %10 = OpLabel
3043 OpBranchConditional %6 %9 %8
3044 %9 = OpLabel
3045 OpReturn
3046 OpFunctionEnd
3047 )";
3048 CheckEqual(env, after_op_1, context.get());
3049 }
3050
TEST(StructuredLoopToSelectionReductionPassTest,UnreachableInnerLoopContinueBranchingToOuterLoopMerge2)3051 TEST(StructuredLoopToSelectionReductionPassTest,
3052 UnreachableInnerLoopContinueBranchingToOuterLoopMerge2) {
3053 // In this test, the branch to the outer loop merge from the inner loop's
3054 // continue is part of a structured selection.
3055 std::string shader = R"(
3056 OpCapability Shader
3057 %1 = OpExtInstImport "GLSL.std.450"
3058 OpMemoryModel Logical GLSL450
3059 OpEntryPoint Fragment %2 "main"
3060 OpExecutionMode %2 OriginUpperLeft
3061 OpSource ESSL 310
3062 %3 = OpTypeVoid
3063 %4 = OpTypeFunction %3
3064 %5 = OpTypeBool
3065 %6 = OpConstantTrue %5
3066 %2 = OpFunction %3 None %4
3067 %7 = OpLabel
3068 OpBranch %8
3069 %8 = OpLabel
3070 OpLoopMerge %9 %10 None
3071 OpBranch %11
3072 %11 = OpLabel
3073 OpLoopMerge %12 %13 None
3074 OpBranch %12
3075 %13 = OpLabel
3076 OpSelectionMerge %14 None
3077 OpBranchConditional %6 %9 %14
3078 %14 = OpLabel
3079 OpBranch %11
3080 %12 = OpLabel
3081 OpBranch %10
3082 %10 = OpLabel
3083 OpBranchConditional %6 %9 %8
3084 %9 = OpLabel
3085 OpReturn
3086 OpFunctionEnd
3087 )";
3088
3089 const auto env = SPV_ENV_UNIVERSAL_1_3;
3090 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3091 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3092 .GetAvailableOpportunities(context.get(), 0);
3093
3094 ASSERT_EQ(2, ops.size());
3095 ASSERT_TRUE(ops[0]->PreconditionHolds());
3096 ops[0]->TryToApply();
3097
3098 CheckValid(env, context.get());
3099
3100 std::string after_op_0 = R"(
3101 OpCapability Shader
3102 %1 = OpExtInstImport "GLSL.std.450"
3103 OpMemoryModel Logical GLSL450
3104 OpEntryPoint Fragment %2 "main"
3105 OpExecutionMode %2 OriginUpperLeft
3106 OpSource ESSL 310
3107 %3 = OpTypeVoid
3108 %4 = OpTypeFunction %3
3109 %5 = OpTypeBool
3110 %6 = OpConstantTrue %5
3111 %2 = OpFunction %3 None %4
3112 %7 = OpLabel
3113 OpBranch %8
3114 %8 = OpLabel
3115 OpSelectionMerge %9 None
3116 OpBranchConditional %6 %11 %9
3117 %11 = OpLabel
3118 OpLoopMerge %12 %13 None
3119 OpBranch %12
3120 %13 = OpLabel
3121 OpSelectionMerge %14 None
3122 OpBranchConditional %6 %9 %14
3123 %14 = OpLabel
3124 OpBranch %11
3125 %12 = OpLabel
3126 OpBranch %9
3127 %10 = OpLabel
3128 OpBranchConditional %6 %9 %8
3129 %9 = OpLabel
3130 OpReturn
3131 OpFunctionEnd
3132 )";
3133 CheckEqual(env, after_op_0, context.get());
3134
3135 ASSERT_TRUE(ops[1]->PreconditionHolds());
3136 ops[1]->TryToApply();
3137
3138 CheckValid(env, context.get());
3139
3140 std::string after_op_1 = R"(
3141 OpCapability Shader
3142 %1 = OpExtInstImport "GLSL.std.450"
3143 OpMemoryModel Logical GLSL450
3144 OpEntryPoint Fragment %2 "main"
3145 OpExecutionMode %2 OriginUpperLeft
3146 OpSource ESSL 310
3147 %3 = OpTypeVoid
3148 %4 = OpTypeFunction %3
3149 %5 = OpTypeBool
3150 %6 = OpConstantTrue %5
3151 %2 = OpFunction %3 None %4
3152 %7 = OpLabel
3153 OpBranch %8
3154 %8 = OpLabel
3155 OpSelectionMerge %9 None
3156 OpBranchConditional %6 %11 %9
3157 %11 = OpLabel
3158 OpSelectionMerge %12 None
3159 OpBranchConditional %6 %12 %12
3160 %13 = OpLabel
3161 OpSelectionMerge %14 None
3162 OpBranchConditional %6 %9 %14
3163 %14 = OpLabel
3164 OpBranch %11
3165 %12 = OpLabel
3166 OpBranch %9
3167 %10 = OpLabel
3168 OpBranchConditional %6 %9 %8
3169 %9 = OpLabel
3170 OpReturn
3171 OpFunctionEnd
3172 )";
3173 CheckEqual(env, after_op_1, context.get());
3174 }
3175
TEST(StructuredLoopToSelectionReductionPassTest,InnerLoopHeaderBranchesToOuterLoopMerge)3176 TEST(StructuredLoopToSelectionReductionPassTest,
3177 InnerLoopHeaderBranchesToOuterLoopMerge) {
3178 std::string shader = R"(
3179 OpCapability Shader
3180 %1 = OpExtInstImport "GLSL.std.450"
3181 OpMemoryModel Logical GLSL450
3182 OpEntryPoint Fragment %2 "main"
3183 OpExecutionMode %2 OriginUpperLeft
3184 OpSource ESSL 310
3185 %3 = OpTypeVoid
3186 %4 = OpTypeFunction %3
3187 %5 = OpTypeBool
3188 %6 = OpConstantTrue %5
3189 %2 = OpFunction %3 None %4
3190 %7 = OpLabel
3191 OpBranch %8
3192 %8 = OpLabel
3193 OpLoopMerge %9 %10 None
3194 OpBranch %11
3195 %11 = OpLabel
3196 OpLoopMerge %12 %13 None
3197 OpBranchConditional %6 %9 %13
3198 %13 = OpLabel
3199 OpBranchConditional %6 %11 %12
3200 %12 = OpLabel
3201 OpBranch %10
3202 %10 = OpLabel
3203 OpBranchConditional %6 %9 %8
3204 %9 = OpLabel
3205 OpReturn
3206 OpFunctionEnd
3207 )";
3208
3209 const auto env = SPV_ENV_UNIVERSAL_1_3;
3210 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3211 auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3212 .GetAvailableOpportunities(context.get(), 0);
3213
3214 // We cannot transform the inner loop due to its header jumping straight to
3215 // the outer loop merge (the inner loop's merge does not post-dominate its
3216 // header).
3217 ASSERT_EQ(1, ops.size());
3218 ASSERT_TRUE(ops[0]->PreconditionHolds());
3219 ops[0]->TryToApply();
3220
3221 CheckValid(env, context.get());
3222
3223 std::string after_op_0 = R"(
3224 OpCapability Shader
3225 %1 = OpExtInstImport "GLSL.std.450"
3226 OpMemoryModel Logical GLSL450
3227 OpEntryPoint Fragment %2 "main"
3228 OpExecutionMode %2 OriginUpperLeft
3229 OpSource ESSL 310
3230 %3 = OpTypeVoid
3231 %4 = OpTypeFunction %3
3232 %5 = OpTypeBool
3233 %6 = OpConstantTrue %5
3234 %2 = OpFunction %3 None %4
3235 %7 = OpLabel
3236 OpBranch %8
3237 %8 = OpLabel
3238 OpSelectionMerge %9 None
3239 OpBranchConditional %6 %11 %9
3240 %11 = OpLabel
3241 OpLoopMerge %12 %13 None
3242 OpBranchConditional %6 %12 %13
3243 %13 = OpLabel
3244 OpBranchConditional %6 %11 %12
3245 %12 = OpLabel
3246 OpBranch %9
3247 %10 = OpLabel
3248 OpBranchConditional %6 %9 %8
3249 %9 = OpLabel
3250 OpReturn
3251 OpFunctionEnd
3252 )";
3253 CheckEqual(env, after_op_0, context.get());
3254
3255 // Now look again for more opportunities.
3256 ops = StructuredLoopToSelectionReductionOpportunityFinder()
3257 .GetAvailableOpportunities(context.get(), 0);
3258
3259 // What was the inner loop should now be transformable, as the jump to the
3260 // outer loop's merge has been redirected.
3261 ASSERT_EQ(1, ops.size());
3262 ASSERT_TRUE(ops[0]->PreconditionHolds());
3263 ops[0]->TryToApply();
3264
3265 CheckValid(env, context.get());
3266
3267 std::string after_another_op_0 = R"(
3268 OpCapability Shader
3269 %1 = OpExtInstImport "GLSL.std.450"
3270 OpMemoryModel Logical GLSL450
3271 OpEntryPoint Fragment %2 "main"
3272 OpExecutionMode %2 OriginUpperLeft
3273 OpSource ESSL 310
3274 %3 = OpTypeVoid
3275 %4 = OpTypeFunction %3
3276 %5 = OpTypeBool
3277 %6 = OpConstantTrue %5
3278 %2 = OpFunction %3 None %4
3279 %7 = OpLabel
3280 OpBranch %8
3281 %8 = OpLabel
3282 OpSelectionMerge %9 None
3283 OpBranchConditional %6 %11 %9
3284 %11 = OpLabel
3285 OpSelectionMerge %12 None
3286 OpBranchConditional %6 %12 %12
3287 %13 = OpLabel
3288 OpBranchConditional %6 %11 %12
3289 %12 = OpLabel
3290 OpBranch %9
3291 %10 = OpLabel
3292 OpBranchConditional %6 %9 %8
3293 %9 = OpLabel
3294 OpReturn
3295 OpFunctionEnd
3296 )";
3297 CheckEqual(env, after_another_op_0, context.get());
3298 }
3299
TEST(StructuredLoopToSelectionReductionPassTest,LongAccessChains)3300 TEST(StructuredLoopToSelectionReductionPassTest, LongAccessChains) {
3301 std::string shader = R"(
3302 OpCapability Shader
3303 %1 = OpExtInstImport "GLSL.std.450"
3304 OpMemoryModel Logical GLSL450
3305 OpEntryPoint Fragment %2 "main"
3306 OpExecutionMode %2 OriginUpperLeft
3307 OpSource ESSL 310
3308 %3 = OpTypeVoid
3309 %4 = OpTypeFunction %3
3310 %5 = OpTypeInt 32 1
3311 %6 = OpTypeInt 32 0
3312 %7 = OpConstant %6 5
3313 %8 = OpTypeArray %5 %7
3314 %9 = OpTypeStruct %8
3315 %10 = OpTypeStruct %9 %9
3316 %11 = OpConstant %6 2
3317 %12 = OpTypeArray %10 %11
3318 %13 = OpTypeStruct %12
3319 %14 = OpTypePointer Function %13
3320 %15 = OpConstant %5 0
3321 %16 = OpConstant %5 1
3322 %17 = OpConstant %5 2
3323 %18 = OpConstant %5 3
3324 %19 = OpConstant %5 4
3325 %20 = OpConstantComposite %8 %15 %16 %17 %18 %19
3326 %21 = OpConstantComposite %9 %20
3327 %22 = OpConstant %5 5
3328 %23 = OpConstant %5 6
3329 %24 = OpConstant %5 7
3330 %25 = OpConstant %5 8
3331 %26 = OpConstant %5 9
3332 %27 = OpConstantComposite %8 %22 %23 %24 %25 %26
3333 %28 = OpConstantComposite %9 %27
3334 %29 = OpConstantComposite %10 %21 %28
3335 %30 = OpConstant %5 10
3336 %31 = OpConstant %5 11
3337 %32 = OpConstant %5 12
3338 %33 = OpConstant %5 13
3339 %34 = OpConstant %5 14
3340 %35 = OpConstantComposite %8 %30 %31 %32 %33 %34
3341 %36 = OpConstantComposite %9 %35
3342 %37 = OpConstant %5 15
3343 %38 = OpConstant %5 16
3344 %39 = OpConstant %5 17
3345 %40 = OpConstant %5 18
3346 %41 = OpConstant %5 19
3347 %42 = OpConstantComposite %8 %37 %38 %39 %40 %41
3348 %43 = OpConstantComposite %9 %42
3349 %44 = OpConstantComposite %10 %36 %43
3350 %45 = OpConstantComposite %12 %29 %44
3351 %46 = OpConstantComposite %13 %45
3352 %47 = OpTypePointer Function %12
3353 %48 = OpTypePointer Function %10
3354 %49 = OpTypePointer Function %9
3355 %50 = OpTypePointer Function %8
3356 %51 = OpTypePointer Function %5
3357 %52 = OpTypeBool
3358 %53 = OpConstantTrue %52
3359 %2 = OpFunction %3 None %4
3360 %54 = OpLabel
3361 %55 = OpVariable %14 Function
3362 OpStore %55 %46
3363 OpBranch %56
3364 %56 = OpLabel
3365 OpLoopMerge %57 %58 None
3366 OpBranchConditional %53 %57 %59
3367 %59 = OpLabel
3368 OpSelectionMerge %60 None
3369 OpBranchConditional %53 %61 %57
3370 %61 = OpLabel
3371 %62 = OpAccessChain %47 %55 %15
3372 OpBranch %63
3373 %63 = OpLabel
3374 OpSelectionMerge %64 None
3375 OpBranchConditional %53 %65 %57
3376 %65 = OpLabel
3377 %66 = OpAccessChain %48 %62 %16
3378 OpBranch %67
3379 %67 = OpLabel
3380 OpSelectionMerge %68 None
3381 OpBranchConditional %53 %69 %57
3382 %69 = OpLabel
3383 %70 = OpAccessChain %49 %66 %16
3384 OpBranch %71
3385 %71 = OpLabel
3386 OpSelectionMerge %72 None
3387 OpBranchConditional %53 %73 %57
3388 %73 = OpLabel
3389 %74 = OpAccessChain %50 %70 %15
3390 OpBranch %75
3391 %75 = OpLabel
3392 OpSelectionMerge %76 None
3393 OpBranchConditional %53 %77 %57
3394 %77 = OpLabel
3395 %78 = OpAccessChain %51 %74 %17
3396 OpBranch %79
3397 %79 = OpLabel
3398 OpSelectionMerge %80 None
3399 OpBranchConditional %53 %81 %57
3400 %81 = OpLabel
3401 %82 = OpLoad %5 %78
3402 OpBranch %80
3403 %80 = OpLabel
3404 OpBranch %76
3405 %76 = OpLabel
3406 OpBranch %72
3407 %72 = OpLabel
3408 OpBranch %68
3409 %68 = OpLabel
3410 OpBranch %64
3411 %64 = OpLabel
3412 OpBranch %60
3413 %60 = OpLabel
3414 OpBranch %58
3415 %58 = OpLabel
3416 OpBranch %56
3417 %57 = OpLabel
3418 OpReturn
3419 OpFunctionEnd
3420 )";
3421
3422 const auto env = SPV_ENV_UNIVERSAL_1_3;
3423 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3424 auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3425 .GetAvailableOpportunities(context.get(), 0);
3426
3427 ASSERT_EQ(1, ops.size());
3428 ASSERT_TRUE(ops[0]->PreconditionHolds());
3429 ops[0]->TryToApply();
3430
3431 CheckValid(env, context.get());
3432
3433 // TODO(2183): When we have a more general solution for handling access
3434 // chains, write an expected result for this test.
3435 // std::string expected = R"(
3436 // Expected text for transformed shader
3437 //)";
3438 // CheckEqual(env, expected, context.get());
3439 }
3440
TEST(StructuredLoopToSelectionReductionPassTest,LoopyShaderWithOpDecorate)3441 TEST(StructuredLoopToSelectionReductionPassTest, LoopyShaderWithOpDecorate) {
3442 // A shader containing a function that contains a loop and some definitions
3443 // that are "used" in OpDecorate instructions (outside the function). These
3444 // "uses" were causing segfaults because we try to calculate their dominance
3445 // information, which doesn't make sense.
3446
3447 std::string shader = R"(
3448 OpCapability Shader
3449 %1 = OpExtInstImport "GLSL.std.450"
3450 OpMemoryModel Logical GLSL450
3451 OpEntryPoint Fragment %4 "main" %9
3452 OpExecutionMode %4 OriginUpperLeft
3453 OpSource ESSL 310
3454 OpName %4 "main"
3455 OpName %9 "_GLF_color"
3456 OpName %14 "buf0"
3457 OpMemberName %14 0 "a"
3458 OpName %16 ""
3459 OpDecorate %9 RelaxedPrecision
3460 OpDecorate %9 Location 0
3461 OpMemberDecorate %14 0 RelaxedPrecision
3462 OpMemberDecorate %14 0 Offset 0
3463 OpDecorate %14 Block
3464 OpDecorate %16 DescriptorSet 0
3465 OpDecorate %16 Binding 0
3466 OpDecorate %21 RelaxedPrecision
3467 OpDecorate %35 RelaxedPrecision
3468 OpDecorate %36 RelaxedPrecision
3469 OpDecorate %39 RelaxedPrecision
3470 OpDecorate %40 RelaxedPrecision
3471 %2 = OpTypeVoid
3472 %3 = OpTypeFunction %2
3473 %6 = OpTypeFloat 32
3474 %7 = OpTypeVector %6 4
3475 %8 = OpTypePointer Output %7
3476 %9 = OpVariable %8 Output
3477 %10 = OpConstant %6 1
3478 %11 = OpConstantComposite %7 %10 %10 %10 %10
3479 %14 = OpTypeStruct %6
3480 %15 = OpTypePointer Uniform %14
3481 %16 = OpVariable %15 Uniform
3482 %17 = OpTypeInt 32 1
3483 %18 = OpConstant %17 0
3484 %19 = OpTypePointer Uniform %6
3485 %28 = OpConstant %6 2
3486 %29 = OpTypeBool
3487 %31 = OpTypeInt 32 0
3488 %32 = OpConstant %31 0
3489 %33 = OpTypePointer Output %6
3490 %4 = OpFunction %2 None %3
3491 %5 = OpLabel
3492 OpStore %9 %11
3493 %20 = OpAccessChain %19 %16 %18
3494 %21 = OpLoad %6 %20
3495 OpBranch %22
3496 %22 = OpLabel
3497 %40 = OpPhi %6 %21 %5 %39 %23
3498 %30 = OpFOrdLessThan %29 %40 %28
3499 OpLoopMerge %24 %23 None
3500 OpBranchConditional %30 %23 %24
3501 %23 = OpLabel
3502 %34 = OpAccessChain %33 %9 %32
3503 %35 = OpLoad %6 %34
3504 %36 = OpFAdd %6 %35 %10
3505 OpStore %34 %36
3506 %39 = OpFAdd %6 %40 %10
3507 OpBranch %22
3508 %24 = OpLabel
3509 OpReturn
3510 OpFunctionEnd
3511 )";
3512
3513 const auto env = SPV_ENV_UNIVERSAL_1_3;
3514 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3515 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3516 .GetAvailableOpportunities(context.get(), 0);
3517 ASSERT_EQ(1, ops.size());
3518
3519 ASSERT_TRUE(ops[0]->PreconditionHolds());
3520 ops[0]->TryToApply();
3521 CheckValid(env, context.get());
3522
3523 std::string after_op_0 = R"(
3524 OpCapability Shader
3525 %1 = OpExtInstImport "GLSL.std.450"
3526 OpMemoryModel Logical GLSL450
3527 OpEntryPoint Fragment %4 "main" %9
3528 OpExecutionMode %4 OriginUpperLeft
3529 OpSource ESSL 310
3530 OpName %4 "main"
3531 OpName %9 "_GLF_color"
3532 OpName %14 "buf0"
3533 OpMemberName %14 0 "a"
3534 OpName %16 ""
3535 OpDecorate %9 RelaxedPrecision
3536 OpDecorate %9 Location 0
3537 OpMemberDecorate %14 0 RelaxedPrecision
3538 OpMemberDecorate %14 0 Offset 0
3539 OpDecorate %14 Block
3540 OpDecorate %16 DescriptorSet 0
3541 OpDecorate %16 Binding 0
3542 OpDecorate %21 RelaxedPrecision
3543 OpDecorate %35 RelaxedPrecision
3544 OpDecorate %36 RelaxedPrecision
3545 OpDecorate %39 RelaxedPrecision
3546 OpDecorate %40 RelaxedPrecision
3547 %2 = OpTypeVoid
3548 %3 = OpTypeFunction %2
3549 %6 = OpTypeFloat 32
3550 %7 = OpTypeVector %6 4
3551 %8 = OpTypePointer Output %7
3552 %9 = OpVariable %8 Output
3553 %10 = OpConstant %6 1
3554 %11 = OpConstantComposite %7 %10 %10 %10 %10
3555 %14 = OpTypeStruct %6
3556 %15 = OpTypePointer Uniform %14
3557 %16 = OpVariable %15 Uniform
3558 %17 = OpTypeInt 32 1
3559 %18 = OpConstant %17 0
3560 %19 = OpTypePointer Uniform %6
3561 %28 = OpConstant %6 2
3562 %29 = OpTypeBool
3563 %31 = OpTypeInt 32 0
3564 %32 = OpConstant %31 0
3565 %33 = OpTypePointer Output %6
3566 %41 = OpUndef %6 ; Added
3567 %4 = OpFunction %2 None %3
3568 %5 = OpLabel
3569 OpStore %9 %11
3570 %20 = OpAccessChain %19 %16 %18
3571 %21 = OpLoad %6 %20
3572 OpBranch %22
3573 %22 = OpLabel
3574 %40 = OpPhi %6 %21 %5 %41 %23 ; Changed
3575 %30 = OpFOrdLessThan %29 %40 %28
3576 OpSelectionMerge %24 None ; Changed
3577 OpBranchConditional %30 %24 %24
3578 %23 = OpLabel
3579 %34 = OpAccessChain %33 %9 %32
3580 %35 = OpLoad %6 %34
3581 %36 = OpFAdd %6 %35 %10
3582 OpStore %34 %36
3583 %39 = OpFAdd %6 %41 %10 ; Changed
3584 OpBranch %22
3585 %24 = OpLabel
3586 OpReturn
3587 OpFunctionEnd
3588 )";
3589 CheckEqual(env, after_op_0, context.get());
3590 }
3591
TEST(StructuredLoopToSelectionReductionPassTest,LoopWithCombinedHeaderAndContinue)3592 TEST(StructuredLoopToSelectionReductionPassTest,
3593 LoopWithCombinedHeaderAndContinue) {
3594 // A shader containing a loop where the header is also the continue target.
3595 // For now, we don't simplify such loops.
3596
3597 std::string shader = R"(
3598 OpCapability Shader
3599 %1 = OpExtInstImport "GLSL.std.450"
3600 OpMemoryModel Logical GLSL450
3601 OpEntryPoint Fragment %4 "main"
3602 OpExecutionMode %4 OriginUpperLeft
3603 OpSource ESSL 310
3604 %2 = OpTypeVoid
3605 %3 = OpTypeFunction %2
3606 %6 = OpTypeBool
3607 %30 = OpConstantFalse %6
3608 %4 = OpFunction %2 None %3
3609 %5 = OpLabel
3610 OpBranch %10
3611 %10 = OpLabel ; loop header and continue target
3612 OpLoopMerge %12 %10 None
3613 OpBranchConditional %30 %10 %12
3614 %12 = OpLabel
3615 OpReturn
3616 OpFunctionEnd
3617 )";
3618
3619 const auto env = SPV_ENV_UNIVERSAL_1_3;
3620 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3621 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3622 .GetAvailableOpportunities(context.get(), 0);
3623 ASSERT_EQ(0, ops.size());
3624 }
3625
3626 } // namespace
3627 } // namespace reduce
3628 } // namespace spvtools
3629