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 <memory>
16 #include <vector>
17 
18 #include "gmock/gmock.h"
19 #include "source/opt/loop_descriptor.h"
20 #include "source/opt/loop_fusion.h"
21 #include "test/opt/pass_fixture.h"
22 
23 namespace spvtools {
24 namespace opt {
25 namespace {
26 
27 using FusionIllegalTest = PassTest<::testing::Test>;
28 
29 /*
30 Generated from the following GLSL + --eliminate-local-multi-store
31 
32 #version 440 core
33 void main() {
34   int[10] a;
35   int[10] b;
36   int[10] c;
37   // Illegal, loop-independent dependence will become a
38   // backward loop-carried antidependence
39   for (int i = 0; i < 10; i++) {
40     a[i] = b[i] + 1;
41   }
42   for (int i = 0; i < 10; i++) {
43     c[i] = a[i+1] + 2;
44   }
45 }
46 
47 */
TEST_F(FusionIllegalTest,PositiveDistanceCreatedRAW)48 TEST_F(FusionIllegalTest, PositiveDistanceCreatedRAW) {
49   std::string text = R"(
50                OpCapability Shader
51           %1 = OpExtInstImport "GLSL.std.450"
52                OpMemoryModel Logical GLSL450
53                OpEntryPoint Fragment %4 "main"
54                OpExecutionMode %4 OriginUpperLeft
55                OpSource GLSL 440
56                OpName %4 "main"
57                OpName %8 "i"
58                OpName %23 "a"
59                OpName %25 "b"
60                OpName %34 "i"
61                OpName %42 "c"
62           %2 = OpTypeVoid
63           %3 = OpTypeFunction %2
64           %6 = OpTypeInt 32 1
65           %7 = OpTypePointer Function %6
66           %9 = OpConstant %6 0
67          %16 = OpConstant %6 10
68          %17 = OpTypeBool
69          %19 = OpTypeInt 32 0
70          %20 = OpConstant %19 10
71          %21 = OpTypeArray %6 %20
72          %22 = OpTypePointer Function %21
73          %29 = OpConstant %6 1
74          %48 = OpConstant %6 2
75           %4 = OpFunction %2 None %3
76           %5 = OpLabel
77           %8 = OpVariable %7 Function
78          %23 = OpVariable %22 Function
79          %25 = OpVariable %22 Function
80          %34 = OpVariable %7 Function
81          %42 = OpVariable %22 Function
82                OpStore %8 %9
83                OpBranch %10
84          %10 = OpLabel
85          %53 = OpPhi %6 %9 %5 %33 %13
86                OpLoopMerge %12 %13 None
87                OpBranch %14
88          %14 = OpLabel
89          %18 = OpSLessThan %17 %53 %16
90                OpBranchConditional %18 %11 %12
91          %11 = OpLabel
92          %27 = OpAccessChain %7 %25 %53
93          %28 = OpLoad %6 %27
94          %30 = OpIAdd %6 %28 %29
95          %31 = OpAccessChain %7 %23 %53
96                OpStore %31 %30
97                OpBranch %13
98          %13 = OpLabel
99          %33 = OpIAdd %6 %53 %29
100                OpStore %8 %33
101                OpBranch %10
102          %12 = OpLabel
103                OpStore %34 %9
104                OpBranch %35
105          %35 = OpLabel
106          %54 = OpPhi %6 %9 %12 %52 %38
107                OpLoopMerge %37 %38 None
108                OpBranch %39
109          %39 = OpLabel
110          %41 = OpSLessThan %17 %54 %16
111                OpBranchConditional %41 %36 %37
112          %36 = OpLabel
113          %45 = OpIAdd %6 %54 %29
114          %46 = OpAccessChain %7 %23 %45
115          %47 = OpLoad %6 %46
116          %49 = OpIAdd %6 %47 %48
117          %50 = OpAccessChain %7 %42 %54
118                OpStore %50 %49
119                OpBranch %38
120          %38 = OpLabel
121          %52 = OpIAdd %6 %54 %29
122                OpStore %34 %52
123                OpBranch %35
124          %37 = OpLabel
125                OpReturn
126                OpFunctionEnd
127     )";
128 
129   std::unique_ptr<IRContext> context =
130       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
131                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
132   Module* module = context->module();
133   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
134                              << text << std::endl;
135   Function& f = *module->begin();
136   LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
137   EXPECT_EQ(ld.NumLoops(), 2u);
138 
139   auto loops = ld.GetLoopsInBinaryLayoutOrder();
140 
141   LoopFusion fusion(context.get(), loops[0], loops[1]);
142 
143   EXPECT_TRUE(fusion.AreCompatible());
144   EXPECT_FALSE(fusion.IsLegal());
145 }
146 
147 /*
148 Generated from the following GLSL + --eliminate-local-multi-store
149 
150 #version 440 core
151 
152 int func() {
153   return 10;
154 }
155 
156 void main() {
157   int[10] a;
158   int[10] b;
159   // Illegal, function call
160   for (int i = 0; i < 10; i++) {
161     a[i] = func();
162   }
163   for (int i = 0; i < 10; i++) {
164     b[i] = a[i];
165   }
166 }
167 */
TEST_F(FusionIllegalTest,FunctionCall)168 TEST_F(FusionIllegalTest, FunctionCall) {
169   std::string text = R"(
170                OpCapability Shader
171           %1 = OpExtInstImport "GLSL.std.450"
172                OpMemoryModel Logical GLSL450
173                OpEntryPoint Fragment %4 "main"
174                OpExecutionMode %4 OriginUpperLeft
175                OpSource GLSL 440
176                OpName %4 "main"
177                OpName %8 "func("
178                OpName %14 "i"
179                OpName %28 "a"
180                OpName %35 "i"
181                OpName %43 "b"
182           %2 = OpTypeVoid
183           %3 = OpTypeFunction %2
184           %6 = OpTypeInt 32 1
185           %7 = OpTypeFunction %6
186          %10 = OpConstant %6 10
187          %13 = OpTypePointer Function %6
188          %15 = OpConstant %6 0
189          %22 = OpTypeBool
190          %24 = OpTypeInt 32 0
191          %25 = OpConstant %24 10
192          %26 = OpTypeArray %6 %25
193          %27 = OpTypePointer Function %26
194          %33 = OpConstant %6 1
195           %4 = OpFunction %2 None %3
196           %5 = OpLabel
197          %14 = OpVariable %13 Function
198          %28 = OpVariable %27 Function
199          %35 = OpVariable %13 Function
200          %43 = OpVariable %27 Function
201                OpStore %14 %15
202                OpBranch %16
203          %16 = OpLabel
204          %51 = OpPhi %6 %15 %5 %34 %19
205                OpLoopMerge %18 %19 None
206                OpBranch %20
207          %20 = OpLabel
208          %23 = OpSLessThan %22 %51 %10
209                OpBranchConditional %23 %17 %18
210          %17 = OpLabel
211          %30 = OpFunctionCall %6 %8
212          %31 = OpAccessChain %13 %28 %51
213                OpStore %31 %30
214                OpBranch %19
215          %19 = OpLabel
216          %34 = OpIAdd %6 %51 %33
217                OpStore %14 %34
218                OpBranch %16
219          %18 = OpLabel
220                OpStore %35 %15
221                OpBranch %36
222          %36 = OpLabel
223          %52 = OpPhi %6 %15 %18 %50 %39
224                OpLoopMerge %38 %39 None
225                OpBranch %40
226          %40 = OpLabel
227          %42 = OpSLessThan %22 %52 %10
228                OpBranchConditional %42 %37 %38
229          %37 = OpLabel
230          %46 = OpAccessChain %13 %28 %52
231          %47 = OpLoad %6 %46
232          %48 = OpAccessChain %13 %43 %52
233                OpStore %48 %47
234                OpBranch %39
235          %39 = OpLabel
236          %50 = OpIAdd %6 %52 %33
237                OpStore %35 %50
238                OpBranch %36
239          %38 = OpLabel
240                OpReturn
241                OpFunctionEnd
242           %8 = OpFunction %6 None %7
243           %9 = OpLabel
244                OpReturnValue %10
245                OpFunctionEnd
246     )";
247 
248   std::unique_ptr<IRContext> context =
249       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
250                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
251   Module* module = context->module();
252   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
253                              << text << std::endl;
254   Function& f = *module->begin();
255   LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
256   EXPECT_EQ(ld.NumLoops(), 2u);
257 
258   auto loops = ld.GetLoopsInBinaryLayoutOrder();
259 
260   LoopFusion fusion(context.get(), loops[0], loops[1]);
261 
262   EXPECT_TRUE(fusion.AreCompatible());
263   EXPECT_FALSE(fusion.IsLegal());
264 }
265 
266 /*
267 Generated from the following GLSL + --eliminate-local-multi-store
268 
269 // 16
270 #version 440 core
271 void main() {
272   int[10][10] a;
273   int[10][10] b;
274   int[10][10] c;
275   // Illegal outer.
276   for (int i = 0; i < 10; i++) {
277     for (int j = 0; j < 10; j++) {
278       c[i][j] = a[i][j] + 2;
279     }
280   }
281   for (int i = 0; i < 10; i++) {
282     for (int j = 0; j < 10; j++) {
283       b[i][j] = c[i+1][j] + 10;
284     }
285   }
286 }
287 
288 */
TEST_F(FusionIllegalTest,PositiveDistanceCreatedRAWOuterLoop)289 TEST_F(FusionIllegalTest, PositiveDistanceCreatedRAWOuterLoop) {
290   std::string text = R"(
291                OpCapability Shader
292           %1 = OpExtInstImport "GLSL.std.450"
293                OpMemoryModel Logical GLSL450
294                OpEntryPoint Fragment %4 "main"
295                OpExecutionMode %4 OriginUpperLeft
296                OpSource GLSL 440
297                OpName %4 "main"
298                OpName %8 "i"
299                OpName %19 "j"
300                OpName %32 "c"
301                OpName %35 "a"
302                OpName %48 "i"
303                OpName %56 "j"
304                OpName %64 "b"
305           %2 = OpTypeVoid
306           %3 = OpTypeFunction %2
307           %6 = OpTypeInt 32 1
308           %7 = OpTypePointer Function %6
309           %9 = OpConstant %6 0
310          %16 = OpConstant %6 10
311          %17 = OpTypeBool
312          %27 = OpTypeInt 32 0
313          %28 = OpConstant %27 10
314          %29 = OpTypeArray %6 %28
315          %30 = OpTypeArray %29 %28
316          %31 = OpTypePointer Function %30
317          %40 = OpConstant %6 2
318          %44 = OpConstant %6 1
319           %4 = OpFunction %2 None %3
320           %5 = OpLabel
321           %8 = OpVariable %7 Function
322          %19 = OpVariable %7 Function
323          %32 = OpVariable %31 Function
324          %35 = OpVariable %31 Function
325          %48 = OpVariable %7 Function
326          %56 = OpVariable %7 Function
327          %64 = OpVariable %31 Function
328                OpStore %8 %9
329                OpBranch %10
330          %10 = OpLabel
331          %78 = OpPhi %6 %9 %5 %47 %13
332                OpLoopMerge %12 %13 None
333                OpBranch %14
334          %14 = OpLabel
335          %18 = OpSLessThan %17 %78 %16
336                OpBranchConditional %18 %11 %12
337          %11 = OpLabel
338                OpStore %19 %9
339                OpBranch %20
340          %20 = OpLabel
341          %82 = OpPhi %6 %9 %11 %45 %23
342                OpLoopMerge %22 %23 None
343                OpBranch %24
344          %24 = OpLabel
345          %26 = OpSLessThan %17 %82 %16
346                OpBranchConditional %26 %21 %22
347          %21 = OpLabel
348          %38 = OpAccessChain %7 %35 %78 %82
349          %39 = OpLoad %6 %38
350          %41 = OpIAdd %6 %39 %40
351          %42 = OpAccessChain %7 %32 %78 %82
352                OpStore %42 %41
353                OpBranch %23
354          %23 = OpLabel
355          %45 = OpIAdd %6 %82 %44
356                OpStore %19 %45
357                OpBranch %20
358          %22 = OpLabel
359                OpBranch %13
360          %13 = OpLabel
361          %47 = OpIAdd %6 %78 %44
362                OpStore %8 %47
363                OpBranch %10
364          %12 = OpLabel
365                OpStore %48 %9
366                OpBranch %49
367          %49 = OpLabel
368          %79 = OpPhi %6 %9 %12 %77 %52
369                OpLoopMerge %51 %52 None
370                OpBranch %53
371          %53 = OpLabel
372          %55 = OpSLessThan %17 %79 %16
373                OpBranchConditional %55 %50 %51
374          %50 = OpLabel
375                OpStore %56 %9
376                OpBranch %57
377          %57 = OpLabel
378          %80 = OpPhi %6 %9 %50 %75 %60
379                OpLoopMerge %59 %60 None
380                OpBranch %61
381          %61 = OpLabel
382          %63 = OpSLessThan %17 %80 %16
383                OpBranchConditional %63 %58 %59
384          %58 = OpLabel
385          %68 = OpIAdd %6 %79 %44
386          %70 = OpAccessChain %7 %32 %68 %80
387          %71 = OpLoad %6 %70
388          %72 = OpIAdd %6 %71 %16
389          %73 = OpAccessChain %7 %64 %79 %80
390                OpStore %73 %72
391                OpBranch %60
392          %60 = OpLabel
393          %75 = OpIAdd %6 %80 %44
394                OpStore %56 %75
395                OpBranch %57
396          %59 = OpLabel
397                OpBranch %52
398          %52 = OpLabel
399          %77 = OpIAdd %6 %79 %44
400                OpStore %48 %77
401                OpBranch %49
402          %51 = OpLabel
403                OpReturn
404                OpFunctionEnd
405     )";
406 
407   std::unique_ptr<IRContext> context =
408       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
409                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
410   Module* module = context->module();
411   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
412                              << text << std::endl;
413   Function& f = *module->begin();
414 
415   {
416     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
417     EXPECT_EQ(ld.NumLoops(), 4u);
418 
419     auto loops = ld.GetLoopsInBinaryLayoutOrder();
420 
421     auto loop_0 = loops[0];
422     auto loop_1 = loops[1];
423     auto loop_2 = loops[2];
424     auto loop_3 = loops[3];
425 
426     {
427       LoopFusion fusion(context.get(), loop_0, loop_1);
428       EXPECT_FALSE(fusion.AreCompatible());
429     }
430 
431     {
432       LoopFusion fusion(context.get(), loop_0, loop_2);
433       EXPECT_TRUE(fusion.AreCompatible());
434       EXPECT_FALSE(fusion.IsLegal());
435     }
436 
437     {
438       LoopFusion fusion(context.get(), loop_1, loop_2);
439       EXPECT_FALSE(fusion.AreCompatible());
440     }
441 
442     {
443       LoopFusion fusion(context.get(), loop_2, loop_3);
444       EXPECT_FALSE(fusion.AreCompatible());
445     }
446   }
447 }
448 
449 /*
450 Generated from the following GLSL + --eliminate-local-multi-store
451 
452 // 19
453 #version 440 core
454 void main() {
455   int[10] a;
456   int[10] b;
457   int[10] c;
458   // Illegal, would create a backward loop-carried anti-dependence.
459   for (int i = 0; i < 10; i++) {
460     c[i] = a[i] + 1;
461   }
462   for (int i = 0; i < 10; i++) {
463     a[i+1] = c[i] + 2;
464   }
465 }
466 
467 */
TEST_F(FusionIllegalTest,PositiveDistanceCreatedWAR)468 TEST_F(FusionIllegalTest, PositiveDistanceCreatedWAR) {
469   std::string text = R"(
470                OpCapability Shader
471           %1 = OpExtInstImport "GLSL.std.450"
472                OpMemoryModel Logical GLSL450
473                OpEntryPoint Fragment %4 "main"
474                OpExecutionMode %4 OriginUpperLeft
475                OpSource GLSL 440
476                OpName %4 "main"
477                OpName %8 "i"
478                OpName %23 "c"
479                OpName %25 "a"
480                OpName %34 "i"
481           %2 = OpTypeVoid
482           %3 = OpTypeFunction %2
483           %6 = OpTypeInt 32 1
484           %7 = OpTypePointer Function %6
485           %9 = OpConstant %6 0
486          %16 = OpConstant %6 10
487          %17 = OpTypeBool
488          %19 = OpTypeInt 32 0
489          %20 = OpConstant %19 10
490          %21 = OpTypeArray %6 %20
491          %22 = OpTypePointer Function %21
492          %29 = OpConstant %6 1
493          %47 = OpConstant %6 2
494           %4 = OpFunction %2 None %3
495           %5 = OpLabel
496           %8 = OpVariable %7 Function
497          %23 = OpVariable %22 Function
498          %25 = OpVariable %22 Function
499          %34 = OpVariable %7 Function
500                OpStore %8 %9
501                OpBranch %10
502          %10 = OpLabel
503          %52 = OpPhi %6 %9 %5 %33 %13
504                OpLoopMerge %12 %13 None
505                OpBranch %14
506          %14 = OpLabel
507          %18 = OpSLessThan %17 %52 %16
508                OpBranchConditional %18 %11 %12
509          %11 = OpLabel
510          %27 = OpAccessChain %7 %25 %52
511          %28 = OpLoad %6 %27
512          %30 = OpIAdd %6 %28 %29
513          %31 = OpAccessChain %7 %23 %52
514                OpStore %31 %30
515                OpBranch %13
516          %13 = OpLabel
517          %33 = OpIAdd %6 %52 %29
518                OpStore %8 %33
519                OpBranch %10
520          %12 = OpLabel
521                OpStore %34 %9
522                OpBranch %35
523          %35 = OpLabel
524          %53 = OpPhi %6 %9 %12 %51 %38
525                OpLoopMerge %37 %38 None
526                OpBranch %39
527          %39 = OpLabel
528          %41 = OpSLessThan %17 %53 %16
529                OpBranchConditional %41 %36 %37
530          %36 = OpLabel
531          %43 = OpIAdd %6 %53 %29
532          %45 = OpAccessChain %7 %23 %53
533          %46 = OpLoad %6 %45
534          %48 = OpIAdd %6 %46 %47
535          %49 = OpAccessChain %7 %25 %43
536                OpStore %49 %48
537                OpBranch %38
538          %38 = OpLabel
539          %51 = OpIAdd %6 %53 %29
540                OpStore %34 %51
541                OpBranch %35
542          %37 = OpLabel
543                OpReturn
544                OpFunctionEnd
545     )";
546 
547   std::unique_ptr<IRContext> context =
548       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
549                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
550   Module* module = context->module();
551   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
552                              << text << std::endl;
553   Function& f = *module->begin();
554 
555   {
556     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
557     EXPECT_EQ(ld.NumLoops(), 2u);
558 
559     auto loops = ld.GetLoopsInBinaryLayoutOrder();
560 
561     LoopFusion fusion(context.get(), loops[0], loops[1]);
562     EXPECT_TRUE(fusion.AreCompatible());
563     EXPECT_FALSE(fusion.IsLegal());
564   }
565 }
566 
567 /*
568 Generated from the following GLSL + --eliminate-local-multi-store
569 
570 // 21
571 #version 440 core
572 void main() {
573   int[10] a;
574   int[10] b;
575   int[10] c;
576   // Illegal, would create a backward loop-carried anti-dependence.
577   for (int i = 0; i < 10; i++) {
578     a[i] = b[i] + 1;
579   }
580   for (int i = 0; i < 10; i++) {
581     a[i+1] = c[i+1] + 2;
582   }
583 }
584 
585 */
TEST_F(FusionIllegalTest,PositiveDistanceCreatedWAW)586 TEST_F(FusionIllegalTest, PositiveDistanceCreatedWAW) {
587   std::string text = R"(
588                OpCapability Shader
589           %1 = OpExtInstImport "GLSL.std.450"
590                OpMemoryModel Logical GLSL450
591                OpEntryPoint Fragment %4 "main"
592                OpExecutionMode %4 OriginUpperLeft
593                OpSource GLSL 440
594                OpName %4 "main"
595                OpName %8 "i"
596                OpName %23 "a"
597                OpName %25 "b"
598                OpName %34 "i"
599                OpName %44 "c"
600           %2 = OpTypeVoid
601           %3 = OpTypeFunction %2
602           %6 = OpTypeInt 32 1
603           %7 = OpTypePointer Function %6
604           %9 = OpConstant %6 0
605          %16 = OpConstant %6 10
606          %17 = OpTypeBool
607          %19 = OpTypeInt 32 0
608          %20 = OpConstant %19 10
609          %21 = OpTypeArray %6 %20
610          %22 = OpTypePointer Function %21
611          %29 = OpConstant %6 1
612          %49 = OpConstant %6 2
613           %4 = OpFunction %2 None %3
614           %5 = OpLabel
615           %8 = OpVariable %7 Function
616          %23 = OpVariable %22 Function
617          %25 = OpVariable %22 Function
618          %34 = OpVariable %7 Function
619          %44 = OpVariable %22 Function
620                OpStore %8 %9
621                OpBranch %10
622          %10 = OpLabel
623          %54 = OpPhi %6 %9 %5 %33 %13
624                OpLoopMerge %12 %13 None
625                OpBranch %14
626          %14 = OpLabel
627          %18 = OpSLessThan %17 %54 %16
628                OpBranchConditional %18 %11 %12
629          %11 = OpLabel
630          %27 = OpAccessChain %7 %25 %54
631          %28 = OpLoad %6 %27
632          %30 = OpIAdd %6 %28 %29
633          %31 = OpAccessChain %7 %23 %54
634                OpStore %31 %30
635                OpBranch %13
636          %13 = OpLabel
637          %33 = OpIAdd %6 %54 %29
638                OpStore %8 %33
639                OpBranch %10
640          %12 = OpLabel
641                OpStore %34 %9
642                OpBranch %35
643          %35 = OpLabel
644          %55 = OpPhi %6 %9 %12 %53 %38
645                OpLoopMerge %37 %38 None
646                OpBranch %39
647          %39 = OpLabel
648          %41 = OpSLessThan %17 %55 %16
649                OpBranchConditional %41 %36 %37
650          %36 = OpLabel
651          %43 = OpIAdd %6 %55 %29
652          %46 = OpIAdd %6 %55 %29
653          %47 = OpAccessChain %7 %44 %46
654          %48 = OpLoad %6 %47
655          %50 = OpIAdd %6 %48 %49
656          %51 = OpAccessChain %7 %23 %43
657                OpStore %51 %50
658                OpBranch %38
659          %38 = OpLabel
660          %53 = OpIAdd %6 %55 %29
661                OpStore %34 %53
662                OpBranch %35
663          %37 = OpLabel
664                OpReturn
665                OpFunctionEnd
666     )";
667 
668   std::unique_ptr<IRContext> context =
669       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
670                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
671   Module* module = context->module();
672   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
673                              << text << std::endl;
674   Function& f = *module->begin();
675 
676   {
677     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
678     EXPECT_EQ(ld.NumLoops(), 2u);
679 
680     auto loops = ld.GetLoopsInBinaryLayoutOrder();
681 
682     LoopFusion fusion(context.get(), loops[0], loops[1]);
683     EXPECT_TRUE(fusion.AreCompatible());
684     EXPECT_FALSE(fusion.IsLegal());
685   }
686 }
687 
688 /*
689 Generated from the following GLSL + --eliminate-local-multi-store
690 
691 // 28
692 #version 440 core
693 void main() {
694   int[10] a;
695   int[10] b;
696 
697   int sum_0 = 0;
698 
699   // Illegal
700   for (int i = 0; i < 10; i++) {
701     sum_0 += a[i];
702   }
703   for (int j = 0; j < 10; j++) {
704     sum_0 += b[j];
705   }
706 }
707 
708 */
TEST_F(FusionIllegalTest,SameReductionVariable)709 TEST_F(FusionIllegalTest, SameReductionVariable) {
710   std::string text = R"(
711                OpCapability Shader
712           %1 = OpExtInstImport "GLSL.std.450"
713                OpMemoryModel Logical GLSL450
714                OpEntryPoint Fragment %4 "main"
715                OpExecutionMode %4 OriginUpperLeft
716                OpSource GLSL 440
717                OpName %4 "main"
718                OpName %8 "sum_0"
719                OpName %10 "i"
720                OpName %24 "a"
721                OpName %33 "j"
722                OpName %41 "b"
723           %2 = OpTypeVoid
724           %3 = OpTypeFunction %2
725           %6 = OpTypeInt 32 1
726           %7 = OpTypePointer Function %6
727           %9 = OpConstant %6 0
728          %17 = OpConstant %6 10
729          %18 = OpTypeBool
730          %20 = OpTypeInt 32 0
731          %21 = OpConstant %20 10
732          %22 = OpTypeArray %6 %21
733          %23 = OpTypePointer Function %22
734          %31 = OpConstant %6 1
735           %4 = OpFunction %2 None %3
736           %5 = OpLabel
737           %8 = OpVariable %7 Function
738          %10 = OpVariable %7 Function
739          %24 = OpVariable %23 Function
740          %33 = OpVariable %7 Function
741          %41 = OpVariable %23 Function
742                OpStore %8 %9
743                OpStore %10 %9
744                OpBranch %11
745          %11 = OpLabel
746          %52 = OpPhi %6 %9 %5 %29 %14
747          %49 = OpPhi %6 %9 %5 %32 %14
748                OpLoopMerge %13 %14 None
749                OpBranch %15
750          %15 = OpLabel
751          %19 = OpSLessThan %18 %49 %17
752                OpBranchConditional %19 %12 %13
753          %12 = OpLabel
754          %26 = OpAccessChain %7 %24 %49
755          %27 = OpLoad %6 %26
756          %29 = OpIAdd %6 %52 %27
757                OpStore %8 %29
758                OpBranch %14
759          %14 = OpLabel
760          %32 = OpIAdd %6 %49 %31
761                OpStore %10 %32
762                OpBranch %11
763          %13 = OpLabel
764                OpStore %33 %9
765                OpBranch %34
766          %34 = OpLabel
767          %51 = OpPhi %6 %52 %13 %46 %37
768          %50 = OpPhi %6 %9 %13 %48 %37
769                OpLoopMerge %36 %37 None
770                OpBranch %38
771          %38 = OpLabel
772          %40 = OpSLessThan %18 %50 %17
773                OpBranchConditional %40 %35 %36
774          %35 = OpLabel
775          %43 = OpAccessChain %7 %41 %50
776          %44 = OpLoad %6 %43
777          %46 = OpIAdd %6 %51 %44
778                OpStore %8 %46
779                OpBranch %37
780          %37 = OpLabel
781          %48 = OpIAdd %6 %50 %31
782                OpStore %33 %48
783                OpBranch %34
784          %36 = OpLabel
785                OpReturn
786                OpFunctionEnd
787     )";
788 
789   std::unique_ptr<IRContext> context =
790       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
791                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
792   Module* module = context->module();
793   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
794                              << text << std::endl;
795   Function& f = *module->begin();
796 
797   {
798     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
799     EXPECT_EQ(ld.NumLoops(), 2u);
800 
801     auto loops = ld.GetLoopsInBinaryLayoutOrder();
802 
803     LoopFusion fusion(context.get(), loops[0], loops[1]);
804     EXPECT_TRUE(fusion.AreCompatible());
805     EXPECT_FALSE(fusion.IsLegal());
806   }
807 }
808 
809 /*
810 Generated from the following GLSL + --eliminate-local-multi-store
811 
812 // 28
813 #version 440 core
814 void main() {
815   int[10] a;
816   int[10] b;
817 
818   int sum_0 = 0;
819 
820   // Illegal
821   for (int i = 0; i < 10; i++) {
822     sum_0 += a[i];
823   }
824   for (int j = 0; j < 10; j++) {
825     sum_0 += b[j];
826   }
827 }
828 
829 */
TEST_F(FusionIllegalTest,SameReductionVariableLCSSA)830 TEST_F(FusionIllegalTest, SameReductionVariableLCSSA) {
831   std::string text = R"(
832                OpCapability Shader
833           %1 = OpExtInstImport "GLSL.std.450"
834                OpMemoryModel Logical GLSL450
835                OpEntryPoint Fragment %4 "main"
836                OpExecutionMode %4 OriginUpperLeft
837                OpSource GLSL 440
838                OpName %4 "main"
839                OpName %8 "sum_0"
840                OpName %10 "i"
841                OpName %24 "a"
842                OpName %33 "j"
843                OpName %41 "b"
844           %2 = OpTypeVoid
845           %3 = OpTypeFunction %2
846           %6 = OpTypeInt 32 1
847           %7 = OpTypePointer Function %6
848           %9 = OpConstant %6 0
849          %17 = OpConstant %6 10
850          %18 = OpTypeBool
851          %20 = OpTypeInt 32 0
852          %21 = OpConstant %20 10
853          %22 = OpTypeArray %6 %21
854          %23 = OpTypePointer Function %22
855          %31 = OpConstant %6 1
856           %4 = OpFunction %2 None %3
857           %5 = OpLabel
858           %8 = OpVariable %7 Function
859          %10 = OpVariable %7 Function
860          %24 = OpVariable %23 Function
861          %33 = OpVariable %7 Function
862          %41 = OpVariable %23 Function
863                OpStore %8 %9
864                OpStore %10 %9
865                OpBranch %11
866          %11 = OpLabel
867          %52 = OpPhi %6 %9 %5 %29 %14
868          %49 = OpPhi %6 %9 %5 %32 %14
869                OpLoopMerge %13 %14 None
870                OpBranch %15
871          %15 = OpLabel
872          %19 = OpSLessThan %18 %49 %17
873                OpBranchConditional %19 %12 %13
874          %12 = OpLabel
875          %26 = OpAccessChain %7 %24 %49
876          %27 = OpLoad %6 %26
877          %29 = OpIAdd %6 %52 %27
878                OpStore %8 %29
879                OpBranch %14
880          %14 = OpLabel
881          %32 = OpIAdd %6 %49 %31
882                OpStore %10 %32
883                OpBranch %11
884          %13 = OpLabel
885                OpStore %33 %9
886                OpBranch %34
887          %34 = OpLabel
888          %51 = OpPhi %6 %52 %13 %46 %37
889          %50 = OpPhi %6 %9 %13 %48 %37
890                OpLoopMerge %36 %37 None
891                OpBranch %38
892          %38 = OpLabel
893          %40 = OpSLessThan %18 %50 %17
894                OpBranchConditional %40 %35 %36
895          %35 = OpLabel
896          %43 = OpAccessChain %7 %41 %50
897          %44 = OpLoad %6 %43
898          %46 = OpIAdd %6 %51 %44
899                OpStore %8 %46
900                OpBranch %37
901          %37 = OpLabel
902          %48 = OpIAdd %6 %50 %31
903                OpStore %33 %48
904                OpBranch %34
905          %36 = OpLabel
906                OpReturn
907                OpFunctionEnd
908     )";
909 
910   std::unique_ptr<IRContext> context =
911       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
912                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
913   Module* module = context->module();
914   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
915                              << text << std::endl;
916   Function& f = *module->begin();
917 
918   {
919     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
920     EXPECT_EQ(ld.NumLoops(), 2u);
921 
922     auto loops = ld.GetLoopsInBinaryLayoutOrder();
923 
924     LoopUtils utils_0(context.get(), loops[0]);
925     utils_0.MakeLoopClosedSSA();
926 
927     LoopFusion fusion(context.get(), loops[0], loops[1]);
928     EXPECT_TRUE(fusion.AreCompatible());
929     EXPECT_FALSE(fusion.IsLegal());
930   }
931 }
932 
933 /*
934 Generated from the following GLSL + --eliminate-local-multi-store
935 
936 // 30
937 #version 440 core
938 int x;
939 void main() {
940   int[10] a;
941   int[10] b;
942 
943   // Illegal, x is unknown.
944   for (int i = 0; i < 10; i++) {
945     a[x] = a[i];
946   }
947   for (int j = 0; j < 10; j++) {
948     a[j] = b[j];
949   }
950 }
951 
952 */
TEST_F(FusionIllegalTest,UnknownIndexVariable)953 TEST_F(FusionIllegalTest, UnknownIndexVariable) {
954   std::string text = R"(
955                OpCapability Shader
956           %1 = OpExtInstImport "GLSL.std.450"
957                OpMemoryModel Logical GLSL450
958                OpEntryPoint Fragment %4 "main"
959                OpExecutionMode %4 OriginUpperLeft
960                OpSource GLSL 440
961                OpName %4 "main"
962                OpName %8 "i"
963                OpName %23 "a"
964                OpName %25 "x"
965                OpName %34 "j"
966                OpName %43 "b"
967           %2 = OpTypeVoid
968           %3 = OpTypeFunction %2
969           %6 = OpTypeInt 32 1
970           %7 = OpTypePointer Function %6
971           %9 = OpConstant %6 0
972          %16 = OpConstant %6 10
973          %17 = OpTypeBool
974          %19 = OpTypeInt 32 0
975          %20 = OpConstant %19 10
976          %21 = OpTypeArray %6 %20
977          %22 = OpTypePointer Function %21
978          %24 = OpTypePointer Private %6
979          %25 = OpVariable %24 Private
980          %32 = OpConstant %6 1
981           %4 = OpFunction %2 None %3
982           %5 = OpLabel
983           %8 = OpVariable %7 Function
984          %23 = OpVariable %22 Function
985          %34 = OpVariable %7 Function
986          %43 = OpVariable %22 Function
987                OpStore %8 %9
988                OpBranch %10
989          %10 = OpLabel
990          %50 = OpPhi %6 %9 %5 %33 %13
991                OpLoopMerge %12 %13 None
992                OpBranch %14
993          %14 = OpLabel
994          %18 = OpSLessThan %17 %50 %16
995                OpBranchConditional %18 %11 %12
996          %11 = OpLabel
997          %26 = OpLoad %6 %25
998          %28 = OpAccessChain %7 %23 %50
999          %29 = OpLoad %6 %28
1000          %30 = OpAccessChain %7 %23 %26
1001                OpStore %30 %29
1002                OpBranch %13
1003          %13 = OpLabel
1004          %33 = OpIAdd %6 %50 %32
1005                OpStore %8 %33
1006                OpBranch %10
1007          %12 = OpLabel
1008                OpStore %34 %9
1009                OpBranch %35
1010          %35 = OpLabel
1011          %51 = OpPhi %6 %9 %12 %49 %38
1012                OpLoopMerge %37 %38 None
1013                OpBranch %39
1014          %39 = OpLabel
1015          %41 = OpSLessThan %17 %51 %16
1016                OpBranchConditional %41 %36 %37
1017          %36 = OpLabel
1018          %45 = OpAccessChain %7 %43 %51
1019          %46 = OpLoad %6 %45
1020          %47 = OpAccessChain %7 %23 %51
1021                OpStore %47 %46
1022                OpBranch %38
1023          %38 = OpLabel
1024          %49 = OpIAdd %6 %51 %32
1025                OpStore %34 %49
1026                OpBranch %35
1027          %37 = OpLabel
1028                OpReturn
1029                OpFunctionEnd
1030     )";
1031 
1032   std::unique_ptr<IRContext> context =
1033       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1034                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1035   Module* module = context->module();
1036   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1037                              << text << std::endl;
1038   Function& f = *module->begin();
1039 
1040   {
1041     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
1042     EXPECT_EQ(ld.NumLoops(), 2u);
1043 
1044     auto loops = ld.GetLoopsInBinaryLayoutOrder();
1045 
1046     LoopFusion fusion(context.get(), loops[0], loops[1]);
1047     EXPECT_TRUE(fusion.AreCompatible());
1048     EXPECT_FALSE(fusion.IsLegal());
1049   }
1050 }
1051 
1052 /*
1053 Generated from the following GLSL + --eliminate-local-multi-store
1054 
1055 #version 440 core
1056 void main() {
1057   int[10] a;
1058   int[10] b;
1059 
1060   int sum = 0;
1061 
1062   // Illegal, accumulator used for indexing.
1063   for (int i = 0; i < 10; i++) {
1064     sum += a[i];
1065     b[sum] = a[i];
1066   }
1067   for (int j = 0; j < 10; j++) {
1068     b[j] = b[j]+1;
1069   }
1070 }
1071 
1072 */
TEST_F(FusionIllegalTest,AccumulatorIndexing)1073 TEST_F(FusionIllegalTest, AccumulatorIndexing) {
1074   std::string text = R"(
1075                OpCapability Shader
1076           %1 = OpExtInstImport "GLSL.std.450"
1077                OpMemoryModel Logical GLSL450
1078                OpEntryPoint Fragment %4 "main"
1079                OpExecutionMode %4 OriginUpperLeft
1080                OpSource GLSL 440
1081                OpName %4 "main"
1082                OpName %8 "sum"
1083                OpName %10 "i"
1084                OpName %24 "a"
1085                OpName %30 "b"
1086                OpName %39 "j"
1087           %2 = OpTypeVoid
1088           %3 = OpTypeFunction %2
1089           %6 = OpTypeInt 32 1
1090           %7 = OpTypePointer Function %6
1091           %9 = OpConstant %6 0
1092          %17 = OpConstant %6 10
1093          %18 = OpTypeBool
1094          %20 = OpTypeInt 32 0
1095          %21 = OpConstant %20 10
1096          %22 = OpTypeArray %6 %21
1097          %23 = OpTypePointer Function %22
1098          %37 = OpConstant %6 1
1099           %4 = OpFunction %2 None %3
1100           %5 = OpLabel
1101           %8 = OpVariable %7 Function
1102          %10 = OpVariable %7 Function
1103          %24 = OpVariable %23 Function
1104          %30 = OpVariable %23 Function
1105          %39 = OpVariable %7 Function
1106                OpStore %8 %9
1107                OpStore %10 %9
1108                OpBranch %11
1109          %11 = OpLabel
1110          %57 = OpPhi %6 %9 %5 %29 %14
1111          %55 = OpPhi %6 %9 %5 %38 %14
1112                OpLoopMerge %13 %14 None
1113                OpBranch %15
1114          %15 = OpLabel
1115          %19 = OpSLessThan %18 %55 %17
1116                OpBranchConditional %19 %12 %13
1117          %12 = OpLabel
1118          %26 = OpAccessChain %7 %24 %55
1119          %27 = OpLoad %6 %26
1120          %29 = OpIAdd %6 %57 %27
1121                OpStore %8 %29
1122          %33 = OpAccessChain %7 %24 %55
1123          %34 = OpLoad %6 %33
1124          %35 = OpAccessChain %7 %30 %29
1125                OpStore %35 %34
1126                OpBranch %14
1127          %14 = OpLabel
1128          %38 = OpIAdd %6 %55 %37
1129                OpStore %10 %38
1130                OpBranch %11
1131          %13 = OpLabel
1132                OpStore %39 %9
1133                OpBranch %40
1134          %40 = OpLabel
1135          %56 = OpPhi %6 %9 %13 %54 %43
1136                OpLoopMerge %42 %43 None
1137                OpBranch %44
1138          %44 = OpLabel
1139          %46 = OpSLessThan %18 %56 %17
1140                OpBranchConditional %46 %41 %42
1141          %41 = OpLabel
1142          %49 = OpAccessChain %7 %30 %56
1143          %50 = OpLoad %6 %49
1144          %51 = OpIAdd %6 %50 %37
1145          %52 = OpAccessChain %7 %30 %56
1146                OpStore %52 %51
1147                OpBranch %43
1148          %43 = OpLabel
1149          %54 = OpIAdd %6 %56 %37
1150                OpStore %39 %54
1151                OpBranch %40
1152          %42 = OpLabel
1153                OpReturn
1154                OpFunctionEnd
1155     )";
1156 
1157   std::unique_ptr<IRContext> context =
1158       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1159                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1160   Module* module = context->module();
1161   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1162                              << text << std::endl;
1163   Function& f = *module->begin();
1164 
1165   {
1166     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
1167     EXPECT_EQ(ld.NumLoops(), 2u);
1168 
1169     auto loops = ld.GetLoopsInBinaryLayoutOrder();
1170 
1171     LoopFusion fusion(context.get(), loops[0], loops[1]);
1172     EXPECT_TRUE(fusion.AreCompatible());
1173     EXPECT_FALSE(fusion.IsLegal());
1174   }
1175 }
1176 
1177 /*
1178 Generated from the following GLSL + --eliminate-local-multi-store
1179 
1180 // 33
1181 #version 440 core
1182 void main() {
1183   int[10] a;
1184   int[10] b;
1185 
1186   // Illegal, barrier.
1187   for (int i = 0; i < 10; i++) {
1188     a[i] = a[i] * 2;
1189     memoryBarrier();
1190   }
1191   for (int j = 0; j < 10; j++) {
1192     b[j] = b[j] + 1;
1193   }
1194 }
1195 
1196 */
TEST_F(FusionIllegalTest,Barrier)1197 TEST_F(FusionIllegalTest, Barrier) {
1198   std::string text = R"(
1199                OpCapability Shader
1200           %1 = OpExtInstImport "GLSL.std.450"
1201                OpMemoryModel Logical GLSL450
1202                OpEntryPoint Fragment %4 "main"
1203                OpExecutionMode %4 OriginUpperLeft
1204                OpSource GLSL 440
1205                OpName %4 "main"
1206                OpName %8 "i"
1207                OpName %23 "a"
1208                OpName %36 "j"
1209                OpName %44 "b"
1210           %2 = OpTypeVoid
1211           %3 = OpTypeFunction %2
1212           %6 = OpTypeInt 32 1
1213           %7 = OpTypePointer Function %6
1214           %9 = OpConstant %6 0
1215          %16 = OpConstant %6 10
1216          %17 = OpTypeBool
1217          %19 = OpTypeInt 32 0
1218          %20 = OpConstant %19 10
1219          %21 = OpTypeArray %6 %20
1220          %22 = OpTypePointer Function %21
1221          %28 = OpConstant %6 2
1222          %31 = OpConstant %19 1
1223          %32 = OpConstant %19 3400
1224          %34 = OpConstant %6 1
1225           %4 = OpFunction %2 None %3
1226           %5 = OpLabel
1227           %8 = OpVariable %7 Function
1228          %23 = OpVariable %22 Function
1229          %36 = OpVariable %7 Function
1230          %44 = OpVariable %22 Function
1231                OpStore %8 %9
1232                OpBranch %10
1233          %10 = OpLabel
1234          %53 = OpPhi %6 %9 %5 %35 %13
1235                OpLoopMerge %12 %13 None
1236                OpBranch %14
1237          %14 = OpLabel
1238          %18 = OpSLessThan %17 %53 %16
1239                OpBranchConditional %18 %11 %12
1240          %11 = OpLabel
1241          %26 = OpAccessChain %7 %23 %53
1242          %27 = OpLoad %6 %26
1243          %29 = OpIMul %6 %27 %28
1244          %30 = OpAccessChain %7 %23 %53
1245                OpStore %30 %29
1246                OpMemoryBarrier %31 %32
1247                OpBranch %13
1248          %13 = OpLabel
1249          %35 = OpIAdd %6 %53 %34
1250                OpStore %8 %35
1251                OpBranch %10
1252          %12 = OpLabel
1253                OpStore %36 %9
1254                OpBranch %37
1255          %37 = OpLabel
1256          %54 = OpPhi %6 %9 %12 %52 %40
1257                OpLoopMerge %39 %40 None
1258                OpBranch %41
1259          %41 = OpLabel
1260          %43 = OpSLessThan %17 %54 %16
1261                OpBranchConditional %43 %38 %39
1262          %38 = OpLabel
1263          %47 = OpAccessChain %7 %44 %54
1264          %48 = OpLoad %6 %47
1265          %49 = OpIAdd %6 %48 %34
1266          %50 = OpAccessChain %7 %44 %54
1267                OpStore %50 %49
1268                OpBranch %40
1269          %40 = OpLabel
1270          %52 = OpIAdd %6 %54 %34
1271                OpStore %36 %52
1272                OpBranch %37
1273          %39 = OpLabel
1274                OpReturn
1275                OpFunctionEnd
1276     )";
1277 
1278   std::unique_ptr<IRContext> context =
1279       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1280                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1281   Module* module = context->module();
1282   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1283                              << text << std::endl;
1284   Function& f = *module->begin();
1285 
1286   {
1287     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
1288     EXPECT_EQ(ld.NumLoops(), 2u);
1289 
1290     auto loops = ld.GetLoopsInBinaryLayoutOrder();
1291 
1292     LoopFusion fusion(context.get(), loops[0], loops[1]);
1293     EXPECT_TRUE(fusion.AreCompatible());
1294     EXPECT_FALSE(fusion.IsLegal());
1295   }
1296 }
1297 
1298 /*
1299 Generated from the following GLSL + --eliminate-local-multi-store
1300 
1301 #version 440 core
1302 struct TestStruct {
1303   int[10] a;
1304   int b;
1305 };
1306 
1307 void main() {
1308   TestStruct test_0;
1309   TestStruct test_1;
1310 
1311   for (int i = 0; i < 10; i++) {
1312     test_0.a[i] = i;
1313   }
1314   for (int j = 0; j < 10; j++) {
1315     test_0 = test_1;
1316   }
1317 }
1318 
1319 */
TEST_F(FusionIllegalTest,ArrayInStruct)1320 TEST_F(FusionIllegalTest, ArrayInStruct) {
1321   std::string text = R"(
1322                OpCapability Shader
1323           %1 = OpExtInstImport "GLSL.std.450"
1324                OpMemoryModel Logical GLSL450
1325                OpEntryPoint Fragment %4 "main"
1326                OpExecutionMode %4 OriginUpperLeft
1327                OpSource GLSL 440
1328                OpName %4 "main"
1329                OpName %8 "i"
1330                OpName %22 "TestStruct"
1331                OpMemberName %22 0 "a"
1332                OpMemberName %22 1 "b"
1333                OpName %24 "test_0"
1334                OpName %31 "j"
1335                OpName %39 "test_1"
1336           %2 = OpTypeVoid
1337           %3 = OpTypeFunction %2
1338           %6 = OpTypeInt 32 1
1339           %7 = OpTypePointer Function %6
1340           %9 = OpConstant %6 0
1341          %16 = OpConstant %6 10
1342          %17 = OpTypeBool
1343          %19 = OpTypeInt 32 0
1344          %20 = OpConstant %19 10
1345          %21 = OpTypeArray %6 %20
1346          %22 = OpTypeStruct %21 %6
1347          %23 = OpTypePointer Function %22
1348          %29 = OpConstant %6 1
1349          %47 = OpUndef %22
1350           %4 = OpFunction %2 None %3
1351           %5 = OpLabel
1352           %8 = OpVariable %7 Function
1353          %24 = OpVariable %23 Function
1354          %31 = OpVariable %7 Function
1355          %39 = OpVariable %23 Function
1356                OpStore %8 %9
1357                OpBranch %10
1358          %10 = OpLabel
1359          %43 = OpPhi %6 %9 %5 %30 %13
1360                OpLoopMerge %12 %13 None
1361                OpBranch %14
1362          %14 = OpLabel
1363          %18 = OpSLessThan %17 %43 %16
1364                OpBranchConditional %18 %11 %12
1365          %11 = OpLabel
1366          %27 = OpAccessChain %7 %24 %9 %43
1367                OpStore %27 %43
1368                OpBranch %13
1369          %13 = OpLabel
1370          %30 = OpIAdd %6 %43 %29
1371                OpStore %8 %30
1372                OpBranch %10
1373          %12 = OpLabel
1374                OpStore %31 %9
1375                OpBranch %32
1376          %32 = OpLabel
1377          %44 = OpPhi %6 %9 %12 %42 %35
1378                OpLoopMerge %34 %35 None
1379                OpBranch %36
1380          %36 = OpLabel
1381          %38 = OpSLessThan %17 %44 %16
1382                OpBranchConditional %38 %33 %34
1383          %33 = OpLabel
1384                OpStore %24 %47
1385                OpBranch %35
1386          %35 = OpLabel
1387          %42 = OpIAdd %6 %44 %29
1388                OpStore %31 %42
1389                OpBranch %32
1390          %34 = OpLabel
1391                OpReturn
1392                OpFunctionEnd
1393     )";
1394 
1395   std::unique_ptr<IRContext> context =
1396       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1397                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1398   Module* module = context->module();
1399   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1400                              << text << std::endl;
1401   Function& f = *module->begin();
1402 
1403   {
1404     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
1405     EXPECT_EQ(ld.NumLoops(), 2u);
1406 
1407     auto loops = ld.GetLoopsInBinaryLayoutOrder();
1408 
1409     LoopFusion fusion(context.get(), loops[0], loops[1]);
1410     EXPECT_TRUE(fusion.AreCompatible());
1411     EXPECT_FALSE(fusion.IsLegal());
1412   }
1413 }
1414 
1415 /*
1416 Generated from the following GLSL + --eliminate-local-multi-store
1417 
1418 #version 450
1419 
1420 struct P {float x,y,z;};
1421 uniform G { int a; P b[2]; int c; } g;
1422 layout(location = 0) out float o;
1423 
1424 void main()
1425 {
1426   P p[2];
1427   for (int i = 0; i < 2; ++i) {
1428     p = g.b;
1429   }
1430   for (int j = 0; j < 2; ++j) {
1431     o = p[g.a].x;
1432   }
1433 }
1434 
1435 */
TEST_F(FusionIllegalTest,NestedAccessChain)1436 TEST_F(FusionIllegalTest, NestedAccessChain) {
1437   std::string text = R"(
1438                OpCapability Shader
1439           %1 = OpExtInstImport "GLSL.std.450"
1440                OpMemoryModel Logical GLSL450
1441                OpEntryPoint Fragment %4 "main" %64
1442                OpExecutionMode %4 OriginUpperLeft
1443                OpSource GLSL 450
1444                OpName %4 "main"
1445                OpName %8 "i"
1446                OpName %20 "P"
1447                OpMemberName %20 0 "x"
1448                OpMemberName %20 1 "y"
1449                OpMemberName %20 2 "z"
1450                OpName %25 "p"
1451                OpName %26 "P"
1452                OpMemberName %26 0 "x"
1453                OpMemberName %26 1 "y"
1454                OpMemberName %26 2 "z"
1455                OpName %28 "G"
1456                OpMemberName %28 0 "a"
1457                OpMemberName %28 1 "b"
1458                OpMemberName %28 2 "c"
1459                OpName %30 "g"
1460                OpName %55 "j"
1461                OpName %64 "o"
1462                OpMemberDecorate %26 0 Offset 0
1463                OpMemberDecorate %26 1 Offset 4
1464                OpMemberDecorate %26 2 Offset 8
1465                OpDecorate %27 ArrayStride 16
1466                OpMemberDecorate %28 0 Offset 0
1467                OpMemberDecorate %28 1 Offset 16
1468                OpMemberDecorate %28 2 Offset 48
1469                OpDecorate %28 Block
1470                OpDecorate %30 DescriptorSet 0
1471                OpDecorate %64 Location 0
1472           %2 = OpTypeVoid
1473           %3 = OpTypeFunction %2
1474           %6 = OpTypeInt 32 1
1475           %7 = OpTypePointer Function %6
1476           %9 = OpConstant %6 0
1477          %16 = OpConstant %6 2
1478          %17 = OpTypeBool
1479          %19 = OpTypeFloat 32
1480          %20 = OpTypeStruct %19 %19 %19
1481          %21 = OpTypeInt 32 0
1482          %22 = OpConstant %21 2
1483          %23 = OpTypeArray %20 %22
1484          %24 = OpTypePointer Function %23
1485          %26 = OpTypeStruct %19 %19 %19
1486          %27 = OpTypeArray %26 %22
1487          %28 = OpTypeStruct %6 %27 %6
1488          %29 = OpTypePointer Uniform %28
1489          %30 = OpVariable %29 Uniform
1490          %31 = OpConstant %6 1
1491          %32 = OpTypePointer Uniform %27
1492          %36 = OpTypePointer Function %20
1493          %39 = OpTypePointer Function %19
1494          %63 = OpTypePointer Output %19
1495          %64 = OpVariable %63 Output
1496          %65 = OpTypePointer Uniform %6
1497           %4 = OpFunction %2 None %3
1498           %5 = OpLabel
1499           %8 = OpVariable %7 Function
1500          %25 = OpVariable %24 Function
1501          %55 = OpVariable %7 Function
1502                OpStore %8 %9
1503                OpBranch %10
1504          %10 = OpLabel
1505          %72 = OpPhi %6 %9 %5 %54 %13
1506                OpLoopMerge %12 %13 None
1507                OpBranch %14
1508          %14 = OpLabel
1509          %18 = OpSLessThan %17 %72 %16
1510                OpBranchConditional %18 %11 %12
1511          %11 = OpLabel
1512          %33 = OpAccessChain %32 %30 %31
1513          %34 = OpLoad %27 %33
1514          %35 = OpCompositeExtract %26 %34 0
1515          %37 = OpAccessChain %36 %25 %9
1516          %38 = OpCompositeExtract %19 %35 0
1517          %40 = OpAccessChain %39 %37 %9
1518                OpStore %40 %38
1519          %41 = OpCompositeExtract %19 %35 1
1520          %42 = OpAccessChain %39 %37 %31
1521                OpStore %42 %41
1522          %43 = OpCompositeExtract %19 %35 2
1523          %44 = OpAccessChain %39 %37 %16
1524                OpStore %44 %43
1525          %45 = OpCompositeExtract %26 %34 1
1526          %46 = OpAccessChain %36 %25 %31
1527          %47 = OpCompositeExtract %19 %45 0
1528          %48 = OpAccessChain %39 %46 %9
1529                OpStore %48 %47
1530          %49 = OpCompositeExtract %19 %45 1
1531          %50 = OpAccessChain %39 %46 %31
1532                OpStore %50 %49
1533          %51 = OpCompositeExtract %19 %45 2
1534          %52 = OpAccessChain %39 %46 %16
1535                OpStore %52 %51
1536                OpBranch %13
1537          %13 = OpLabel
1538          %54 = OpIAdd %6 %72 %31
1539                OpStore %8 %54
1540                OpBranch %10
1541          %12 = OpLabel
1542                OpStore %55 %9
1543                OpBranch %56
1544          %56 = OpLabel
1545          %73 = OpPhi %6 %9 %12 %71 %59
1546                OpLoopMerge %58 %59 None
1547                OpBranch %60
1548          %60 = OpLabel
1549          %62 = OpSLessThan %17 %73 %16
1550                OpBranchConditional %62 %57 %58
1551          %57 = OpLabel
1552          %66 = OpAccessChain %65 %30 %9
1553          %67 = OpLoad %6 %66
1554          %68 = OpAccessChain %39 %25 %67 %9
1555          %69 = OpLoad %19 %68
1556                OpStore %64 %69
1557                OpBranch %59
1558          %59 = OpLabel
1559          %71 = OpIAdd %6 %73 %31
1560                OpStore %55 %71
1561                OpBranch %56
1562          %58 = OpLabel
1563                OpReturn
1564                OpFunctionEnd
1565     )";
1566 
1567   std::unique_ptr<IRContext> context =
1568       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1569                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1570   Module* module = context->module();
1571   EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
1572                              << text << std::endl;
1573   Function& f = *module->begin();
1574 
1575   {
1576     LoopDescriptor& ld = *context->GetLoopDescriptor(&f);
1577     EXPECT_EQ(ld.NumLoops(), 2u);
1578 
1579     auto loops = ld.GetLoopsInBinaryLayoutOrder();
1580 
1581     LoopFusion fusion(context.get(), loops[0], loops[1]);
1582     EXPECT_TRUE(fusion.AreCompatible());
1583     EXPECT_FALSE(fusion.IsLegal());
1584   }
1585 }
1586 
1587 }  // namespace
1588 }  // namespace opt
1589 }  // namespace spvtools
1590