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