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