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