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 OpBranch %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 OpBranch %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 OpBranch %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 unreachable continue is composed of multiple blocks.
3054 std::string shader = R"(
3055 OpCapability Shader
3056 %1 = OpExtInstImport "GLSL.std.450"
3057 OpMemoryModel Logical GLSL450
3058 OpEntryPoint Fragment %2 "main"
3059 OpExecutionMode %2 OriginUpperLeft
3060 OpSource ESSL 310
3061 %3 = OpTypeVoid
3062 %4 = OpTypeFunction %3
3063 %5 = OpTypeBool
3064 %6 = OpConstantTrue %5
3065 %2 = OpFunction %3 None %4
3066 %7 = OpLabel
3067 OpBranch %8
3068 %8 = OpLabel
3069 OpLoopMerge %9 %10 None
3070 OpBranch %11
3071 %11 = OpLabel
3072 OpLoopMerge %12 %13 None
3073 OpBranch %12
3074 %13 = OpLabel
3075 OpBranch %14
3076 %14 = OpLabel
3077 OpBranch %11
3078 %12 = OpLabel
3079 OpBranch %10
3080 %10 = OpLabel
3081 OpBranchConditional %6 %9 %8
3082 %9 = OpLabel
3083 OpReturn
3084 OpFunctionEnd
3085 )";
3086
3087 const auto env = SPV_ENV_UNIVERSAL_1_3;
3088 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3089 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3090 .GetAvailableOpportunities(context.get(), 0);
3091
3092 ASSERT_EQ(2, ops.size());
3093 ASSERT_TRUE(ops[0]->PreconditionHolds());
3094 ops[0]->TryToApply();
3095
3096 CheckValid(env, context.get());
3097
3098 std::string after_op_0 = R"(
3099 OpCapability Shader
3100 %1 = OpExtInstImport "GLSL.std.450"
3101 OpMemoryModel Logical GLSL450
3102 OpEntryPoint Fragment %2 "main"
3103 OpExecutionMode %2 OriginUpperLeft
3104 OpSource ESSL 310
3105 %3 = OpTypeVoid
3106 %4 = OpTypeFunction %3
3107 %5 = OpTypeBool
3108 %6 = OpConstantTrue %5
3109 %2 = OpFunction %3 None %4
3110 %7 = OpLabel
3111 OpBranch %8
3112 %8 = OpLabel
3113 OpSelectionMerge %9 None
3114 OpBranchConditional %6 %11 %9
3115 %11 = OpLabel
3116 OpLoopMerge %12 %13 None
3117 OpBranch %12
3118 %13 = OpLabel
3119 OpBranch %14
3120 %14 = OpLabel
3121 OpBranch %11
3122 %12 = OpLabel
3123 OpBranch %9
3124 %10 = OpLabel
3125 OpBranchConditional %6 %9 %8
3126 %9 = OpLabel
3127 OpReturn
3128 OpFunctionEnd
3129 )";
3130 CheckEqual(env, after_op_0, context.get());
3131
3132 ASSERT_TRUE(ops[1]->PreconditionHolds());
3133 ops[1]->TryToApply();
3134
3135 CheckValid(env, context.get());
3136
3137 std::string after_op_1 = R"(
3138 OpCapability Shader
3139 %1 = OpExtInstImport "GLSL.std.450"
3140 OpMemoryModel Logical GLSL450
3141 OpEntryPoint Fragment %2 "main"
3142 OpExecutionMode %2 OriginUpperLeft
3143 OpSource ESSL 310
3144 %3 = OpTypeVoid
3145 %4 = OpTypeFunction %3
3146 %5 = OpTypeBool
3147 %6 = OpConstantTrue %5
3148 %2 = OpFunction %3 None %4
3149 %7 = OpLabel
3150 OpBranch %8
3151 %8 = OpLabel
3152 OpSelectionMerge %9 None
3153 OpBranchConditional %6 %11 %9
3154 %11 = OpLabel
3155 OpSelectionMerge %12 None
3156 OpBranchConditional %6 %12 %12
3157 %13 = OpLabel
3158 OpBranch %14
3159 %14 = OpLabel
3160 OpBranch %11
3161 %12 = OpLabel
3162 OpBranch %9
3163 %10 = OpLabel
3164 OpBranchConditional %6 %9 %8
3165 %9 = OpLabel
3166 OpReturn
3167 OpFunctionEnd
3168 )";
3169 CheckEqual(env, after_op_1, context.get());
3170 }
3171
TEST(StructuredLoopToSelectionReductionPassTest,InnerLoopHeaderBranchesToOuterLoopMerge)3172 TEST(StructuredLoopToSelectionReductionPassTest,
3173 InnerLoopHeaderBranchesToOuterLoopMerge) {
3174 std::string shader = R"(
3175 OpCapability Shader
3176 %1 = OpExtInstImport "GLSL.std.450"
3177 OpMemoryModel Logical GLSL450
3178 OpEntryPoint Fragment %2 "main"
3179 OpExecutionMode %2 OriginUpperLeft
3180 OpSource ESSL 310
3181 %3 = OpTypeVoid
3182 %4 = OpTypeFunction %3
3183 %5 = OpTypeBool
3184 %6 = OpConstantTrue %5
3185 %2 = OpFunction %3 None %4
3186 %7 = OpLabel
3187 OpBranch %8
3188 %8 = OpLabel
3189 OpLoopMerge %9 %10 None
3190 OpBranch %11
3191 %11 = OpLabel
3192 OpLoopMerge %12 %13 None
3193 OpBranchConditional %6 %9 %13
3194 %13 = OpLabel
3195 OpBranchConditional %6 %11 %12
3196 %12 = OpLabel
3197 OpBranch %10
3198 %10 = OpLabel
3199 OpBranchConditional %6 %9 %8
3200 %9 = OpLabel
3201 OpReturn
3202 OpFunctionEnd
3203 )";
3204
3205 const auto env = SPV_ENV_UNIVERSAL_1_3;
3206 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3207 auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3208 .GetAvailableOpportunities(context.get(), 0);
3209
3210 // We cannot transform the inner loop due to its header jumping straight to
3211 // the outer loop merge (the inner loop's merge does not post-dominate its
3212 // header).
3213 ASSERT_EQ(1, ops.size());
3214 ASSERT_TRUE(ops[0]->PreconditionHolds());
3215 ops[0]->TryToApply();
3216
3217 CheckValid(env, context.get());
3218
3219 std::string after_op_0 = R"(
3220 OpCapability Shader
3221 %1 = OpExtInstImport "GLSL.std.450"
3222 OpMemoryModel Logical GLSL450
3223 OpEntryPoint Fragment %2 "main"
3224 OpExecutionMode %2 OriginUpperLeft
3225 OpSource ESSL 310
3226 %3 = OpTypeVoid
3227 %4 = OpTypeFunction %3
3228 %5 = OpTypeBool
3229 %6 = OpConstantTrue %5
3230 %2 = OpFunction %3 None %4
3231 %7 = OpLabel
3232 OpBranch %8
3233 %8 = OpLabel
3234 OpSelectionMerge %9 None
3235 OpBranchConditional %6 %11 %9
3236 %11 = OpLabel
3237 OpLoopMerge %12 %13 None
3238 OpBranchConditional %6 %12 %13
3239 %13 = OpLabel
3240 OpBranchConditional %6 %11 %12
3241 %12 = OpLabel
3242 OpBranch %9
3243 %10 = OpLabel
3244 OpBranchConditional %6 %9 %8
3245 %9 = OpLabel
3246 OpReturn
3247 OpFunctionEnd
3248 )";
3249 CheckEqual(env, after_op_0, context.get());
3250
3251 // Now look again for more opportunities.
3252 ops = StructuredLoopToSelectionReductionOpportunityFinder()
3253 .GetAvailableOpportunities(context.get(), 0);
3254
3255 // What was the inner loop should now be transformable, as the jump to the
3256 // outer loop's merge has been redirected.
3257 ASSERT_EQ(1, ops.size());
3258 ASSERT_TRUE(ops[0]->PreconditionHolds());
3259 ops[0]->TryToApply();
3260
3261 CheckValid(env, context.get());
3262
3263 std::string after_another_op_0 = R"(
3264 OpCapability Shader
3265 %1 = OpExtInstImport "GLSL.std.450"
3266 OpMemoryModel Logical GLSL450
3267 OpEntryPoint Fragment %2 "main"
3268 OpExecutionMode %2 OriginUpperLeft
3269 OpSource ESSL 310
3270 %3 = OpTypeVoid
3271 %4 = OpTypeFunction %3
3272 %5 = OpTypeBool
3273 %6 = OpConstantTrue %5
3274 %2 = OpFunction %3 None %4
3275 %7 = OpLabel
3276 OpBranch %8
3277 %8 = OpLabel
3278 OpSelectionMerge %9 None
3279 OpBranchConditional %6 %11 %9
3280 %11 = OpLabel
3281 OpSelectionMerge %12 None
3282 OpBranchConditional %6 %12 %12
3283 %13 = OpLabel
3284 OpBranchConditional %6 %11 %12
3285 %12 = OpLabel
3286 OpBranch %9
3287 %10 = OpLabel
3288 OpBranchConditional %6 %9 %8
3289 %9 = OpLabel
3290 OpReturn
3291 OpFunctionEnd
3292 )";
3293 CheckEqual(env, after_another_op_0, context.get());
3294 }
3295
TEST(StructuredLoopToSelectionReductionPassTest,LongAccessChains)3296 TEST(StructuredLoopToSelectionReductionPassTest, LongAccessChains) {
3297 std::string shader = R"(
3298 OpCapability Shader
3299 %1 = OpExtInstImport "GLSL.std.450"
3300 OpMemoryModel Logical GLSL450
3301 OpEntryPoint Fragment %2 "main"
3302 OpExecutionMode %2 OriginUpperLeft
3303 OpSource ESSL 310
3304 %3 = OpTypeVoid
3305 %4 = OpTypeFunction %3
3306 %5 = OpTypeInt 32 1
3307 %6 = OpTypeInt 32 0
3308 %7 = OpConstant %6 5
3309 %8 = OpTypeArray %5 %7
3310 %9 = OpTypeStruct %8
3311 %10 = OpTypeStruct %9 %9
3312 %11 = OpConstant %6 2
3313 %12 = OpTypeArray %10 %11
3314 %13 = OpTypeStruct %12
3315 %14 = OpTypePointer Function %13
3316 %15 = OpConstant %5 0
3317 %16 = OpConstant %5 1
3318 %17 = OpConstant %5 2
3319 %18 = OpConstant %5 3
3320 %19 = OpConstant %5 4
3321 %20 = OpConstantComposite %8 %15 %16 %17 %18 %19
3322 %21 = OpConstantComposite %9 %20
3323 %22 = OpConstant %5 5
3324 %23 = OpConstant %5 6
3325 %24 = OpConstant %5 7
3326 %25 = OpConstant %5 8
3327 %26 = OpConstant %5 9
3328 %27 = OpConstantComposite %8 %22 %23 %24 %25 %26
3329 %28 = OpConstantComposite %9 %27
3330 %29 = OpConstantComposite %10 %21 %28
3331 %30 = OpConstant %5 10
3332 %31 = OpConstant %5 11
3333 %32 = OpConstant %5 12
3334 %33 = OpConstant %5 13
3335 %34 = OpConstant %5 14
3336 %35 = OpConstantComposite %8 %30 %31 %32 %33 %34
3337 %36 = OpConstantComposite %9 %35
3338 %37 = OpConstant %5 15
3339 %38 = OpConstant %5 16
3340 %39 = OpConstant %5 17
3341 %40 = OpConstant %5 18
3342 %41 = OpConstant %5 19
3343 %42 = OpConstantComposite %8 %37 %38 %39 %40 %41
3344 %43 = OpConstantComposite %9 %42
3345 %44 = OpConstantComposite %10 %36 %43
3346 %45 = OpConstantComposite %12 %29 %44
3347 %46 = OpConstantComposite %13 %45
3348 %47 = OpTypePointer Function %12
3349 %48 = OpTypePointer Function %10
3350 %49 = OpTypePointer Function %9
3351 %50 = OpTypePointer Function %8
3352 %51 = OpTypePointer Function %5
3353 %52 = OpTypeBool
3354 %53 = OpConstantTrue %52
3355 %2 = OpFunction %3 None %4
3356 %54 = OpLabel
3357 %55 = OpVariable %14 Function
3358 OpStore %55 %46
3359 OpBranch %56
3360 %56 = OpLabel
3361 OpLoopMerge %57 %58 None
3362 OpBranchConditional %53 %57 %59
3363 %59 = OpLabel
3364 OpSelectionMerge %60 None
3365 OpBranchConditional %53 %61 %57
3366 %61 = OpLabel
3367 %62 = OpAccessChain %47 %55 %15
3368 OpBranch %63
3369 %63 = OpLabel
3370 OpSelectionMerge %64 None
3371 OpBranchConditional %53 %65 %57
3372 %65 = OpLabel
3373 %66 = OpAccessChain %48 %62 %16
3374 OpBranch %67
3375 %67 = OpLabel
3376 OpSelectionMerge %68 None
3377 OpBranchConditional %53 %69 %57
3378 %69 = OpLabel
3379 %70 = OpAccessChain %49 %66 %16
3380 OpBranch %71
3381 %71 = OpLabel
3382 OpSelectionMerge %72 None
3383 OpBranchConditional %53 %73 %57
3384 %73 = OpLabel
3385 %74 = OpAccessChain %50 %70 %15
3386 OpBranch %75
3387 %75 = OpLabel
3388 OpSelectionMerge %76 None
3389 OpBranchConditional %53 %77 %57
3390 %77 = OpLabel
3391 %78 = OpAccessChain %51 %74 %17
3392 OpBranch %79
3393 %79 = OpLabel
3394 OpSelectionMerge %80 None
3395 OpBranchConditional %53 %81 %57
3396 %81 = OpLabel
3397 %82 = OpLoad %5 %78
3398 OpBranch %80
3399 %80 = OpLabel
3400 OpBranch %76
3401 %76 = OpLabel
3402 OpBranch %72
3403 %72 = OpLabel
3404 OpBranch %68
3405 %68 = OpLabel
3406 OpBranch %64
3407 %64 = OpLabel
3408 OpBranch %60
3409 %60 = OpLabel
3410 OpBranch %58
3411 %58 = OpLabel
3412 OpBranch %56
3413 %57 = OpLabel
3414 OpReturn
3415 OpFunctionEnd
3416 )";
3417
3418 const auto env = SPV_ENV_UNIVERSAL_1_3;
3419 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3420 auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3421 .GetAvailableOpportunities(context.get(), 0);
3422
3423 ASSERT_EQ(1, ops.size());
3424 ASSERT_TRUE(ops[0]->PreconditionHolds());
3425 ops[0]->TryToApply();
3426
3427 CheckValid(env, context.get());
3428
3429 // TODO(2183): When we have a more general solution for handling access
3430 // chains, write an expected result for this test.
3431 // std::string expected = R"(
3432 // Expected text for transformed shader
3433 //)";
3434 // CheckEqual(env, expected, context.get());
3435 }
3436
TEST(StructuredLoopToSelectionReductionPassTest,LoopyShaderWithOpDecorate)3437 TEST(StructuredLoopToSelectionReductionPassTest, LoopyShaderWithOpDecorate) {
3438 // A shader containing a function that contains a loop and some definitions
3439 // that are "used" in OpDecorate instructions (outside the function). These
3440 // "uses" were causing segfaults because we try to calculate their dominance
3441 // information, which doesn't make sense.
3442
3443 std::string shader = R"(
3444 OpCapability Shader
3445 %1 = OpExtInstImport "GLSL.std.450"
3446 OpMemoryModel Logical GLSL450
3447 OpEntryPoint Fragment %4 "main" %9
3448 OpExecutionMode %4 OriginUpperLeft
3449 OpSource ESSL 310
3450 OpName %4 "main"
3451 OpName %9 "_GLF_color"
3452 OpName %14 "buf0"
3453 OpMemberName %14 0 "a"
3454 OpName %16 ""
3455 OpDecorate %9 RelaxedPrecision
3456 OpDecorate %9 Location 0
3457 OpMemberDecorate %14 0 RelaxedPrecision
3458 OpMemberDecorate %14 0 Offset 0
3459 OpDecorate %14 Block
3460 OpDecorate %16 DescriptorSet 0
3461 OpDecorate %16 Binding 0
3462 OpDecorate %21 RelaxedPrecision
3463 OpDecorate %35 RelaxedPrecision
3464 OpDecorate %36 RelaxedPrecision
3465 OpDecorate %39 RelaxedPrecision
3466 OpDecorate %40 RelaxedPrecision
3467 %2 = OpTypeVoid
3468 %3 = OpTypeFunction %2
3469 %6 = OpTypeFloat 32
3470 %7 = OpTypeVector %6 4
3471 %8 = OpTypePointer Output %7
3472 %9 = OpVariable %8 Output
3473 %10 = OpConstant %6 1
3474 %11 = OpConstantComposite %7 %10 %10 %10 %10
3475 %14 = OpTypeStruct %6
3476 %15 = OpTypePointer Uniform %14
3477 %16 = OpVariable %15 Uniform
3478 %17 = OpTypeInt 32 1
3479 %18 = OpConstant %17 0
3480 %19 = OpTypePointer Uniform %6
3481 %28 = OpConstant %6 2
3482 %29 = OpTypeBool
3483 %31 = OpTypeInt 32 0
3484 %32 = OpConstant %31 0
3485 %33 = OpTypePointer Output %6
3486 %4 = OpFunction %2 None %3
3487 %5 = OpLabel
3488 OpStore %9 %11
3489 %20 = OpAccessChain %19 %16 %18
3490 %21 = OpLoad %6 %20
3491 OpBranch %22
3492 %22 = OpLabel
3493 %40 = OpPhi %6 %21 %5 %39 %23
3494 %30 = OpFOrdLessThan %29 %40 %28
3495 OpLoopMerge %24 %23 None
3496 OpBranchConditional %30 %23 %24
3497 %23 = OpLabel
3498 %34 = OpAccessChain %33 %9 %32
3499 %35 = OpLoad %6 %34
3500 %36 = OpFAdd %6 %35 %10
3501 OpStore %34 %36
3502 %39 = OpFAdd %6 %40 %10
3503 OpBranch %22
3504 %24 = OpLabel
3505 OpReturn
3506 OpFunctionEnd
3507 )";
3508
3509 const auto env = SPV_ENV_UNIVERSAL_1_3;
3510 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3511 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3512 .GetAvailableOpportunities(context.get(), 0);
3513 ASSERT_EQ(1, ops.size());
3514
3515 ASSERT_TRUE(ops[0]->PreconditionHolds());
3516 ops[0]->TryToApply();
3517 CheckValid(env, context.get());
3518
3519 std::string after_op_0 = R"(
3520 OpCapability Shader
3521 %1 = OpExtInstImport "GLSL.std.450"
3522 OpMemoryModel Logical GLSL450
3523 OpEntryPoint Fragment %4 "main" %9
3524 OpExecutionMode %4 OriginUpperLeft
3525 OpSource ESSL 310
3526 OpName %4 "main"
3527 OpName %9 "_GLF_color"
3528 OpName %14 "buf0"
3529 OpMemberName %14 0 "a"
3530 OpName %16 ""
3531 OpDecorate %9 RelaxedPrecision
3532 OpDecorate %9 Location 0
3533 OpMemberDecorate %14 0 RelaxedPrecision
3534 OpMemberDecorate %14 0 Offset 0
3535 OpDecorate %14 Block
3536 OpDecorate %16 DescriptorSet 0
3537 OpDecorate %16 Binding 0
3538 OpDecorate %21 RelaxedPrecision
3539 OpDecorate %35 RelaxedPrecision
3540 OpDecorate %36 RelaxedPrecision
3541 OpDecorate %39 RelaxedPrecision
3542 OpDecorate %40 RelaxedPrecision
3543 %2 = OpTypeVoid
3544 %3 = OpTypeFunction %2
3545 %6 = OpTypeFloat 32
3546 %7 = OpTypeVector %6 4
3547 %8 = OpTypePointer Output %7
3548 %9 = OpVariable %8 Output
3549 %10 = OpConstant %6 1
3550 %11 = OpConstantComposite %7 %10 %10 %10 %10
3551 %14 = OpTypeStruct %6
3552 %15 = OpTypePointer Uniform %14
3553 %16 = OpVariable %15 Uniform
3554 %17 = OpTypeInt 32 1
3555 %18 = OpConstant %17 0
3556 %19 = OpTypePointer Uniform %6
3557 %28 = OpConstant %6 2
3558 %29 = OpTypeBool
3559 %31 = OpTypeInt 32 0
3560 %32 = OpConstant %31 0
3561 %33 = OpTypePointer Output %6
3562 %41 = OpUndef %6 ; Added
3563 %4 = OpFunction %2 None %3
3564 %5 = OpLabel
3565 OpStore %9 %11
3566 %20 = OpAccessChain %19 %16 %18
3567 %21 = OpLoad %6 %20
3568 OpBranch %22
3569 %22 = OpLabel
3570 %40 = OpPhi %6 %21 %5 %41 %23 ; Changed
3571 %30 = OpFOrdLessThan %29 %40 %28
3572 OpSelectionMerge %24 None ; Changed
3573 OpBranchConditional %30 %24 %24
3574 %23 = OpLabel
3575 %34 = OpAccessChain %33 %9 %32
3576 %35 = OpLoad %6 %34
3577 %36 = OpFAdd %6 %35 %10
3578 OpStore %34 %36
3579 %39 = OpFAdd %6 %41 %10 ; Changed
3580 OpBranch %22
3581 %24 = OpLabel
3582 OpReturn
3583 OpFunctionEnd
3584 )";
3585 CheckEqual(env, after_op_0, context.get());
3586 }
3587
TEST(StructuredLoopToSelectionReductionPassTest,LoopWithCombinedHeaderAndContinue)3588 TEST(StructuredLoopToSelectionReductionPassTest,
3589 LoopWithCombinedHeaderAndContinue) {
3590 // A shader containing a loop where the header is also the continue target.
3591 // For now, we don't simplify such loops.
3592
3593 std::string shader = R"(
3594 OpCapability Shader
3595 %1 = OpExtInstImport "GLSL.std.450"
3596 OpMemoryModel Logical GLSL450
3597 OpEntryPoint Fragment %4 "main"
3598 OpExecutionMode %4 OriginUpperLeft
3599 OpSource ESSL 310
3600 %2 = OpTypeVoid
3601 %3 = OpTypeFunction %2
3602 %6 = OpTypeBool
3603 %30 = OpConstantFalse %6
3604 %4 = OpFunction %2 None %3
3605 %5 = OpLabel
3606 OpBranch %10
3607 %10 = OpLabel ; loop header and continue target
3608 OpLoopMerge %12 %10 None
3609 OpBranchConditional %30 %10 %12
3610 %12 = OpLabel
3611 OpReturn
3612 OpFunctionEnd
3613 )";
3614
3615 const auto env = SPV_ENV_UNIVERSAL_1_3;
3616 const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
3617 const auto ops = StructuredLoopToSelectionReductionOpportunityFinder()
3618 .GetAvailableOpportunities(context.get(), 0);
3619 ASSERT_EQ(0, ops.size());
3620 }
3621
3622 } // namespace
3623 } // namespace reduce
3624 } // namespace spvtools
3625