• 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 <string>
16 
17 #include "effcee/effcee.h"
18 #include "gmock/gmock.h"
19 #include "test/opt/pass_fixture.h"
20 
21 namespace spvtools {
22 namespace opt {
23 namespace {
24 
25 using FusionPassTest = PassTest<::testing::Test>;
26 
27 /*
28 Generated from the following GLSL + --eliminate-local-multi-store
29 
30 #version 440 core
31 void main() {
32   int[10] a;
33   int[10] b;
34   for (int i = 0; i < 10; i++) {
35     a[i] = a[i]*2;
36   }
37   for (int i = 0; i < 10; i++) {
38     b[i] = a[i]+2;
39   }
40 }
41 
42 */
TEST_F(FusionPassTest,SimpleFusion)43 TEST_F(FusionPassTest, SimpleFusion) {
44   const std::string text = R"(
45 ; CHECK: OpPhi
46 ; CHECK: OpLoad
47 ; CHECK: OpStore
48 ; CHECK-NOT: OpPhi
49 ; CHECK: OpLoad
50 ; CHECK: OpStore
51 
52                OpCapability Shader
53           %1 = OpExtInstImport "GLSL.std.450"
54                OpMemoryModel Logical GLSL450
55                OpEntryPoint Fragment %4 "main"
56                OpExecutionMode %4 OriginUpperLeft
57                OpSource GLSL 440
58                OpName %4 "main"
59                OpName %8 "i"
60                OpName %23 "a"
61                OpName %34 "i"
62                OpName %42 "b"
63           %2 = OpTypeVoid
64           %3 = OpTypeFunction %2
65           %6 = OpTypeInt 32 1
66           %7 = OpTypePointer Function %6
67           %9 = OpConstant %6 0
68          %16 = OpConstant %6 10
69          %17 = OpTypeBool
70          %19 = OpTypeInt 32 0
71          %20 = OpConstant %19 10
72          %21 = OpTypeArray %6 %20
73          %22 = OpTypePointer Function %21
74          %28 = OpConstant %6 2
75          %32 = OpConstant %6 1
76           %4 = OpFunction %2 None %3
77           %5 = OpLabel
78           %8 = OpVariable %7 Function
79          %23 = OpVariable %22 Function
80          %34 = OpVariable %7 Function
81          %42 = OpVariable %22 Function
82                OpStore %8 %9
83                OpBranch %10
84          %10 = OpLabel
85          %51 = OpPhi %6 %9 %5 %33 %13
86                OpLoopMerge %12 %13 None
87                OpBranch %14
88          %14 = OpLabel
89          %18 = OpSLessThan %17 %51 %16
90                OpBranchConditional %18 %11 %12
91          %11 = OpLabel
92          %26 = OpAccessChain %7 %23 %51
93          %27 = OpLoad %6 %26
94          %29 = OpIMul %6 %27 %28
95          %30 = OpAccessChain %7 %23 %51
96                OpStore %30 %29
97                OpBranch %13
98          %13 = OpLabel
99          %33 = OpIAdd %6 %51 %32
100                OpStore %8 %33
101                OpBranch %10
102          %12 = OpLabel
103                OpStore %34 %9
104                OpBranch %35
105          %35 = OpLabel
106          %52 = OpPhi %6 %9 %12 %50 %38
107                OpLoopMerge %37 %38 None
108                OpBranch %39
109          %39 = OpLabel
110          %41 = OpSLessThan %17 %52 %16
111                OpBranchConditional %41 %36 %37
112          %36 = OpLabel
113          %45 = OpAccessChain %7 %23 %52
114          %46 = OpLoad %6 %45
115          %47 = OpIAdd %6 %46 %28
116          %48 = OpAccessChain %7 %42 %52
117                OpStore %48 %47
118                OpBranch %38
119          %38 = OpLabel
120          %50 = OpIAdd %6 %52 %32
121                OpStore %34 %50
122                OpBranch %35
123          %37 = OpLabel
124                OpReturn
125                OpFunctionEnd
126   )";
127 
128   SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
129 }
130 
131 /*
132 Generated from the following GLSL + --eliminate-local-multi-store
133 
134 #version 440 core
135 void main() {
136   int[10] a;
137   int[10] b;
138   int[10] c;
139   for (int i = 0; i < 10; i++) {
140     a[i] = b[i] + 1;
141   }
142   for (int i = 0; i < 10; i++) {
143     c[i] = a[i] + 2;
144   }
145   for (int i = 0; i < 10; i++) {
146     b[i] = c[i] + 10;
147   }
148 }
149 
150 */
TEST_F(FusionPassTest,ThreeLoopsFused)151 TEST_F(FusionPassTest, ThreeLoopsFused) {
152   const std::string text = R"(
153 ; CHECK: OpPhi
154 ; CHECK: OpLoad
155 ; CHECK: OpStore
156 ; CHECK-NOT: OpPhi
157 ; CHECK: OpLoad
158 ; CHECK: OpStore
159 ; CHECK-NOT: OpPhi
160 ; CHECK: OpLoad
161 ; CHECK: OpStore
162 
163                OpCapability Shader
164           %1 = OpExtInstImport "GLSL.std.450"
165                OpMemoryModel Logical GLSL450
166                OpEntryPoint Fragment %4 "main"
167                OpExecutionMode %4 OriginUpperLeft
168                OpSource GLSL 440
169                OpName %4 "main"
170                OpName %8 "i"
171                OpName %23 "a"
172                OpName %25 "b"
173                OpName %34 "i"
174                OpName %42 "c"
175                OpName %52 "i"
176           %2 = OpTypeVoid
177           %3 = OpTypeFunction %2
178           %6 = OpTypeInt 32 1
179           %7 = OpTypePointer Function %6
180           %9 = OpConstant %6 0
181          %16 = OpConstant %6 10
182          %17 = OpTypeBool
183          %19 = OpTypeInt 32 0
184          %20 = OpConstant %19 10
185          %21 = OpTypeArray %6 %20
186          %22 = OpTypePointer Function %21
187          %29 = OpConstant %6 1
188          %47 = OpConstant %6 2
189           %4 = OpFunction %2 None %3
190           %5 = OpLabel
191           %8 = OpVariable %7 Function
192          %23 = OpVariable %22 Function
193          %25 = OpVariable %22 Function
194          %34 = OpVariable %7 Function
195          %42 = OpVariable %22 Function
196          %52 = OpVariable %7 Function
197                OpStore %8 %9
198                OpBranch %10
199          %10 = OpLabel
200          %68 = OpPhi %6 %9 %5 %33 %13
201                OpLoopMerge %12 %13 None
202                OpBranch %14
203          %14 = OpLabel
204          %18 = OpSLessThan %17 %68 %16
205                OpBranchConditional %18 %11 %12
206          %11 = OpLabel
207          %27 = OpAccessChain %7 %25 %68
208          %28 = OpLoad %6 %27
209          %30 = OpIAdd %6 %28 %29
210          %31 = OpAccessChain %7 %23 %68
211                OpStore %31 %30
212                OpBranch %13
213          %13 = OpLabel
214          %33 = OpIAdd %6 %68 %29
215                OpStore %8 %33
216                OpBranch %10
217          %12 = OpLabel
218                OpStore %34 %9
219                OpBranch %35
220          %35 = OpLabel
221          %69 = OpPhi %6 %9 %12 %51 %38
222                OpLoopMerge %37 %38 None
223                OpBranch %39
224          %39 = OpLabel
225          %41 = OpSLessThan %17 %69 %16
226                OpBranchConditional %41 %36 %37
227          %36 = OpLabel
228          %45 = OpAccessChain %7 %23 %69
229          %46 = OpLoad %6 %45
230          %48 = OpIAdd %6 %46 %47
231          %49 = OpAccessChain %7 %42 %69
232                OpStore %49 %48
233                OpBranch %38
234          %38 = OpLabel
235          %51 = OpIAdd %6 %69 %29
236                OpStore %34 %51
237                OpBranch %35
238          %37 = OpLabel
239                OpStore %52 %9
240                OpBranch %53
241          %53 = OpLabel
242          %70 = OpPhi %6 %9 %37 %67 %56
243                OpLoopMerge %55 %56 None
244                OpBranch %57
245          %57 = OpLabel
246          %59 = OpSLessThan %17 %70 %16
247                OpBranchConditional %59 %54 %55
248          %54 = OpLabel
249          %62 = OpAccessChain %7 %42 %70
250          %63 = OpLoad %6 %62
251          %64 = OpIAdd %6 %63 %16
252          %65 = OpAccessChain %7 %25 %70
253                OpStore %65 %64
254                OpBranch %56
255          %56 = OpLabel
256          %67 = OpIAdd %6 %70 %29
257                OpStore %52 %67
258                OpBranch %53
259          %55 = OpLabel
260                OpReturn
261                OpFunctionEnd
262 
263   )";
264 
265   SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
266 }
267 
268 /*
269 Generated from the following GLSL + --eliminate-local-multi-store
270 
271 #version 440 core
272 void main() {
273   int[10][10] a;
274   int[10][10] b;
275   int[10][10] c;
276   // Legal both
277   for (int i = 0; i < 10; i++) {
278     for (int j = 0; j < 10; j++) {
279       c[i][j] = a[i][j] + 2;
280     }
281   }
282   for (int i = 0; i < 10; i++) {
283     for (int j = 0; j < 10; j++) {
284       b[i][j] = c[i][j] + 10;
285     }
286   }
287 }
288 
289 */
TEST_F(FusionPassTest,NestedLoopsFused)290 TEST_F(FusionPassTest, NestedLoopsFused) {
291   const std::string text = R"(
292 ; CHECK: OpPhi
293 ; CHECK: OpPhi
294 ; CHECK: OpLoad
295 ; CHECK: OpStore
296 ; CHECK-NOT: OpPhi
297 ; CHECK: OpLoad
298 ; CHECK: OpStore
299 
300                OpCapability Shader
301           %1 = OpExtInstImport "GLSL.std.450"
302                OpMemoryModel Logical GLSL450
303                OpEntryPoint Fragment %4 "main"
304                OpExecutionMode %4 OriginUpperLeft
305                OpSource GLSL 440
306                OpName %4 "main"
307                OpName %8 "i"
308                OpName %19 "j"
309                OpName %32 "c"
310                OpName %35 "a"
311                OpName %48 "i"
312                OpName %56 "j"
313                OpName %64 "b"
314           %2 = OpTypeVoid
315           %3 = OpTypeFunction %2
316           %6 = OpTypeInt 32 1
317           %7 = OpTypePointer Function %6
318           %9 = OpConstant %6 0
319          %16 = OpConstant %6 10
320          %17 = OpTypeBool
321          %27 = OpTypeInt 32 0
322          %28 = OpConstant %27 10
323          %29 = OpTypeArray %6 %28
324          %30 = OpTypeArray %29 %28
325          %31 = OpTypePointer Function %30
326          %40 = OpConstant %6 2
327          %44 = OpConstant %6 1
328           %4 = OpFunction %2 None %3
329           %5 = OpLabel
330           %8 = OpVariable %7 Function
331          %19 = OpVariable %7 Function
332          %32 = OpVariable %31 Function
333          %35 = OpVariable %31 Function
334          %48 = OpVariable %7 Function
335          %56 = OpVariable %7 Function
336          %64 = OpVariable %31 Function
337                OpStore %8 %9
338                OpBranch %10
339          %10 = OpLabel
340          %77 = OpPhi %6 %9 %5 %47 %13
341                OpLoopMerge %12 %13 None
342                OpBranch %14
343          %14 = OpLabel
344          %18 = OpSLessThan %17 %77 %16
345                OpBranchConditional %18 %11 %12
346          %11 = OpLabel
347                OpStore %19 %9
348                OpBranch %20
349          %20 = OpLabel
350          %81 = OpPhi %6 %9 %11 %45 %23
351                OpLoopMerge %22 %23 None
352                OpBranch %24
353          %24 = OpLabel
354          %26 = OpSLessThan %17 %81 %16
355                OpBranchConditional %26 %21 %22
356          %21 = OpLabel
357          %38 = OpAccessChain %7 %35 %77 %81
358          %39 = OpLoad %6 %38
359          %41 = OpIAdd %6 %39 %40
360          %42 = OpAccessChain %7 %32 %77 %81
361                OpStore %42 %41
362                OpBranch %23
363          %23 = OpLabel
364          %45 = OpIAdd %6 %81 %44
365                OpStore %19 %45
366                OpBranch %20
367          %22 = OpLabel
368                OpBranch %13
369          %13 = OpLabel
370          %47 = OpIAdd %6 %77 %44
371                OpStore %8 %47
372                OpBranch %10
373          %12 = OpLabel
374                OpStore %48 %9
375                OpBranch %49
376          %49 = OpLabel
377          %78 = OpPhi %6 %9 %12 %76 %52
378                OpLoopMerge %51 %52 None
379                OpBranch %53
380          %53 = OpLabel
381          %55 = OpSLessThan %17 %78 %16
382                OpBranchConditional %55 %50 %51
383          %50 = OpLabel
384                OpStore %56 %9
385                OpBranch %57
386          %57 = OpLabel
387          %79 = OpPhi %6 %9 %50 %74 %60
388                OpLoopMerge %59 %60 None
389                OpBranch %61
390          %61 = OpLabel
391          %63 = OpSLessThan %17 %79 %16
392                OpBranchConditional %63 %58 %59
393          %58 = OpLabel
394          %69 = OpAccessChain %7 %32 %78 %79
395          %70 = OpLoad %6 %69
396          %71 = OpIAdd %6 %70 %16
397          %72 = OpAccessChain %7 %64 %78 %79
398                OpStore %72 %71
399                OpBranch %60
400          %60 = OpLabel
401          %74 = OpIAdd %6 %79 %44
402                OpStore %56 %74
403                OpBranch %57
404          %59 = OpLabel
405                OpBranch %52
406          %52 = OpLabel
407          %76 = OpIAdd %6 %78 %44
408                OpStore %48 %76
409                OpBranch %49
410          %51 = OpLabel
411                OpReturn
412                OpFunctionEnd
413   )";
414 
415   SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
416 }
417 
418 /*
419 Generated from the following GLSL + --eliminate-local-multi-store
420 
421 #version 440 core
422 void main() {
423   // Can't fuse, different step
424   for (int i = 0; i < 10; i++) {}
425   for (int j = 0; j < 10; j=j+2) {}
426 }
427 
428 */
TEST_F(FusionPassTest,Incompatible)429 TEST_F(FusionPassTest, Incompatible) {
430   const std::string text = R"(
431 ; CHECK: OpPhi
432 ; CHECK-NEXT: OpLoopMerge
433 ; CHECK: OpPhi
434 ; CHECK-NEXT: OpLoopMerge
435 
436                OpCapability Shader
437           %1 = OpExtInstImport "GLSL.std.450"
438                OpMemoryModel Logical GLSL450
439                OpEntryPoint Fragment %4 "main"
440                OpExecutionMode %4 OriginUpperLeft
441                OpSource GLSL 440
442                OpName %4 "main"
443                OpName %8 "i"
444                OpName %22 "j"
445           %2 = OpTypeVoid
446           %3 = OpTypeFunction %2
447           %6 = OpTypeInt 32 1
448           %7 = OpTypePointer Function %6
449           %9 = OpConstant %6 0
450          %16 = OpConstant %6 10
451          %17 = OpTypeBool
452          %20 = OpConstant %6 1
453          %31 = OpConstant %6 2
454           %4 = OpFunction %2 None %3
455           %5 = OpLabel
456           %8 = OpVariable %7 Function
457          %22 = OpVariable %7 Function
458                OpStore %8 %9
459                OpBranch %10
460          %10 = OpLabel
461          %33 = OpPhi %6 %9 %5 %21 %13
462                OpLoopMerge %12 %13 None
463                OpBranch %14
464          %14 = OpLabel
465          %18 = OpSLessThan %17 %33 %16
466                OpBranchConditional %18 %11 %12
467          %11 = OpLabel
468                OpBranch %13
469          %13 = OpLabel
470          %21 = OpIAdd %6 %33 %20
471                OpStore %8 %21
472                OpBranch %10
473          %12 = OpLabel
474                OpStore %22 %9
475                OpBranch %23
476          %23 = OpLabel
477          %34 = OpPhi %6 %9 %12 %32 %26
478                OpLoopMerge %25 %26 None
479                OpBranch %27
480          %27 = OpLabel
481          %29 = OpSLessThan %17 %34 %16
482                OpBranchConditional %29 %24 %25
483          %24 = OpLabel
484                OpBranch %26
485          %26 = OpLabel
486          %32 = OpIAdd %6 %34 %31
487                OpStore %22 %32
488                OpBranch %23
489          %25 = OpLabel
490                OpReturn
491                OpFunctionEnd
492   )";
493 
494   SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
495 }
496 
497 /*
498 Generated from the following GLSL + --eliminate-local-multi-store
499 
500 #version 440 core
501 void main() {
502   int[10] a;
503   int[10] b;
504   int[10] c;
505   // Illegal, loop-independent dependence will become a
506   // backward loop-carried antidependence
507   for (int i = 0; i < 10; i++) {
508     a[i] = b[i] + 1;
509   }
510   for (int i = 0; i < 10; i++) {
511     c[i] = a[i+1] + 2;
512   }
513 }
514 
515 */
TEST_F(FusionPassTest,Illegal)516 TEST_F(FusionPassTest, Illegal) {
517   std::string text = R"(
518 ; CHECK: OpPhi
519 ; CHECK-NEXT: OpLoopMerge
520 ; CHECK: OpLoad
521 ; CHECK: OpStore
522 ; CHECK: OpPhi
523 ; CHECK-NEXT: OpLoopMerge
524 ; CHECK: OpLoad
525 ; CHECK: OpStore
526 
527                OpCapability Shader
528           %1 = OpExtInstImport "GLSL.std.450"
529                OpMemoryModel Logical GLSL450
530                OpEntryPoint Fragment %4 "main"
531                OpExecutionMode %4 OriginUpperLeft
532                OpSource GLSL 440
533                OpName %4 "main"
534                OpName %8 "i"
535                OpName %23 "a"
536                OpName %25 "b"
537                OpName %34 "i"
538                OpName %42 "c"
539           %2 = OpTypeVoid
540           %3 = OpTypeFunction %2
541           %6 = OpTypeInt 32 1
542           %7 = OpTypePointer Function %6
543           %9 = OpConstant %6 0
544          %16 = OpConstant %6 10
545          %17 = OpTypeBool
546          %19 = OpTypeInt 32 0
547          %20 = OpConstant %19 10
548          %21 = OpTypeArray %6 %20
549          %22 = OpTypePointer Function %21
550          %29 = OpConstant %6 1
551          %48 = OpConstant %6 2
552           %4 = OpFunction %2 None %3
553           %5 = OpLabel
554           %8 = OpVariable %7 Function
555          %23 = OpVariable %22 Function
556          %25 = OpVariable %22 Function
557          %34 = OpVariable %7 Function
558          %42 = OpVariable %22 Function
559                OpStore %8 %9
560                OpBranch %10
561          %10 = OpLabel
562          %53 = OpPhi %6 %9 %5 %33 %13
563                OpLoopMerge %12 %13 None
564                OpBranch %14
565          %14 = OpLabel
566          %18 = OpSLessThan %17 %53 %16
567                OpBranchConditional %18 %11 %12
568          %11 = OpLabel
569          %27 = OpAccessChain %7 %25 %53
570          %28 = OpLoad %6 %27
571          %30 = OpIAdd %6 %28 %29
572          %31 = OpAccessChain %7 %23 %53
573                OpStore %31 %30
574                OpBranch %13
575          %13 = OpLabel
576          %33 = OpIAdd %6 %53 %29
577                OpStore %8 %33
578                OpBranch %10
579          %12 = OpLabel
580                OpStore %34 %9
581                OpBranch %35
582          %35 = OpLabel
583          %54 = OpPhi %6 %9 %12 %52 %38
584                OpLoopMerge %37 %38 None
585                OpBranch %39
586          %39 = OpLabel
587          %41 = OpSLessThan %17 %54 %16
588                OpBranchConditional %41 %36 %37
589          %36 = OpLabel
590          %45 = OpIAdd %6 %54 %29
591          %46 = OpAccessChain %7 %23 %45
592          %47 = OpLoad %6 %46
593          %49 = OpIAdd %6 %47 %48
594          %50 = OpAccessChain %7 %42 %54
595                OpStore %50 %49
596                OpBranch %38
597          %38 = OpLabel
598          %52 = OpIAdd %6 %54 %29
599                OpStore %34 %52
600                OpBranch %35
601          %37 = OpLabel
602                OpReturn
603                OpFunctionEnd
604     )";
605 
606   SinglePassRunAndMatch<LoopFusionPass>(text, true, 20);
607 }
608 
609 /*
610 Generated from the following GLSL + --eliminate-local-multi-store
611 
612 #version 440 core
613 void main() {
614   int[10] a;
615   int[10] b;
616   for (int i = 0; i < 10; i++) {
617     a[i] = a[i]*2;
618   }
619   for (int i = 0; i < 10; i++) {
620     b[i] = a[i]+2;
621   }
622 }
623 
624 */
TEST_F(FusionPassTest,TooManyRegisters)625 TEST_F(FusionPassTest, TooManyRegisters) {
626   const std::string text = R"(
627 ; CHECK: OpPhi
628 ; CHECK-NEXT: OpLoopMerge
629 ; CHECK: OpLoad
630 ; CHECK: OpStore
631 ; CHECK: OpPhi
632 ; CHECK-NEXT: OpLoopMerge
633 ; CHECK: OpLoad
634 ; CHECK: OpStore
635 
636                OpCapability Shader
637           %1 = OpExtInstImport "GLSL.std.450"
638                OpMemoryModel Logical GLSL450
639                OpEntryPoint Fragment %4 "main"
640                OpExecutionMode %4 OriginUpperLeft
641                OpSource GLSL 440
642                OpName %4 "main"
643                OpName %8 "i"
644                OpName %23 "a"
645                OpName %34 "i"
646                OpName %42 "b"
647           %2 = OpTypeVoid
648           %3 = OpTypeFunction %2
649           %6 = OpTypeInt 32 1
650           %7 = OpTypePointer Function %6
651           %9 = OpConstant %6 0
652          %16 = OpConstant %6 10
653          %17 = OpTypeBool
654          %19 = OpTypeInt 32 0
655          %20 = OpConstant %19 10
656          %21 = OpTypeArray %6 %20
657          %22 = OpTypePointer Function %21
658          %28 = OpConstant %6 2
659          %32 = OpConstant %6 1
660           %4 = OpFunction %2 None %3
661           %5 = OpLabel
662           %8 = OpVariable %7 Function
663          %23 = OpVariable %22 Function
664          %34 = OpVariable %7 Function
665          %42 = OpVariable %22 Function
666                OpStore %8 %9
667                OpBranch %10
668          %10 = OpLabel
669          %51 = OpPhi %6 %9 %5 %33 %13
670                OpLoopMerge %12 %13 None
671                OpBranch %14
672          %14 = OpLabel
673          %18 = OpSLessThan %17 %51 %16
674                OpBranchConditional %18 %11 %12
675          %11 = OpLabel
676          %26 = OpAccessChain %7 %23 %51
677          %27 = OpLoad %6 %26
678          %29 = OpIMul %6 %27 %28
679          %30 = OpAccessChain %7 %23 %51
680                OpStore %30 %29
681                OpBranch %13
682          %13 = OpLabel
683          %33 = OpIAdd %6 %51 %32
684                OpStore %8 %33
685                OpBranch %10
686          %12 = OpLabel
687                OpStore %34 %9
688                OpBranch %35
689          %35 = OpLabel
690          %52 = OpPhi %6 %9 %12 %50 %38
691                OpLoopMerge %37 %38 None
692                OpBranch %39
693          %39 = OpLabel
694          %41 = OpSLessThan %17 %52 %16
695                OpBranchConditional %41 %36 %37
696          %36 = OpLabel
697          %45 = OpAccessChain %7 %23 %52
698          %46 = OpLoad %6 %45
699          %47 = OpIAdd %6 %46 %28
700          %48 = OpAccessChain %7 %42 %52
701                OpStore %48 %47
702                OpBranch %38
703          %38 = OpLabel
704          %50 = OpIAdd %6 %52 %32
705                OpStore %34 %50
706                OpBranch %35
707          %37 = OpLabel
708                OpReturn
709                OpFunctionEnd
710   )";
711 
712   SinglePassRunAndMatch<LoopFusionPass>(text, true, 5);
713 }
714 
715 }  // namespace
716 }  // namespace opt
717 }  // namespace spvtools
718