• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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