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