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