1 // Copyright (c) 2020 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_flatten_conditional_branch.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/counter_overflow_id_source.h"
19 #include "source/fuzz/fuzzer_util.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "test/fuzz/fuzz_test_util.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26 
MakeSideEffectWrapperInfo(const protobufs::InstructionDescriptor & instruction,uint32_t merge_block_id,uint32_t execute_block_id,uint32_t actual_result_id,uint32_t alternative_block_id,uint32_t placeholder_result_id,uint32_t value_to_copy_id)27 protobufs::SideEffectWrapperInfo MakeSideEffectWrapperInfo(
28     const protobufs::InstructionDescriptor& instruction,
29     uint32_t merge_block_id, uint32_t execute_block_id,
30     uint32_t actual_result_id, uint32_t alternative_block_id,
31     uint32_t placeholder_result_id, uint32_t value_to_copy_id) {
32   protobufs::SideEffectWrapperInfo result;
33   *result.mutable_instruction() = instruction;
34   result.set_merge_block_id(merge_block_id);
35   result.set_execute_block_id(execute_block_id);
36   result.set_actual_result_id(actual_result_id);
37   result.set_alternative_block_id(alternative_block_id);
38   result.set_placeholder_result_id(placeholder_result_id);
39   result.set_value_to_copy_id(value_to_copy_id);
40   return result;
41 }
42 
MakeSideEffectWrapperInfo(const protobufs::InstructionDescriptor & instruction,uint32_t merge_block_id,uint32_t execute_block_id)43 protobufs::SideEffectWrapperInfo MakeSideEffectWrapperInfo(
44     const protobufs::InstructionDescriptor& instruction,
45     uint32_t merge_block_id, uint32_t execute_block_id) {
46   return MakeSideEffectWrapperInfo(instruction, merge_block_id,
47                                    execute_block_id, 0, 0, 0, 0);
48 }
49 
TEST(TransformationFlattenConditionalBranchTest,Inapplicable)50 TEST(TransformationFlattenConditionalBranchTest, Inapplicable) {
51   std::string shader = R"(
52                OpCapability Shader
53           %1 = OpExtInstImport "GLSL.std.450"
54                OpMemoryModel Logical GLSL450
55                OpEntryPoint Fragment %2 "main" %3
56                OpExecutionMode %2 OriginUpperLeft
57                OpSource ESSL 310
58                OpName %2 "main"
59           %4 = OpTypeVoid
60           %5 = OpTypeFunction %4
61           %6 = OpTypeInt 32 1
62           %7 = OpTypeInt 32 0
63           %8 = OpConstant %7 0
64           %9 = OpTypeBool
65          %10 = OpConstantTrue %9
66          %11 = OpTypePointer Function %6
67          %12 = OpTypePointer Workgroup %6
68           %3 = OpVariable %12 Workgroup
69          %13 = OpConstant %6 2
70           %2 = OpFunction %4 None %5
71          %14 = OpLabel
72                OpBranch %15
73          %15 = OpLabel
74                OpSelectionMerge %16 None
75                OpSwitch %13 %17 2 %18
76          %17 = OpLabel
77                OpBranch %16
78          %18 = OpLabel
79                OpBranch %16
80          %16 = OpLabel
81                OpLoopMerge %19 %16 None
82                OpBranchConditional %10 %16 %19
83          %19 = OpLabel
84                OpSelectionMerge %20 None
85                OpBranchConditional %10 %21 %20
86          %21 = OpLabel
87                OpReturn
88          %20 = OpLabel
89                OpSelectionMerge %22 None
90                OpBranchConditional %10 %23 %22
91          %23 = OpLabel
92                OpSelectionMerge %24 None
93                OpBranchConditional %10 %25 %24
94          %25 = OpLabel
95                OpBranch %24
96          %24 = OpLabel
97                OpBranch %22
98          %22 = OpLabel
99                OpSelectionMerge %26 None
100                OpBranchConditional %10 %26 %27
101          %27 = OpLabel
102                OpBranch %28
103          %28 = OpLabel
104                OpLoopMerge %29 %28 None
105                OpBranchConditional %10 %28 %29
106          %29 = OpLabel
107                OpBranch %26
108          %26 = OpLabel
109                OpSelectionMerge %30 None
110                OpBranchConditional %10 %30 %31
111          %31 = OpLabel
112                OpBranch %32
113          %32 = OpLabel
114          %33 = OpAtomicLoad %6 %3 %8 %8
115                OpBranch %30
116          %30 = OpLabel
117                OpSelectionMerge %34 None
118                OpBranchConditional %10 %35 %34
119          %35 = OpLabel
120                OpMemoryBarrier %8 %8
121                OpBranch %34
122          %34 = OpLabel
123                OpLoopMerge %40 %39 None
124                OpBranchConditional %10 %36 %40
125          %36 = OpLabel
126                OpSelectionMerge %38 None
127                OpBranchConditional %10 %37 %38
128          %37 = OpLabel
129                OpBranch %40
130          %38 = OpLabel
131                OpBranch %39
132          %39 = OpLabel
133                OpBranch %34
134          %40 = OpLabel
135                OpReturn
136                OpFunctionEnd
137 )";
138 
139   const auto env = SPV_ENV_UNIVERSAL_1_5;
140   const auto consumer = nullptr;
141   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
142   spvtools::ValidatorOptions validator_options;
143   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
144                                                kConsoleMessageConsumer));
145   TransformationContext transformation_context(
146       MakeUnique<FactManager>(context.get()), validator_options);
147   // Block %15 does not end with OpBranchConditional.
148   ASSERT_FALSE(TransformationFlattenConditionalBranch(15, true, 0, 0, 0, {})
149                    .IsApplicable(context.get(), transformation_context));
150 
151   // Block %17 is not a selection header.
152   ASSERT_FALSE(TransformationFlattenConditionalBranch(17, true, 0, 0, 0, {})
153                    .IsApplicable(context.get(), transformation_context));
154 
155   // Block %16 is a loop header, not a selection header.
156   ASSERT_FALSE(TransformationFlattenConditionalBranch(16, true, 0, 0, 0, {})
157                    .IsApplicable(context.get(), transformation_context));
158 
159   // Block %19 and the corresponding merge block do not describe a single-entry,
160   // single-exit region, because there is a return instruction in %21.
161   ASSERT_FALSE(TransformationFlattenConditionalBranch(19, true, 0, 0, 0, {})
162                    .IsApplicable(context.get(), transformation_context));
163 
164   // Block %20 is the header of a construct containing an inner selection
165   // construct.
166   ASSERT_FALSE(TransformationFlattenConditionalBranch(20, true, 0, 0, 0, {})
167                    .IsApplicable(context.get(), transformation_context));
168 
169   // Block %22 is the header of a construct containing an inner loop.
170   ASSERT_FALSE(TransformationFlattenConditionalBranch(22, true, 0, 0, 0, {})
171                    .IsApplicable(context.get(), transformation_context));
172 
173   // Block %30 is the header of a construct containing a barrier instruction.
174   ASSERT_FALSE(TransformationFlattenConditionalBranch(30, true, 0, 0, 0, {})
175                    .IsApplicable(context.get(), transformation_context));
176 
177   // %33 is not a block.
178   ASSERT_FALSE(TransformationFlattenConditionalBranch(33, true, 0, 0, 0, {})
179                    .IsApplicable(context.get(), transformation_context));
180 
181   // Block %36 and the corresponding merge block do not describe a single-entry,
182   // single-exit region, because block %37 breaks out of the outer loop.
183   ASSERT_FALSE(TransformationFlattenConditionalBranch(36, true, 0, 0, 0, {})
184                    .IsApplicable(context.get(), transformation_context));
185 }
186 
TEST(TransformationFlattenConditionalBranchTest,Simple)187 TEST(TransformationFlattenConditionalBranchTest, Simple) {
188   std::string shader = R"(
189                OpCapability Shader
190           %1 = OpExtInstImport "GLSL.std.450"
191                OpMemoryModel Logical GLSL450
192                OpEntryPoint Fragment %2 "main"
193                OpExecutionMode %2 OriginUpperLeft
194                OpSource ESSL 310
195                OpName %2 "main"
196           %3 = OpTypeBool
197           %4 = OpConstantTrue %3
198           %5 = OpTypeVoid
199           %6 = OpTypeFunction %5
200           %2 = OpFunction %5 None %6
201           %7 = OpLabel
202                OpSelectionMerge %8 None
203                OpBranchConditional %4 %9 %10
204          %10 = OpLabel
205          %26 = OpPhi %3 %4 %7
206                OpBranch %8
207           %9 = OpLabel
208          %27 = OpPhi %3 %4 %7
209          %11 = OpCopyObject %3 %4
210                OpBranch %8
211           %8 = OpLabel
212          %12 = OpPhi %3 %11 %9 %4 %10
213          %23 = OpPhi %3 %4 %9 %4 %10
214                OpBranch %13
215          %13 = OpLabel
216          %14 = OpCopyObject %3 %4
217                OpSelectionMerge %15 None
218                OpBranchConditional %4 %16 %17
219          %16 = OpLabel
220          %28 = OpPhi %3 %4 %13
221                OpBranch %18
222          %18 = OpLabel
223                OpBranch %19
224          %17 = OpLabel
225          %29 = OpPhi %3 %4 %13
226          %20 = OpCopyObject %3 %4
227                OpBranch %19
228          %19 = OpLabel
229          %21 = OpPhi %3 %4 %18 %20 %17
230                OpBranch %15
231          %15 = OpLabel
232                OpSelectionMerge %22 None
233                OpBranchConditional %4 %22 %22
234          %22 = OpLabel
235          %30 = OpPhi %3 %4 %15
236                OpSelectionMerge %25 None
237                OpBranchConditional %4 %24 %24
238          %24 = OpLabel
239                OpBranch %25
240          %25 = OpLabel
241                OpReturn
242                OpFunctionEnd
243 )";
244 
245   const auto env = SPV_ENV_UNIVERSAL_1_5;
246   const auto consumer = nullptr;
247   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
248   spvtools::ValidatorOptions validator_options;
249   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
250                                                kConsoleMessageConsumer));
251   TransformationContext transformation_context(
252       MakeUnique<FactManager>(context.get()), validator_options);
253   auto transformation1 =
254       TransformationFlattenConditionalBranch(7, true, 0, 0, 0, {});
255   ASSERT_TRUE(
256       transformation1.IsApplicable(context.get(), transformation_context));
257   ApplyAndCheckFreshIds(transformation1, context.get(),
258                         &transformation_context);
259 
260   auto transformation2 =
261       TransformationFlattenConditionalBranch(13, false, 0, 0, 0, {});
262   ASSERT_TRUE(
263       transformation2.IsApplicable(context.get(), transformation_context));
264   ApplyAndCheckFreshIds(transformation2, context.get(),
265                         &transformation_context);
266 
267   auto transformation3 =
268       TransformationFlattenConditionalBranch(15, true, 0, 0, 0, {});
269   ASSERT_TRUE(
270       transformation3.IsApplicable(context.get(), transformation_context));
271   ApplyAndCheckFreshIds(transformation3, context.get(),
272                         &transformation_context);
273 
274   auto transformation4 =
275       TransformationFlattenConditionalBranch(22, false, 0, 0, 0, {});
276   ASSERT_TRUE(
277       transformation4.IsApplicable(context.get(), transformation_context));
278   ApplyAndCheckFreshIds(transformation4, context.get(),
279                         &transformation_context);
280 
281   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
282                                                kConsoleMessageConsumer));
283 
284   std::string after_transformations = R"(
285                OpCapability Shader
286           %1 = OpExtInstImport "GLSL.std.450"
287                OpMemoryModel Logical GLSL450
288                OpEntryPoint Fragment %2 "main"
289                OpExecutionMode %2 OriginUpperLeft
290                OpSource ESSL 310
291                OpName %2 "main"
292           %3 = OpTypeBool
293           %4 = OpConstantTrue %3
294           %5 = OpTypeVoid
295           %6 = OpTypeFunction %5
296           %2 = OpFunction %5 None %6
297           %7 = OpLabel
298                OpBranch %9
299           %9 = OpLabel
300          %27 = OpPhi %3 %4 %7
301          %11 = OpCopyObject %3 %4
302                OpBranch %10
303          %10 = OpLabel
304          %26 = OpPhi %3 %4 %9
305                OpBranch %8
306           %8 = OpLabel
307          %12 = OpSelect %3 %4 %11 %4
308          %23 = OpSelect %3 %4 %4 %4
309                OpBranch %13
310          %13 = OpLabel
311          %14 = OpCopyObject %3 %4
312                OpBranch %17
313          %17 = OpLabel
314          %29 = OpPhi %3 %4 %13
315          %20 = OpCopyObject %3 %4
316                OpBranch %16
317          %16 = OpLabel
318          %28 = OpPhi %3 %4 %17
319                OpBranch %18
320          %18 = OpLabel
321                OpBranch %19
322          %19 = OpLabel
323          %21 = OpSelect %3 %4 %4 %20
324                OpBranch %15
325          %15 = OpLabel
326                OpBranch %22
327          %22 = OpLabel
328          %30 = OpPhi %3 %4 %15
329                OpBranch %24
330          %24 = OpLabel
331                OpBranch %25
332          %25 = OpLabel
333                OpReturn
334                OpFunctionEnd
335 )";
336 
337   ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
338 }
339 
TEST(TransformationFlattenConditionalBranchTest,LoadStoreFunctionCall)340 TEST(TransformationFlattenConditionalBranchTest, LoadStoreFunctionCall) {
341   std::string shader = R"(
342                OpCapability Shader
343           %1 = OpExtInstImport "GLSL.std.450"
344                OpMemoryModel Logical GLSL450
345                OpEntryPoint Fragment %2 "main"
346                OpExecutionMode %2 OriginUpperLeft
347                OpSource ESSL 310
348           %9 = OpTypeVoid
349          %10 = OpTypeFunction %9
350          %11 = OpTypeInt 32 1
351          %12 = OpTypeVector %11 4
352          %13 = OpTypeFunction %11
353          %70 = OpConstant %11 0
354          %14 = OpConstant %11 1
355          %15 = OpTypeFloat 32
356          %16 = OpTypeVector %15 2
357          %17 = OpConstant %15 1
358          %18 = OpConstantComposite %16 %17 %17
359          %19 = OpTypeBool
360          %20 = OpConstantTrue %19
361          %21 = OpTypePointer Function %11
362          %22 = OpTypeSampler
363          %23 = OpTypeImage %9 2D 2 0 0 1 Unknown
364          %24 = OpTypeSampledImage %23
365          %25 = OpTypePointer Function %23
366          %26 = OpTypePointer Function %22
367          %27 = OpTypeInt 32 0
368          %28 = OpConstant %27 2
369          %29 = OpTypeArray %11 %28
370          %30 = OpTypePointer Function %29
371           %2 = OpFunction %9 None %10
372          %31 = OpLabel
373           %4 = OpVariable %21 Function
374           %5 = OpVariable %30 Function
375          %32 = OpVariable %25 Function
376          %33 = OpVariable %26 Function
377          %34 = OpLoad %23 %32
378          %35 = OpLoad %22 %33
379                OpSelectionMerge %36 None
380                OpBranchConditional %20 %37 %36
381          %37 = OpLabel
382           %6 = OpLoad %11 %4
383           %7 = OpIAdd %11 %6 %14
384                OpStore %4 %7
385                OpBranch %36
386          %36 = OpLabel
387          %42 = OpPhi %11 %14 %37 %14 %31
388                OpSelectionMerge %43 None
389                OpBranchConditional %20 %44 %45
390          %44 = OpLabel
391           %8 = OpFunctionCall %11 %3
392                OpStore %4 %8
393                OpBranch %46
394          %45 = OpLabel
395          %47 = OpAccessChain %21 %5 %14
396                OpStore %47 %14
397                OpBranch %46
398          %46 = OpLabel
399                OpStore %4 %14
400                OpBranch %43
401          %43 = OpLabel
402                OpStore %4 %14
403                OpSelectionMerge %48 None
404                OpBranchConditional %20 %49 %48
405          %49 = OpLabel
406                OpBranch %48
407          %48 = OpLabel
408                OpSelectionMerge %50 None
409                OpBranchConditional %20 %51 %50
410          %51 = OpLabel
411          %52 = OpSampledImage %24 %34 %35
412          %53 = OpLoad %11 %4
413          %54 = OpImageSampleImplicitLod %12 %52 %18
414                OpBranch %50
415          %50 = OpLabel
416                OpReturn
417                OpFunctionEnd
418           %3 = OpFunction %11 None %13
419          %55 = OpLabel
420                OpReturnValue %14
421                OpFunctionEnd
422 )";
423 
424   const auto env = SPV_ENV_UNIVERSAL_1_5;
425   const auto consumer = nullptr;
426   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
427   spvtools::ValidatorOptions validator_options;
428   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
429                                                kConsoleMessageConsumer));
430   TransformationContext transformation_context(
431       MakeUnique<FactManager>(context.get()), validator_options);
432 #ifndef NDEBUG
433   // The following checks lead to assertion failures, since some entries
434   // requiring fresh ids are not present in the map, and the transformation
435   // context does not have a source overflow ids.
436 
437   ASSERT_DEATH(TransformationFlattenConditionalBranch(31, true, 0, 0, 0, {})
438                    .IsApplicable(context.get(), transformation_context),
439                "Bad attempt to query whether overflow ids are available.");
440 
441   ASSERT_DEATH(TransformationFlattenConditionalBranch(
442                    31, true, 0, 0, 0,
443                    {{MakeSideEffectWrapperInfo(
444                        MakeInstructionDescriptor(6, SpvOpLoad, 0), 100, 101,
445                        102, 103, 104, 14)}})
446                    .IsApplicable(context.get(), transformation_context),
447                "Bad attempt to query whether overflow ids are available.");
448 #endif
449 
450   // The map maps from an instruction to a list with not enough fresh ids.
451   ASSERT_FALSE(TransformationFlattenConditionalBranch(
452                    31, true, 0, 0, 0,
453                    {{MakeSideEffectWrapperInfo(
454                        MakeInstructionDescriptor(6, SpvOpLoad, 0), 100, 101,
455                        102, 103, 0, 0)}})
456                    .IsApplicable(context.get(), transformation_context));
457 
458   // Not all fresh ids given are distinct.
459   ASSERT_FALSE(TransformationFlattenConditionalBranch(
460                    31, true, 0, 0, 0,
461                    {{MakeSideEffectWrapperInfo(
462                        MakeInstructionDescriptor(6, SpvOpLoad, 0), 100, 100,
463                        102, 103, 104, 0)}})
464                    .IsApplicable(context.get(), transformation_context));
465 
466   // %48 heads a construct containing an OpSampledImage instruction.
467   ASSERT_FALSE(TransformationFlattenConditionalBranch(
468                    48, true, 0, 0, 0,
469                    {{MakeSideEffectWrapperInfo(
470                        MakeInstructionDescriptor(53, SpvOpLoad, 0), 100, 101,
471                        102, 103, 104, 0)}})
472                    .IsApplicable(context.get(), transformation_context));
473 
474   // %0 is not a valid id.
475   ASSERT_FALSE(
476       TransformationFlattenConditionalBranch(
477           31, true, 0, 0, 0,
478           {MakeSideEffectWrapperInfo(MakeInstructionDescriptor(6, SpvOpLoad, 0),
479                                      104, 100, 101, 102, 103, 0),
480            MakeSideEffectWrapperInfo(
481                MakeInstructionDescriptor(6, SpvOpStore, 0), 106, 105)})
482           .IsApplicable(context.get(), transformation_context));
483 
484   // %17 is a float constant, while %6 has int type.
485   ASSERT_FALSE(
486       TransformationFlattenConditionalBranch(
487           31, true, 0, 0, 0,
488           {MakeSideEffectWrapperInfo(MakeInstructionDescriptor(6, SpvOpLoad, 0),
489                                      104, 100, 101, 102, 103, 17),
490            MakeSideEffectWrapperInfo(
491                MakeInstructionDescriptor(6, SpvOpStore, 0), 106, 105)})
492           .IsApplicable(context.get(), transformation_context));
493 
494   auto transformation1 = TransformationFlattenConditionalBranch(
495       31, true, 0, 0, 0,
496       {MakeSideEffectWrapperInfo(MakeInstructionDescriptor(6, SpvOpLoad, 0),
497                                  104, 100, 101, 102, 103, 70),
498        MakeSideEffectWrapperInfo(MakeInstructionDescriptor(6, SpvOpStore, 0),
499                                  106, 105)});
500   ASSERT_TRUE(
501       transformation1.IsApplicable(context.get(), transformation_context));
502   ApplyAndCheckFreshIds(transformation1, context.get(),
503                         &transformation_context);
504 
505   // Check that the placeholder id was marked as irrelevant.
506   ASSERT_TRUE(transformation_context.GetFactManager()->IdIsIrrelevant(103));
507 
508   // Make a new transformation context with a source of overflow ids.
509   auto overflow_ids_unique_ptr = MakeUnique<CounterOverflowIdSource>(1000);
510   auto overflow_ids_ptr = overflow_ids_unique_ptr.get();
511   TransformationContext new_transformation_context(
512       MakeUnique<FactManager>(context.get()), validator_options,
513       std::move(overflow_ids_unique_ptr));
514 
515   auto transformation2 = TransformationFlattenConditionalBranch(
516       36, false, 0, 0, 0,
517       {MakeSideEffectWrapperInfo(MakeInstructionDescriptor(8, SpvOpStore, 0),
518                                  114, 113)});
519   ASSERT_TRUE(
520       transformation2.IsApplicable(context.get(), new_transformation_context));
521   ApplyAndCheckFreshIds(transformation2, context.get(),
522                         &new_transformation_context,
523                         overflow_ids_ptr->GetIssuedOverflowIds());
524 
525   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
526                                                kConsoleMessageConsumer));
527 
528   std::string after_transformations = R"(
529                OpCapability Shader
530           %1 = OpExtInstImport "GLSL.std.450"
531                OpMemoryModel Logical GLSL450
532                OpEntryPoint Fragment %2 "main"
533                OpExecutionMode %2 OriginUpperLeft
534                OpSource ESSL 310
535           %9 = OpTypeVoid
536          %10 = OpTypeFunction %9
537          %11 = OpTypeInt 32 1
538          %12 = OpTypeVector %11 4
539          %13 = OpTypeFunction %11
540          %70 = OpConstant %11 0
541          %14 = OpConstant %11 1
542          %15 = OpTypeFloat 32
543          %16 = OpTypeVector %15 2
544          %17 = OpConstant %15 1
545          %18 = OpConstantComposite %16 %17 %17
546          %19 = OpTypeBool
547          %20 = OpConstantTrue %19
548          %21 = OpTypePointer Function %11
549          %22 = OpTypeSampler
550          %23 = OpTypeImage %9 2D 2 0 0 1 Unknown
551          %24 = OpTypeSampledImage %23
552          %25 = OpTypePointer Function %23
553          %26 = OpTypePointer Function %22
554          %27 = OpTypeInt 32 0
555          %28 = OpConstant %27 2
556          %29 = OpTypeArray %11 %28
557          %30 = OpTypePointer Function %29
558           %2 = OpFunction %9 None %10
559          %31 = OpLabel
560           %4 = OpVariable %21 Function
561           %5 = OpVariable %30 Function
562          %32 = OpVariable %25 Function
563          %33 = OpVariable %26 Function
564          %34 = OpLoad %23 %32
565          %35 = OpLoad %22 %33
566                OpBranch %37
567          %37 = OpLabel
568                OpSelectionMerge %104 None
569                OpBranchConditional %20 %100 %102
570         %100 = OpLabel
571         %101 = OpLoad %11 %4
572                OpBranch %104
573         %102 = OpLabel
574         %103 = OpCopyObject %11 %70
575                OpBranch %104
576         %104 = OpLabel
577           %6 = OpPhi %11 %101 %100 %103 %102
578           %7 = OpIAdd %11 %6 %14
579                OpSelectionMerge %106 None
580                OpBranchConditional %20 %105 %106
581         %105 = OpLabel
582                OpStore %4 %7
583                OpBranch %106
584         %106 = OpLabel
585                OpBranch %36
586          %36 = OpLabel
587          %42 = OpSelect %11 %20 %14 %14
588                OpBranch %45
589          %45 = OpLabel
590          %47 = OpAccessChain %21 %5 %14
591                OpSelectionMerge %1005 None
592                OpBranchConditional %20 %1005 %1006
593        %1006 = OpLabel
594                OpStore %47 %14
595                OpBranch %1005
596        %1005 = OpLabel
597                OpBranch %44
598          %44 = OpLabel
599                OpSelectionMerge %1000 None
600                OpBranchConditional %20 %1001 %1003
601        %1001 = OpLabel
602        %1002 = OpFunctionCall %11 %3
603                OpBranch %1000
604        %1003 = OpLabel
605        %1004 = OpCopyObject %11 %70
606                OpBranch %1000
607        %1000 = OpLabel
608           %8 = OpPhi %11 %1002 %1001 %1004 %1003
609                OpSelectionMerge %114 None
610                OpBranchConditional %20 %113 %114
611         %113 = OpLabel
612                OpStore %4 %8
613                OpBranch %114
614         %114 = OpLabel
615                OpBranch %46
616          %46 = OpLabel
617                OpStore %4 %14
618                OpBranch %43
619          %43 = OpLabel
620                OpStore %4 %14
621                OpSelectionMerge %48 None
622                OpBranchConditional %20 %49 %48
623          %49 = OpLabel
624                OpBranch %48
625          %48 = OpLabel
626                OpSelectionMerge %50 None
627                OpBranchConditional %20 %51 %50
628          %51 = OpLabel
629          %52 = OpSampledImage %24 %34 %35
630          %53 = OpLoad %11 %4
631          %54 = OpImageSampleImplicitLod %12 %52 %18
632                OpBranch %50
633          %50 = OpLabel
634                OpReturn
635                OpFunctionEnd
636           %3 = OpFunction %11 None %13
637          %55 = OpLabel
638                OpReturnValue %14
639                OpFunctionEnd
640 )";
641 
642   ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
643 }  // namespace
644 
TEST(TransformationFlattenConditionalBranchTest,EdgeCases)645 TEST(TransformationFlattenConditionalBranchTest, EdgeCases) {
646   std::string shader = R"(
647                OpCapability Shader
648           %1 = OpExtInstImport "GLSL.std.450"
649                OpMemoryModel Logical GLSL450
650                OpEntryPoint Fragment %2 "main"
651                OpExecutionMode %2 OriginUpperLeft
652                OpSource ESSL 310
653           %3 = OpTypeVoid
654           %4 = OpTypeBool
655           %5 = OpConstantTrue %4
656           %6 = OpTypeFunction %3
657           %2 = OpFunction %3 None %6
658           %7 = OpLabel
659                OpSelectionMerge %8 None
660                OpBranchConditional %5 %9 %8
661           %9 = OpLabel
662          %10 = OpFunctionCall %3 %11
663                OpBranch %8
664           %8 = OpLabel
665                OpSelectionMerge %12 None
666                OpBranchConditional %5 %13 %12
667          %13 = OpLabel
668          %14 = OpFunctionCall %3 %11
669                OpBranch %12
670          %12 = OpLabel
671                OpReturn
672          %16 = OpLabel
673                OpSelectionMerge %17 None
674                OpBranchConditional %5 %18 %17
675          %18 = OpLabel
676                OpBranch %17
677          %17 = OpLabel
678                OpReturn
679                OpFunctionEnd
680          %11 = OpFunction %3 None %6
681          %19 = OpLabel
682                OpBranch %20
683          %20 = OpLabel
684                OpSelectionMerge %25 None
685                OpBranchConditional %5 %21 %22
686          %21 = OpLabel
687                OpBranch %22
688          %22 = OpLabel
689                OpSelectionMerge %24 None
690                OpBranchConditional %5 %24 %23
691          %23 = OpLabel
692                OpBranch %24
693          %24 = OpLabel
694                OpBranch %25
695          %25 = OpLabel
696                OpReturn
697                OpFunctionEnd
698 )";
699 
700   const auto env = SPV_ENV_UNIVERSAL_1_5;
701   const auto consumer = nullptr;
702   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
703   spvtools::ValidatorOptions validator_options;
704   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
705                                                kConsoleMessageConsumer));
706   TransformationContext transformation_context(
707       MakeUnique<FactManager>(context.get()), validator_options);
708 #ifndef NDEBUG
709   // The selection construct headed by %7 requires fresh ids because it contains
710   // a function call. This causes an assertion failure because transformation
711   // context does not have a source of overflow ids.
712   ASSERT_DEATH(TransformationFlattenConditionalBranch(7, true, 0, 0, 0, {})
713                    .IsApplicable(context.get(), transformation_context),
714                "Bad attempt to query whether overflow ids are available.");
715 #endif
716 
717   auto transformation1 = TransformationFlattenConditionalBranch(
718       7, true, 0, 0, 0,
719       {{MakeSideEffectWrapperInfo(
720           MakeInstructionDescriptor(10, SpvOpFunctionCall, 0), 100, 101)}});
721   ASSERT_TRUE(
722       transformation1.IsApplicable(context.get(), transformation_context));
723   ApplyAndCheckFreshIds(transformation1, context.get(),
724                         &transformation_context);
725 
726   // The selection construct headed by %8 cannot be flattened because it
727   // contains a function call returning void, whose result id is used.
728   ASSERT_FALSE(
729       TransformationFlattenConditionalBranch(
730           7, true, 0, 0, 0,
731           {{MakeSideEffectWrapperInfo(
732               MakeInstructionDescriptor(14, SpvOpFunctionCall, 0), 102, 103)}})
733           .IsApplicable(context.get(), transformation_context));
734 
735   // Block %16 is unreachable.
736   ASSERT_FALSE(TransformationFlattenConditionalBranch(16, true, 0, 0, 0, {})
737                    .IsApplicable(context.get(), transformation_context));
738 
739   auto transformation2 =
740       TransformationFlattenConditionalBranch(20, false, 0, 0, 0, {});
741   ASSERT_TRUE(
742       transformation2.IsApplicable(context.get(), transformation_context));
743   ApplyAndCheckFreshIds(transformation2, context.get(),
744                         &transformation_context);
745 
746   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
747                                                kConsoleMessageConsumer));
748 
749   std::string after_transformation = R"(
750                OpCapability Shader
751           %1 = OpExtInstImport "GLSL.std.450"
752                OpMemoryModel Logical GLSL450
753                OpEntryPoint Fragment %2 "main"
754                OpExecutionMode %2 OriginUpperLeft
755                OpSource ESSL 310
756           %3 = OpTypeVoid
757           %4 = OpTypeBool
758           %5 = OpConstantTrue %4
759           %6 = OpTypeFunction %3
760           %2 = OpFunction %3 None %6
761           %7 = OpLabel
762                OpBranch %9
763           %9 = OpLabel
764                OpSelectionMerge %100 None
765                OpBranchConditional %5 %101 %100
766         %101 = OpLabel
767          %10 = OpFunctionCall %3 %11
768                OpBranch %100
769         %100 = OpLabel
770                OpBranch %8
771           %8 = OpLabel
772                OpSelectionMerge %12 None
773                OpBranchConditional %5 %13 %12
774          %13 = OpLabel
775          %14 = OpFunctionCall %3 %11
776                OpBranch %12
777          %12 = OpLabel
778                OpReturn
779          %16 = OpLabel
780                OpSelectionMerge %17 None
781                OpBranchConditional %5 %18 %17
782          %18 = OpLabel
783                OpBranch %17
784          %17 = OpLabel
785                OpReturn
786                OpFunctionEnd
787          %11 = OpFunction %3 None %6
788          %19 = OpLabel
789                OpBranch %20
790          %20 = OpLabel
791                OpBranch %21
792          %21 = OpLabel
793                OpBranch %22
794          %22 = OpLabel
795                OpSelectionMerge %24 None
796                OpBranchConditional %5 %24 %23
797          %23 = OpLabel
798                OpBranch %24
799          %24 = OpLabel
800                OpBranch %25
801          %25 = OpLabel
802                OpReturn
803                OpFunctionEnd
804 )";
805 
806   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
807 }
808 
TEST(TransformationFlattenConditionalBranchTest,PhiToSelect1)809 TEST(TransformationFlattenConditionalBranchTest, PhiToSelect1) {
810   std::string shader = R"(
811                OpCapability Shader
812           %1 = OpExtInstImport "GLSL.std.450"
813                OpMemoryModel Logical GLSL450
814                OpEntryPoint Fragment %2 "main"
815                OpExecutionMode %2 OriginUpperLeft
816                OpSource ESSL 310
817           %3 = OpTypeVoid
818           %4 = OpTypeBool
819           %5 = OpConstantTrue %4
820          %10 = OpConstantFalse %4
821           %6 = OpTypeFunction %3
822           %2 = OpFunction %3 None %6
823           %7 = OpLabel
824                OpSelectionMerge %8 None
825                OpBranchConditional %5 %9 %8
826           %9 = OpLabel
827                OpBranch %8
828           %8 = OpLabel
829          %11 = OpPhi %4 %5 %9 %10 %7
830                OpReturn
831                OpFunctionEnd
832 )";
833 
834   const auto env = SPV_ENV_UNIVERSAL_1_5;
835   const auto consumer = nullptr;
836   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
837   spvtools::ValidatorOptions validator_options;
838   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
839                                                kConsoleMessageConsumer));
840   TransformationContext transformation_context(
841       MakeUnique<FactManager>(context.get()), validator_options);
842 
843   auto transformation =
844       TransformationFlattenConditionalBranch(7, true, 0, 0, 0, {});
845   ASSERT_TRUE(
846       transformation.IsApplicable(context.get(), transformation_context));
847   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
848   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
849                                                kConsoleMessageConsumer));
850 
851   std::string after_transformation = R"(
852                OpCapability Shader
853           %1 = OpExtInstImport "GLSL.std.450"
854                OpMemoryModel Logical GLSL450
855                OpEntryPoint Fragment %2 "main"
856                OpExecutionMode %2 OriginUpperLeft
857                OpSource ESSL 310
858           %3 = OpTypeVoid
859           %4 = OpTypeBool
860           %5 = OpConstantTrue %4
861          %10 = OpConstantFalse %4
862           %6 = OpTypeFunction %3
863           %2 = OpFunction %3 None %6
864           %7 = OpLabel
865                OpBranch %9
866           %9 = OpLabel
867                OpBranch %8
868           %8 = OpLabel
869          %11 = OpSelect %4 %5 %5 %10
870                OpReturn
871                OpFunctionEnd
872 )";
873   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
874 }
875 
TEST(TransformationFlattenConditionalBranchTest,PhiToSelect2)876 TEST(TransformationFlattenConditionalBranchTest, PhiToSelect2) {
877   std::string shader = R"(
878                OpCapability Shader
879           %1 = OpExtInstImport "GLSL.std.450"
880                OpMemoryModel Logical GLSL450
881                OpEntryPoint Fragment %2 "main"
882                OpExecutionMode %2 OriginUpperLeft
883                OpSource ESSL 310
884           %3 = OpTypeVoid
885           %4 = OpTypeBool
886           %5 = OpConstantTrue %4
887          %10 = OpConstantFalse %4
888           %6 = OpTypeFunction %3
889           %2 = OpFunction %3 None %6
890           %7 = OpLabel
891                OpSelectionMerge %8 None
892                OpBranchConditional %5 %9 %8
893           %9 = OpLabel
894                OpBranch %8
895           %8 = OpLabel
896          %11 = OpPhi %4 %10 %7 %5 %9
897                OpReturn
898                OpFunctionEnd
899 )";
900 
901   const auto env = SPV_ENV_UNIVERSAL_1_5;
902   const auto consumer = nullptr;
903   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
904   spvtools::ValidatorOptions validator_options;
905   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
906                                                kConsoleMessageConsumer));
907   TransformationContext transformation_context(
908       MakeUnique<FactManager>(context.get()), validator_options);
909 
910   auto transformation =
911       TransformationFlattenConditionalBranch(7, true, 0, 0, 0, {});
912   ASSERT_TRUE(
913       transformation.IsApplicable(context.get(), transformation_context));
914   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
915   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
916                                                kConsoleMessageConsumer));
917 
918   std::string after_transformation = R"(
919                OpCapability Shader
920           %1 = OpExtInstImport "GLSL.std.450"
921                OpMemoryModel Logical GLSL450
922                OpEntryPoint Fragment %2 "main"
923                OpExecutionMode %2 OriginUpperLeft
924                OpSource ESSL 310
925           %3 = OpTypeVoid
926           %4 = OpTypeBool
927           %5 = OpConstantTrue %4
928          %10 = OpConstantFalse %4
929           %6 = OpTypeFunction %3
930           %2 = OpFunction %3 None %6
931           %7 = OpLabel
932                OpBranch %9
933           %9 = OpLabel
934                OpBranch %8
935           %8 = OpLabel
936          %11 = OpSelect %4 %5 %5 %10
937                OpReturn
938                OpFunctionEnd
939 )";
940   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
941 }
942 
TEST(TransformationFlattenConditionalBranchTest,PhiToSelect3)943 TEST(TransformationFlattenConditionalBranchTest, PhiToSelect3) {
944   std::string shader = R"(
945                OpCapability Shader
946           %1 = OpExtInstImport "GLSL.std.450"
947                OpMemoryModel Logical GLSL450
948                OpEntryPoint Fragment %2 "main"
949                OpExecutionMode %2 OriginUpperLeft
950                OpSource ESSL 310
951           %3 = OpTypeVoid
952           %4 = OpTypeBool
953           %5 = OpConstantTrue %4
954          %10 = OpConstantFalse %4
955           %6 = OpTypeFunction %3
956           %2 = OpFunction %3 None %6
957           %7 = OpLabel
958                OpSelectionMerge %8 None
959                OpBranchConditional %5 %9 %12
960           %9 = OpLabel
961                OpBranch %8
962          %12 = OpLabel
963                OpBranch %8
964           %8 = OpLabel
965          %11 = OpPhi %4 %10 %12 %5 %9
966                OpReturn
967                OpFunctionEnd
968 )";
969 
970   const auto env = SPV_ENV_UNIVERSAL_1_5;
971   const auto consumer = nullptr;
972   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
973   spvtools::ValidatorOptions validator_options;
974   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
975                                                kConsoleMessageConsumer));
976   TransformationContext transformation_context(
977       MakeUnique<FactManager>(context.get()), validator_options);
978 
979   auto transformation =
980       TransformationFlattenConditionalBranch(7, true, 0, 0, 0, {});
981   ASSERT_TRUE(
982       transformation.IsApplicable(context.get(), transformation_context));
983   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
984   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
985                                                kConsoleMessageConsumer));
986 
987   std::string after_transformation = R"(
988                OpCapability Shader
989           %1 = OpExtInstImport "GLSL.std.450"
990                OpMemoryModel Logical GLSL450
991                OpEntryPoint Fragment %2 "main"
992                OpExecutionMode %2 OriginUpperLeft
993                OpSource ESSL 310
994           %3 = OpTypeVoid
995           %4 = OpTypeBool
996           %5 = OpConstantTrue %4
997          %10 = OpConstantFalse %4
998           %6 = OpTypeFunction %3
999           %2 = OpFunction %3 None %6
1000           %7 = OpLabel
1001                OpBranch %9
1002           %9 = OpLabel
1003                OpBranch %12
1004          %12 = OpLabel
1005                OpBranch %8
1006           %8 = OpLabel
1007          %11 = OpSelect %4 %5 %5 %10
1008                OpReturn
1009                OpFunctionEnd
1010 )";
1011   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1012 }
1013 
TEST(TransformationFlattenConditionalBranchTest,PhiToSelect4)1014 TEST(TransformationFlattenConditionalBranchTest, PhiToSelect4) {
1015   std::string shader = R"(
1016                OpCapability Shader
1017           %1 = OpExtInstImport "GLSL.std.450"
1018                OpMemoryModel Logical GLSL450
1019                OpEntryPoint Fragment %2 "main"
1020                OpExecutionMode %2 OriginUpperLeft
1021                OpSource ESSL 310
1022           %3 = OpTypeVoid
1023           %4 = OpTypeBool
1024           %5 = OpConstantTrue %4
1025          %10 = OpConstantFalse %4
1026           %6 = OpTypeFunction %3
1027           %2 = OpFunction %3 None %6
1028           %7 = OpLabel
1029                OpSelectionMerge %8 None
1030                OpBranchConditional %5 %9 %12
1031           %9 = OpLabel
1032                OpBranch %8
1033          %12 = OpLabel
1034                OpBranch %8
1035           %8 = OpLabel
1036          %11 = OpPhi %4 %5 %9 %10 %12
1037                OpReturn
1038                OpFunctionEnd
1039 )";
1040 
1041   const auto env = SPV_ENV_UNIVERSAL_1_5;
1042   const auto consumer = nullptr;
1043   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1044   spvtools::ValidatorOptions validator_options;
1045   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1046                                                kConsoleMessageConsumer));
1047   TransformationContext transformation_context(
1048       MakeUnique<FactManager>(context.get()), validator_options);
1049 
1050   auto transformation =
1051       TransformationFlattenConditionalBranch(7, true, 0, 0, 0, {});
1052   ASSERT_TRUE(
1053       transformation.IsApplicable(context.get(), transformation_context));
1054   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1055   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1056                                                kConsoleMessageConsumer));
1057 
1058   std::string after_transformation = R"(
1059                OpCapability Shader
1060           %1 = OpExtInstImport "GLSL.std.450"
1061                OpMemoryModel Logical GLSL450
1062                OpEntryPoint Fragment %2 "main"
1063                OpExecutionMode %2 OriginUpperLeft
1064                OpSource ESSL 310
1065           %3 = OpTypeVoid
1066           %4 = OpTypeBool
1067           %5 = OpConstantTrue %4
1068          %10 = OpConstantFalse %4
1069           %6 = OpTypeFunction %3
1070           %2 = OpFunction %3 None %6
1071           %7 = OpLabel
1072                OpBranch %9
1073           %9 = OpLabel
1074                OpBranch %12
1075          %12 = OpLabel
1076                OpBranch %8
1077           %8 = OpLabel
1078          %11 = OpSelect %4 %5 %5 %10
1079                OpReturn
1080                OpFunctionEnd
1081 )";
1082   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1083 }
1084 
TEST(TransformationFlattenConditionalBranchTest,PhiToSelect5)1085 TEST(TransformationFlattenConditionalBranchTest, PhiToSelect5) {
1086   std::string shader = R"(
1087                OpCapability Shader
1088           %1 = OpExtInstImport "GLSL.std.450"
1089                OpMemoryModel Logical GLSL450
1090                OpEntryPoint Fragment %2 "main"
1091                OpExecutionMode %2 OriginUpperLeft
1092                OpSource ESSL 310
1093           %3 = OpTypeVoid
1094           %4 = OpTypeBool
1095           %5 = OpConstantTrue %4
1096          %10 = OpConstantFalse %4
1097           %6 = OpTypeFunction %3
1098         %100 = OpTypePointer Function %4
1099           %2 = OpFunction %3 None %6
1100           %7 = OpLabel
1101         %101 = OpVariable %100 Function
1102         %102 = OpVariable %100 Function
1103                OpSelectionMerge %470 None
1104                OpBranchConditional %5 %454 %462
1105         %454 = OpLabel
1106         %522 = OpLoad %4 %101
1107                OpBranch %470
1108         %462 = OpLabel
1109         %466 = OpLoad %4 %102
1110                OpBranch %470
1111         %470 = OpLabel
1112         %534 = OpPhi %4 %522 %454 %466 %462
1113                OpReturn
1114                OpFunctionEnd
1115 )";
1116 
1117   const auto env = SPV_ENV_UNIVERSAL_1_5;
1118   const auto consumer = nullptr;
1119   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1120   spvtools::ValidatorOptions validator_options;
1121   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1122                                                kConsoleMessageConsumer));
1123 
1124   TransformationContext transformation_context(
1125       MakeUnique<FactManager>(context.get()), validator_options);
1126 
1127   auto transformation = TransformationFlattenConditionalBranch(
1128       7, true, 0, 0, 0,
1129       {MakeSideEffectWrapperInfo(MakeInstructionDescriptor(522, SpvOpLoad, 0),
1130                                  200, 201, 202, 203, 204, 5),
1131        MakeSideEffectWrapperInfo(MakeInstructionDescriptor(466, SpvOpLoad, 0),
1132                                  300, 301, 302, 303, 304, 5)});
1133   ASSERT_TRUE(
1134       transformation.IsApplicable(context.get(), transformation_context));
1135   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1136   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1137                                                kConsoleMessageConsumer));
1138 
1139   std::string after_transformation = R"(
1140                OpCapability Shader
1141           %1 = OpExtInstImport "GLSL.std.450"
1142                OpMemoryModel Logical GLSL450
1143                OpEntryPoint Fragment %2 "main"
1144                OpExecutionMode %2 OriginUpperLeft
1145                OpSource ESSL 310
1146           %3 = OpTypeVoid
1147           %4 = OpTypeBool
1148           %5 = OpConstantTrue %4
1149          %10 = OpConstantFalse %4
1150           %6 = OpTypeFunction %3
1151         %100 = OpTypePointer Function %4
1152           %2 = OpFunction %3 None %6
1153           %7 = OpLabel
1154         %101 = OpVariable %100 Function
1155         %102 = OpVariable %100 Function
1156                OpBranch %454
1157         %454 = OpLabel
1158                OpSelectionMerge %200 None
1159                OpBranchConditional %5 %201 %203
1160         %201 = OpLabel
1161         %202 = OpLoad %4 %101
1162                OpBranch %200
1163         %203 = OpLabel
1164         %204 = OpCopyObject %4 %5
1165                OpBranch %200
1166         %200 = OpLabel
1167         %522 = OpPhi %4 %202 %201 %204 %203
1168                OpBranch %462
1169         %462 = OpLabel
1170                OpSelectionMerge %300 None
1171                OpBranchConditional %5 %303 %301
1172         %301 = OpLabel
1173         %302 = OpLoad %4 %102
1174                OpBranch %300
1175         %303 = OpLabel
1176         %304 = OpCopyObject %4 %5
1177                OpBranch %300
1178         %300 = OpLabel
1179         %466 = OpPhi %4 %302 %301 %304 %303
1180                OpBranch %470
1181         %470 = OpLabel
1182         %534 = OpSelect %4 %5 %522 %466
1183                OpReturn
1184                OpFunctionEnd
1185 )";
1186   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1187 }
1188 
TEST(TransformationFlattenConditionalBranchTest,LoadFromBufferBlockDecoratedStruct)1189 TEST(TransformationFlattenConditionalBranchTest,
1190      LoadFromBufferBlockDecoratedStruct) {
1191   std::string shader = R"(
1192                OpCapability Shader
1193           %1 = OpExtInstImport "GLSL.std.450"
1194                OpMemoryModel Logical GLSL450
1195                OpEntryPoint Fragment %4 "main"
1196                OpExecutionMode %4 OriginUpperLeft
1197                OpSource ESSL 320
1198                OpMemberDecorate %11 0 Offset 0
1199                OpDecorate %11 BufferBlock
1200                OpDecorate %13 DescriptorSet 0
1201                OpDecorate %13 Binding 0
1202           %2 = OpTypeVoid
1203           %3 = OpTypeFunction %2
1204           %6 = OpTypeBool
1205           %7 = OpConstantTrue %6
1206          %10 = OpTypeInt 32 1
1207          %11 = OpTypeStruct %10
1208          %12 = OpTypePointer Uniform %11
1209          %13 = OpVariable %12 Uniform
1210          %21 = OpUndef %11
1211           %4 = OpFunction %2 None %3
1212           %5 = OpLabel
1213                OpSelectionMerge %9 None
1214                OpBranchConditional %7 %8 %9
1215           %8 = OpLabel
1216          %20 = OpLoad %11 %13
1217                OpBranch %9
1218           %9 = OpLabel
1219                OpReturn
1220                OpFunctionEnd
1221   )";
1222 
1223   const auto env = SPV_ENV_UNIVERSAL_1_3;
1224   const auto consumer = nullptr;
1225   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1226   spvtools::ValidatorOptions validator_options;
1227   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1228                                                kConsoleMessageConsumer));
1229   TransformationContext transformation_context(
1230       MakeUnique<FactManager>(context.get()), validator_options);
1231 
1232   auto transformation = TransformationFlattenConditionalBranch(
1233       5, true, 0, 0, 0,
1234       {MakeSideEffectWrapperInfo(MakeInstructionDescriptor(20, SpvOpLoad, 0),
1235                                  100, 101, 102, 103, 104, 21)});
1236   ASSERT_TRUE(
1237       transformation.IsApplicable(context.get(), transformation_context));
1238   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1239   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1240                                                kConsoleMessageConsumer));
1241 }
1242 
TEST(TransformationFlattenConditionalBranchTest,InapplicableSampledImageLoad)1243 TEST(TransformationFlattenConditionalBranchTest, InapplicableSampledImageLoad) {
1244   std::string shader = R"(
1245                OpCapability Shader
1246           %1 = OpExtInstImport "GLSL.std.450"
1247                OpMemoryModel Logical GLSL450
1248                OpEntryPoint Fragment %4 "main" %12 %96
1249                OpExecutionMode %4 OriginUpperLeft
1250                OpSource ESSL 320
1251                OpDecorate %12 BuiltIn FragCoord
1252                OpDecorate %91 DescriptorSet 0
1253                OpDecorate %91 Binding 0
1254                OpDecorate %96 Location 0
1255           %2 = OpTypeVoid
1256           %3 = OpTypeFunction %2
1257           %6 = OpTypeFloat 32
1258           %7 = OpTypeVector %6 2
1259          %10 = OpTypeVector %6 4
1260          %11 = OpTypePointer Input %10
1261          %12 = OpVariable %11 Input
1262          %21 = OpConstant %6 2
1263          %24 = OpTypeInt 32 1
1264          %33 = OpTypeBool
1265          %35 = OpConstantTrue %33
1266          %88 = OpTypeImage %6 2D 0 0 0 1 Unknown
1267          %89 = OpTypeSampledImage %88
1268          %90 = OpTypePointer UniformConstant %89
1269          %91 = OpVariable %90 UniformConstant
1270          %95 = OpTypePointer Output %10
1271          %96 = OpVariable %95 Output
1272         %200 = OpUndef %89
1273           %4 = OpFunction %2 None %3
1274           %5 = OpLabel
1275                OpBranch %28
1276          %28 = OpLabel
1277                OpSelectionMerge %38 None
1278                OpBranchConditional %35 %32 %37
1279          %32 = OpLabel
1280          %40 = OpLoad %89 %91
1281                OpBranch %38
1282          %37 = OpLabel
1283                OpBranch %38
1284          %38 = OpLabel
1285                OpReturn
1286                OpFunctionEnd
1287   )";
1288 
1289   const auto env = SPV_ENV_UNIVERSAL_1_3;
1290   const auto consumer = nullptr;
1291   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1292   spvtools::ValidatorOptions validator_options;
1293   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1294                                                kConsoleMessageConsumer));
1295 
1296   TransformationContext transformation_context(
1297       MakeUnique<FactManager>(context.get()), validator_options);
1298 
1299   ASSERT_FALSE(TransformationFlattenConditionalBranch(
1300                    28, true, 0, 0, 0,
1301                    {MakeSideEffectWrapperInfo(
1302                        MakeInstructionDescriptor(40, SpvOpLoad, 0), 100, 101,
1303                        102, 103, 104, 200)})
1304                    .IsApplicable(context.get(), transformation_context));
1305 }
1306 
TEST(TransformationFlattenConditionalBranchTest,InapplicablePhiToSelectVector)1307 TEST(TransformationFlattenConditionalBranchTest,
1308      InapplicablePhiToSelectVector) {
1309   std::string shader = R"(
1310                OpCapability Shader
1311           %1 = OpExtInstImport "GLSL.std.450"
1312                OpMemoryModel Logical GLSL450
1313                OpEntryPoint Fragment %4 "main"
1314                OpExecutionMode %4 OriginUpperLeft
1315                OpSource ESSL 320
1316           %2 = OpTypeVoid
1317           %3 = OpTypeFunction %2
1318           %6 = OpTypeBool
1319           %7 = OpConstantTrue %6
1320          %10 = OpTypeInt 32 1
1321          %11 = OpTypeVector %10 3
1322          %12 = OpUndef %11
1323           %4 = OpFunction %2 None %3
1324           %5 = OpLabel
1325                OpSelectionMerge %20 None
1326                OpBranchConditional %7 %8 %9
1327           %8 = OpLabel
1328                OpBranch %20
1329           %9 = OpLabel
1330                OpBranch %20
1331          %20 = OpLabel
1332          %21 = OpPhi %11 %12 %8 %12 %9
1333                OpReturn
1334                OpFunctionEnd
1335   )";
1336 
1337   const auto env = SPV_ENV_UNIVERSAL_1_3;
1338   const auto consumer = nullptr;
1339   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1340   spvtools::ValidatorOptions validator_options;
1341   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1342                                                kConsoleMessageConsumer));
1343 
1344   TransformationContext transformation_context(
1345       MakeUnique<FactManager>(context.get()), validator_options);
1346 
1347   auto transformation =
1348       TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {});
1349   ASSERT_FALSE(
1350       transformation.IsApplicable(context.get(), transformation_context));
1351 }
1352 
TEST(TransformationFlattenConditionalBranchTest,InapplicablePhiToSelectVector2)1353 TEST(TransformationFlattenConditionalBranchTest,
1354      InapplicablePhiToSelectVector2) {
1355   std::string shader = R"(
1356                OpCapability Shader
1357           %1 = OpExtInstImport "GLSL.std.450"
1358                OpMemoryModel Logical GLSL450
1359                OpEntryPoint Fragment %4 "main"
1360                OpExecutionMode %4 OriginUpperLeft
1361                OpSource ESSL 320
1362           %2 = OpTypeVoid
1363           %3 = OpTypeFunction %2
1364           %6 = OpTypeBool
1365          %30 = OpTypeVector %6 3
1366          %31 = OpTypeVector %6 2
1367           %7 = OpConstantTrue %6
1368          %10 = OpTypeInt 32 1
1369          %11 = OpTypeVector %10 3
1370          %40 = OpTypeFloat 32
1371          %41 = OpTypeVector %40 4
1372          %12 = OpUndef %11
1373          %60 = OpUndef %41
1374 	 %61 = OpConstantComposite %31 %7 %7
1375           %4 = OpFunction %2 None %3
1376           %5 = OpLabel
1377                OpSelectionMerge %20 None
1378                OpBranchConditional %7 %8 %9
1379           %8 = OpLabel
1380                OpBranch %20
1381           %9 = OpLabel
1382                OpBranch %20
1383          %20 = OpLabel
1384          %21 = OpPhi %11 %12 %8 %12 %9
1385          %22 = OpPhi %11 %12 %8 %12 %9
1386          %23 = OpPhi %41 %60 %8 %60 %9
1387          %24 = OpPhi %31 %61 %8 %61 %9
1388          %25 = OpPhi %41 %60 %8 %60 %9
1389                OpReturn
1390                OpFunctionEnd
1391   )";
1392 
1393   const auto env = SPV_ENV_UNIVERSAL_1_3;
1394   const auto consumer = nullptr;
1395   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1396   spvtools::ValidatorOptions validator_options;
1397   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1398                                                kConsoleMessageConsumer));
1399 
1400   TransformationContext transformation_context(
1401       MakeUnique<FactManager>(context.get()), validator_options);
1402 
1403   auto transformation =
1404       TransformationFlattenConditionalBranch(5, true, 101, 102, 103, {});
1405 
1406   // bvec4 is not present in the module.
1407   ASSERT_FALSE(
1408       transformation.IsApplicable(context.get(), transformation_context));
1409   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1410 }
1411 
TEST(TransformationFlattenConditionalBranchTest,InapplicablePhiToSelectMatrix)1412 TEST(TransformationFlattenConditionalBranchTest,
1413      InapplicablePhiToSelectMatrix) {
1414   std::string shader = R"(
1415                OpCapability Shader
1416           %1 = OpExtInstImport "GLSL.std.450"
1417                OpMemoryModel Logical GLSL450
1418                OpEntryPoint Fragment %4 "main"
1419                OpExecutionMode %4 OriginUpperLeft
1420                OpSource ESSL 320
1421           %2 = OpTypeVoid
1422           %3 = OpTypeFunction %2
1423           %6 = OpTypeBool
1424           %7 = OpConstantTrue %6
1425          %10 = OpTypeFloat 32
1426          %30 = OpTypeVector %10 3
1427          %11 = OpTypeMatrix %30 3
1428          %12 = OpUndef %11
1429           %4 = OpFunction %2 None %3
1430           %5 = OpLabel
1431                OpSelectionMerge %20 None
1432                OpBranchConditional %7 %8 %9
1433           %8 = OpLabel
1434                OpBranch %20
1435           %9 = OpLabel
1436                OpBranch %20
1437          %20 = OpLabel
1438          %21 = OpPhi %11 %12 %8 %12 %9
1439                OpReturn
1440                OpFunctionEnd
1441   )";
1442 
1443   const auto env = SPV_ENV_UNIVERSAL_1_3;
1444   const auto consumer = nullptr;
1445   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1446   spvtools::ValidatorOptions validator_options;
1447   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1448                                                kConsoleMessageConsumer));
1449 
1450   TransformationContext transformation_context(
1451       MakeUnique<FactManager>(context.get()), validator_options);
1452 
1453   auto transformation =
1454       TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {});
1455   ASSERT_FALSE(
1456       transformation.IsApplicable(context.get(), transformation_context));
1457 }
1458 
TEST(TransformationFlattenConditionalBranchTest,ApplicablePhiToSelectVector)1459 TEST(TransformationFlattenConditionalBranchTest, ApplicablePhiToSelectVector) {
1460   std::string shader = R"(
1461                OpCapability Shader
1462           %1 = OpExtInstImport "GLSL.std.450"
1463                OpMemoryModel Logical GLSL450
1464                OpEntryPoint Fragment %4 "main"
1465                OpExecutionMode %4 OriginUpperLeft
1466                OpSource ESSL 320
1467           %2 = OpTypeVoid
1468           %3 = OpTypeFunction %2
1469           %6 = OpTypeBool
1470           %7 = OpConstantTrue %6
1471          %10 = OpTypeInt 32 1
1472          %11 = OpTypeVector %10 3
1473          %12 = OpUndef %11
1474           %4 = OpFunction %2 None %3
1475           %5 = OpLabel
1476                OpSelectionMerge %20 None
1477                OpBranchConditional %7 %8 %9
1478           %8 = OpLabel
1479                OpBranch %20
1480           %9 = OpLabel
1481                OpBranch %20
1482          %20 = OpLabel
1483          %21 = OpPhi %11 %12 %8 %12 %9
1484                OpReturn
1485                OpFunctionEnd
1486   )";
1487 
1488   const auto env = SPV_ENV_UNIVERSAL_1_5;
1489   const auto consumer = nullptr;
1490   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1491   spvtools::ValidatorOptions validator_options;
1492   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1493                                                kConsoleMessageConsumer));
1494 
1495   TransformationContext transformation_context(
1496       MakeUnique<FactManager>(context.get()), validator_options);
1497 
1498   auto transformation =
1499       TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {});
1500   ASSERT_TRUE(
1501       transformation.IsApplicable(context.get(), transformation_context));
1502   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1503   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1504                                                kConsoleMessageConsumer));
1505 
1506   std::string expected_shader = R"(
1507                OpCapability Shader
1508           %1 = OpExtInstImport "GLSL.std.450"
1509                OpMemoryModel Logical GLSL450
1510                OpEntryPoint Fragment %4 "main"
1511                OpExecutionMode %4 OriginUpperLeft
1512                OpSource ESSL 320
1513           %2 = OpTypeVoid
1514           %3 = OpTypeFunction %2
1515           %6 = OpTypeBool
1516           %7 = OpConstantTrue %6
1517          %10 = OpTypeInt 32 1
1518          %11 = OpTypeVector %10 3
1519          %12 = OpUndef %11
1520           %4 = OpFunction %2 None %3
1521           %5 = OpLabel
1522                OpBranch %8
1523           %8 = OpLabel
1524                OpBranch %9
1525           %9 = OpLabel
1526                OpBranch %20
1527          %20 = OpLabel
1528          %21 = OpSelect %11 %7 %12 %12
1529                OpReturn
1530                OpFunctionEnd
1531   )";
1532   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1533 }
1534 
TEST(TransformationFlattenConditionalBranchTest,ApplicablePhiToSelectVector2)1535 TEST(TransformationFlattenConditionalBranchTest, ApplicablePhiToSelectVector2) {
1536   std::string shader = R"(
1537                OpCapability Shader
1538           %1 = OpExtInstImport "GLSL.std.450"
1539                OpMemoryModel Logical GLSL450
1540                OpEntryPoint Fragment %4 "main"
1541                OpExecutionMode %4 OriginUpperLeft
1542                OpSource ESSL 320
1543           %2 = OpTypeVoid
1544           %3 = OpTypeFunction %2
1545           %6 = OpTypeBool
1546          %30 = OpTypeVector %6 3
1547          %31 = OpTypeVector %6 2
1548          %32 = OpTypeVector %6 4
1549           %7 = OpConstantTrue %6
1550          %10 = OpTypeInt 32 1
1551          %11 = OpTypeVector %10 3
1552          %40 = OpTypeFloat 32
1553          %41 = OpTypeVector %40 4
1554          %12 = OpUndef %11
1555          %60 = OpUndef %41
1556 	 %61 = OpConstantComposite %31 %7 %7
1557           %4 = OpFunction %2 None %3
1558           %5 = OpLabel
1559                OpSelectionMerge %20 None
1560                OpBranchConditional %7 %8 %9
1561           %8 = OpLabel
1562                OpBranch %20
1563           %9 = OpLabel
1564                OpBranch %20
1565          %20 = OpLabel
1566          %21 = OpPhi %11 %12 %8 %12 %9
1567          %22 = OpPhi %11 %12 %8 %12 %9
1568          %23 = OpPhi %41 %60 %8 %60 %9
1569          %24 = OpPhi %31 %61 %8 %61 %9
1570          %25 = OpPhi %41 %60 %8 %60 %9
1571                OpReturn
1572                OpFunctionEnd
1573   )";
1574 
1575   const auto env = SPV_ENV_UNIVERSAL_1_3;
1576   const auto consumer = nullptr;
1577   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1578   spvtools::ValidatorOptions validator_options;
1579   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1580                                                kConsoleMessageConsumer));
1581 
1582   TransformationContext transformation_context(
1583       MakeUnique<FactManager>(context.get()), validator_options);
1584 
1585   // No id for the 2D vector case is provided.
1586   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 0, 102, 103, {})
1587                    .IsApplicable(context.get(), transformation_context));
1588 
1589   // No id for the 3D vector case is provided.
1590   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 101, 0, 103, {})
1591                    .IsApplicable(context.get(), transformation_context));
1592 
1593   // No id for the 4D vector case is provided.
1594   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 101, 102, 0, {})
1595                    .IsApplicable(context.get(), transformation_context));
1596 
1597   // %10 is not fresh
1598   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 10, 102, 103, {})
1599                    .IsApplicable(context.get(), transformation_context));
1600 
1601   // %10 is not fresh
1602   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 101, 10, 103, {})
1603                    .IsApplicable(context.get(), transformation_context));
1604 
1605   // %10 is not fresh
1606   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 101, 102, 10, {})
1607                    .IsApplicable(context.get(), transformation_context));
1608 
1609   // Duplicate "fresh" ids used for boolean vector constructors
1610   ASSERT_FALSE(
1611       TransformationFlattenConditionalBranch(5, true, 101, 102, 102, {})
1612           .IsApplicable(context.get(), transformation_context));
1613 
1614   auto transformation =
1615       TransformationFlattenConditionalBranch(5, true, 101, 102, 103, {});
1616 
1617   ASSERT_TRUE(
1618       transformation.IsApplicable(context.get(), transformation_context));
1619   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1620   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1621                                                kConsoleMessageConsumer));
1622 
1623   std::string expected_shader = R"(
1624                OpCapability Shader
1625           %1 = OpExtInstImport "GLSL.std.450"
1626                OpMemoryModel Logical GLSL450
1627                OpEntryPoint Fragment %4 "main"
1628                OpExecutionMode %4 OriginUpperLeft
1629                OpSource ESSL 320
1630           %2 = OpTypeVoid
1631           %3 = OpTypeFunction %2
1632           %6 = OpTypeBool
1633          %30 = OpTypeVector %6 3
1634          %31 = OpTypeVector %6 2
1635          %32 = OpTypeVector %6 4
1636           %7 = OpConstantTrue %6
1637          %10 = OpTypeInt 32 1
1638          %11 = OpTypeVector %10 3
1639          %40 = OpTypeFloat 32
1640          %41 = OpTypeVector %40 4
1641          %12 = OpUndef %11
1642          %60 = OpUndef %41
1643 	 %61 = OpConstantComposite %31 %7 %7
1644           %4 = OpFunction %2 None %3
1645           %5 = OpLabel
1646                OpBranch %8
1647           %8 = OpLabel
1648                OpBranch %9
1649           %9 = OpLabel
1650                OpBranch %20
1651          %20 = OpLabel
1652         %103 = OpCompositeConstruct %32 %7 %7 %7 %7
1653         %102 = OpCompositeConstruct %30 %7 %7 %7
1654         %101 = OpCompositeConstruct %31 %7 %7
1655          %21 = OpSelect %11 %102 %12 %12
1656          %22 = OpSelect %11 %102 %12 %12
1657          %23 = OpSelect %41 %103 %60 %60
1658          %24 = OpSelect %31 %101 %61 %61
1659          %25 = OpSelect %41 %103 %60 %60
1660                OpReturn
1661                OpFunctionEnd
1662   )";
1663 
1664   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1665 }
1666 
TEST(TransformationFlattenConditionalBranchTest,ApplicablePhiToSelectVector3)1667 TEST(TransformationFlattenConditionalBranchTest, ApplicablePhiToSelectVector3) {
1668   std::string shader = R"(
1669                OpCapability Shader
1670           %1 = OpExtInstImport "GLSL.std.450"
1671                OpMemoryModel Logical GLSL450
1672                OpEntryPoint Fragment %4 "main"
1673                OpExecutionMode %4 OriginUpperLeft
1674                OpSource ESSL 320
1675           %2 = OpTypeVoid
1676           %3 = OpTypeFunction %2
1677           %6 = OpTypeBool
1678          %30 = OpTypeVector %6 3
1679          %31 = OpTypeVector %6 2
1680          %32 = OpTypeVector %6 4
1681           %7 = OpConstantTrue %6
1682          %10 = OpTypeInt 32 1
1683          %11 = OpTypeVector %10 3
1684          %40 = OpTypeFloat 32
1685          %41 = OpTypeVector %40 4
1686          %12 = OpUndef %11
1687          %60 = OpUndef %41
1688 	 %61 = OpConstantComposite %31 %7 %7
1689           %4 = OpFunction %2 None %3
1690           %5 = OpLabel
1691                OpSelectionMerge %20 None
1692                OpBranchConditional %7 %8 %9
1693           %8 = OpLabel
1694                OpBranch %20
1695           %9 = OpLabel
1696                OpBranch %20
1697          %20 = OpLabel
1698          %21 = OpPhi %11 %12 %8 %12 %9
1699          %22 = OpPhi %11 %12 %8 %12 %9
1700          %23 = OpPhi %41 %60 %8 %60 %9
1701          %24 = OpPhi %31 %61 %8 %61 %9
1702          %25 = OpPhi %41 %60 %8 %60 %9
1703                OpReturn
1704                OpFunctionEnd
1705   )";
1706 
1707   const auto env = SPV_ENV_UNIVERSAL_1_5;
1708   const auto consumer = nullptr;
1709   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1710   spvtools::ValidatorOptions validator_options;
1711   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1712                                                kConsoleMessageConsumer));
1713 
1714   TransformationContext transformation_context(
1715       MakeUnique<FactManager>(context.get()), validator_options);
1716 
1717   auto transformation =
1718       TransformationFlattenConditionalBranch(5, true, 101, 0, 103, {});
1719 
1720   ASSERT_TRUE(
1721       transformation.IsApplicable(context.get(), transformation_context));
1722   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1723   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1724                                                kConsoleMessageConsumer));
1725 
1726   // Check that the in operands of any OpSelect instructions all have the
1727   // appropriate operand type.
1728   context->module()->ForEachInst([](opt::Instruction* inst) {
1729     if (inst->opcode() == SpvOpSelect) {
1730       ASSERT_EQ(SPV_OPERAND_TYPE_ID, inst->GetInOperand(0).type);
1731       ASSERT_EQ(SPV_OPERAND_TYPE_ID, inst->GetInOperand(1).type);
1732       ASSERT_EQ(SPV_OPERAND_TYPE_ID, inst->GetInOperand(2).type);
1733     }
1734   });
1735 
1736   std::string expected_shader = R"(
1737                OpCapability Shader
1738           %1 = OpExtInstImport "GLSL.std.450"
1739                OpMemoryModel Logical GLSL450
1740                OpEntryPoint Fragment %4 "main"
1741                OpExecutionMode %4 OriginUpperLeft
1742                OpSource ESSL 320
1743           %2 = OpTypeVoid
1744           %3 = OpTypeFunction %2
1745           %6 = OpTypeBool
1746          %30 = OpTypeVector %6 3
1747          %31 = OpTypeVector %6 2
1748          %32 = OpTypeVector %6 4
1749           %7 = OpConstantTrue %6
1750          %10 = OpTypeInt 32 1
1751          %11 = OpTypeVector %10 3
1752          %40 = OpTypeFloat 32
1753          %41 = OpTypeVector %40 4
1754          %12 = OpUndef %11
1755          %60 = OpUndef %41
1756 	 %61 = OpConstantComposite %31 %7 %7
1757           %4 = OpFunction %2 None %3
1758           %5 = OpLabel
1759                OpBranch %8
1760           %8 = OpLabel
1761                OpBranch %9
1762           %9 = OpLabel
1763                OpBranch %20
1764          %20 = OpLabel
1765         %103 = OpCompositeConstruct %32 %7 %7 %7 %7
1766         %101 = OpCompositeConstruct %31 %7 %7
1767          %21 = OpSelect %11 %7 %12 %12
1768          %22 = OpSelect %11 %7 %12 %12
1769          %23 = OpSelect %41 %103 %60 %60
1770          %24 = OpSelect %31 %101 %61 %61
1771          %25 = OpSelect %41 %103 %60 %60
1772                OpReturn
1773                OpFunctionEnd
1774   )";
1775 
1776   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1777 }
1778 
TEST(TransformationFlattenConditionalBranchTest,ApplicablePhiToSelectMatrix)1779 TEST(TransformationFlattenConditionalBranchTest, ApplicablePhiToSelectMatrix) {
1780   std::string shader = R"(
1781                OpCapability Shader
1782           %1 = OpExtInstImport "GLSL.std.450"
1783                OpMemoryModel Logical GLSL450
1784                OpEntryPoint Fragment %4 "main"
1785                OpExecutionMode %4 OriginUpperLeft
1786                OpSource ESSL 320
1787           %2 = OpTypeVoid
1788           %3 = OpTypeFunction %2
1789           %6 = OpTypeBool
1790           %7 = OpConstantTrue %6
1791          %10 = OpTypeFloat 32
1792          %30 = OpTypeVector %10 3
1793          %11 = OpTypeMatrix %30 3
1794          %12 = OpUndef %11
1795           %4 = OpFunction %2 None %3
1796           %5 = OpLabel
1797                OpSelectionMerge %20 None
1798                OpBranchConditional %7 %8 %9
1799           %8 = OpLabel
1800                OpBranch %20
1801           %9 = OpLabel
1802                OpBranch %20
1803          %20 = OpLabel
1804          %21 = OpPhi %11 %12 %8 %12 %9
1805                OpReturn
1806                OpFunctionEnd
1807   )";
1808 
1809   const auto env = SPV_ENV_UNIVERSAL_1_5;
1810   const auto consumer = nullptr;
1811   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1812   spvtools::ValidatorOptions validator_options;
1813   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1814                                                kConsoleMessageConsumer));
1815 
1816   TransformationContext transformation_context(
1817       MakeUnique<FactManager>(context.get()), validator_options);
1818 
1819   auto transformation =
1820       TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {});
1821   ASSERT_TRUE(
1822       transformation.IsApplicable(context.get(), transformation_context));
1823   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1824   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1825                                                kConsoleMessageConsumer));
1826 
1827   std::string expected_shader = R"(
1828                OpCapability Shader
1829           %1 = OpExtInstImport "GLSL.std.450"
1830                OpMemoryModel Logical GLSL450
1831                OpEntryPoint Fragment %4 "main"
1832                OpExecutionMode %4 OriginUpperLeft
1833                OpSource ESSL 320
1834           %2 = OpTypeVoid
1835           %3 = OpTypeFunction %2
1836           %6 = OpTypeBool
1837           %7 = OpConstantTrue %6
1838          %10 = OpTypeFloat 32
1839          %30 = OpTypeVector %10 3
1840          %11 = OpTypeMatrix %30 3
1841          %12 = OpUndef %11
1842           %4 = OpFunction %2 None %3
1843           %5 = OpLabel
1844                OpBranch %8
1845           %8 = OpLabel
1846                OpBranch %9
1847           %9 = OpLabel
1848                OpBranch %20
1849          %20 = OpLabel
1850          %21 = OpSelect %11 %7 %12 %12
1851                OpReturn
1852                OpFunctionEnd
1853   )";
1854   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1855 }
1856 
TEST(TransformationFlattenConditionalBranchTest,InapplicableConditionIsIrrelevant)1857 TEST(TransformationFlattenConditionalBranchTest,
1858      InapplicableConditionIsIrrelevant) {
1859   std::string shader = R"(
1860                OpCapability Shader
1861           %1 = OpExtInstImport "GLSL.std.450"
1862                OpMemoryModel Logical GLSL450
1863                OpEntryPoint Fragment %4 "main"
1864                OpExecutionMode %4 OriginUpperLeft
1865                OpSource ESSL 320
1866           %2 = OpTypeVoid
1867           %3 = OpTypeFunction %2
1868           %6 = OpTypeBool
1869           %7 = OpConstantTrue %6
1870          %10 = OpTypeInt 32 1
1871           %4 = OpFunction %2 None %3
1872           %5 = OpLabel
1873                OpSelectionMerge %9 None
1874                OpBranchConditional %7 %8 %9
1875           %8 = OpLabel
1876                OpBranch %9
1877           %9 = OpLabel
1878                OpReturn
1879                OpFunctionEnd
1880   )";
1881 
1882   const auto env = SPV_ENV_UNIVERSAL_1_3;
1883   const auto consumer = nullptr;
1884   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1885   spvtools::ValidatorOptions validator_options;
1886   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1887                                                kConsoleMessageConsumer));
1888   TransformationContext transformation_context(
1889       MakeUnique<FactManager>(context.get()), validator_options);
1890 
1891   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(7);
1892 
1893   // Inapplicable because the branch condition, %7, is irrelevant.
1894   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {})
1895                    .IsApplicable(context.get(), transformation_context));
1896 }
1897 
TEST(TransformationFlattenConditionalBranchTest,OpPhiWhenTrueBranchIsConvergenceBlock)1898 TEST(TransformationFlattenConditionalBranchTest,
1899      OpPhiWhenTrueBranchIsConvergenceBlock) {
1900   std::string shader = R"(
1901                OpCapability Shader
1902           %1 = OpExtInstImport "GLSL.std.450"
1903                OpMemoryModel Logical GLSL450
1904                OpEntryPoint Fragment %4 "main"
1905                OpExecutionMode %4 OriginUpperLeft
1906                OpSource ESSL 320
1907                OpName %4 "main"
1908           %2 = OpTypeVoid
1909           %3 = OpTypeFunction %2
1910           %6 = OpTypeBool
1911           %7 = OpConstantTrue %6
1912           %4 = OpFunction %2 None %3
1913           %5 = OpLabel
1914                OpSelectionMerge %9 None
1915                OpBranchConditional %7 %9 %8
1916           %8 = OpLabel
1917          %10 = OpCopyObject %6 %7
1918                OpBranch %9
1919           %9 = OpLabel
1920          %11 = OpPhi %6 %10 %8 %7 %5
1921          %12 = OpPhi %6 %7 %5 %10 %8
1922                OpReturn
1923                OpFunctionEnd
1924 )";
1925 
1926   const auto env = SPV_ENV_UNIVERSAL_1_3;
1927   const auto consumer = nullptr;
1928   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1929   spvtools::ValidatorOptions validator_options;
1930   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1931                                                kConsoleMessageConsumer));
1932   TransformationContext transformation_context(
1933       MakeUnique<FactManager>(context.get()), validator_options);
1934 
1935   TransformationFlattenConditionalBranch transformation(5, true, 0, 0, 0, {});
1936   ASSERT_TRUE(
1937       transformation.IsApplicable(context.get(), transformation_context));
1938   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1939   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1940                                                kConsoleMessageConsumer));
1941 
1942   std::string expected = R"(
1943                OpCapability Shader
1944           %1 = OpExtInstImport "GLSL.std.450"
1945                OpMemoryModel Logical GLSL450
1946                OpEntryPoint Fragment %4 "main"
1947                OpExecutionMode %4 OriginUpperLeft
1948                OpSource ESSL 320
1949                OpName %4 "main"
1950           %2 = OpTypeVoid
1951           %3 = OpTypeFunction %2
1952           %6 = OpTypeBool
1953           %7 = OpConstantTrue %6
1954           %4 = OpFunction %2 None %3
1955           %5 = OpLabel
1956                OpBranch %8
1957           %8 = OpLabel
1958          %10 = OpCopyObject %6 %7
1959                OpBranch %9
1960           %9 = OpLabel
1961          %11 = OpSelect %6 %7 %7 %10
1962          %12 = OpSelect %6 %7 %7 %10
1963                OpReturn
1964                OpFunctionEnd
1965 )";
1966 
1967   ASSERT_TRUE(IsEqual(env, expected, context.get()));
1968 }
1969 
TEST(TransformationFlattenConditionalBranchTest,OpPhiWhenFalseBranchIsConvergenceBlock)1970 TEST(TransformationFlattenConditionalBranchTest,
1971      OpPhiWhenFalseBranchIsConvergenceBlock) {
1972   std::string shader = R"(
1973                OpCapability Shader
1974           %1 = OpExtInstImport "GLSL.std.450"
1975                OpMemoryModel Logical GLSL450
1976                OpEntryPoint Fragment %4 "main"
1977                OpExecutionMode %4 OriginUpperLeft
1978                OpSource ESSL 320
1979                OpName %4 "main"
1980           %2 = OpTypeVoid
1981           %3 = OpTypeFunction %2
1982           %6 = OpTypeBool
1983           %7 = OpConstantTrue %6
1984           %4 = OpFunction %2 None %3
1985           %5 = OpLabel
1986                OpSelectionMerge %9 None
1987                OpBranchConditional %7 %8 %9
1988           %8 = OpLabel
1989          %10 = OpCopyObject %6 %7
1990                OpBranch %9
1991           %9 = OpLabel
1992          %11 = OpPhi %6 %10 %8 %7 %5
1993          %12 = OpPhi %6 %7 %5 %10 %8
1994                OpReturn
1995                OpFunctionEnd
1996 )";
1997 
1998   const auto env = SPV_ENV_UNIVERSAL_1_3;
1999   const auto consumer = nullptr;
2000   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2001   spvtools::ValidatorOptions validator_options;
2002   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2003                                                kConsoleMessageConsumer));
2004   TransformationContext transformation_context(
2005       MakeUnique<FactManager>(context.get()), validator_options);
2006 
2007   TransformationFlattenConditionalBranch transformation(5, true, 0, 0, 0, {});
2008   ASSERT_TRUE(
2009       transformation.IsApplicable(context.get(), transformation_context));
2010   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
2011   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2012                                                kConsoleMessageConsumer));
2013 
2014   std::string expected = R"(
2015                OpCapability Shader
2016           %1 = OpExtInstImport "GLSL.std.450"
2017                OpMemoryModel Logical GLSL450
2018                OpEntryPoint Fragment %4 "main"
2019                OpExecutionMode %4 OriginUpperLeft
2020                OpSource ESSL 320
2021                OpName %4 "main"
2022           %2 = OpTypeVoid
2023           %3 = OpTypeFunction %2
2024           %6 = OpTypeBool
2025           %7 = OpConstantTrue %6
2026           %4 = OpFunction %2 None %3
2027           %5 = OpLabel
2028                OpBranch %8
2029           %8 = OpLabel
2030          %10 = OpCopyObject %6 %7
2031                OpBranch %9
2032           %9 = OpLabel
2033          %11 = OpSelect %6 %7 %10 %7
2034          %12 = OpSelect %6 %7 %10 %7
2035                OpReturn
2036                OpFunctionEnd
2037 )";
2038 
2039   ASSERT_TRUE(IsEqual(env, expected, context.get()));
2040 }
2041 
TEST(TransformationFlattenConditionalBranchTest,ContainsDeadBlocksTest)2042 TEST(TransformationFlattenConditionalBranchTest, ContainsDeadBlocksTest) {
2043   std::string shader = R"(
2044                OpCapability Shader
2045           %1 = OpExtInstImport "GLSL.std.450"
2046                OpMemoryModel Logical GLSL450
2047                OpEntryPoint Fragment %4 "main"
2048                OpExecutionMode %4 OriginUpperLeft
2049                OpSource ESSL 320
2050                OpName %4 "main"
2051           %2 = OpTypeVoid
2052           %3 = OpTypeFunction %2
2053           %6 = OpTypeBool
2054           %7 = OpConstantFalse %6
2055           %4 = OpFunction %2 None %3
2056           %5 = OpLabel
2057                OpSelectionMerge %9 None
2058                OpBranchConditional %7 %8 %9
2059           %8 = OpLabel
2060          %10 = OpCopyObject %6 %7
2061                OpBranch %9
2062           %9 = OpLabel
2063          %11 = OpPhi %6 %10 %8 %7 %5
2064          %12 = OpPhi %6 %7 %5 %10 %8
2065                OpReturn
2066                OpFunctionEnd
2067   )";
2068 
2069   const auto env = SPV_ENV_UNIVERSAL_1_3;
2070   const auto consumer = nullptr;
2071   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2072   spvtools::ValidatorOptions validator_options;
2073   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2074                                                kConsoleMessageConsumer));
2075   TransformationContext transformation_context(
2076       MakeUnique<FactManager>(context.get()), validator_options);
2077 
2078   TransformationFlattenConditionalBranch transformation(5, true, 0, 0, 0, {});
2079   ASSERT_TRUE(
2080       transformation.IsApplicable(context.get(), transformation_context));
2081 
2082   transformation_context.GetFactManager()->AddFactBlockIsDead(8);
2083 
2084   ASSERT_FALSE(
2085       transformation.IsApplicable(context.get(), transformation_context));
2086 }
2087 
TEST(TransformationFlattenConditionalBranchTest,ContainsContinueBlockTest)2088 TEST(TransformationFlattenConditionalBranchTest, ContainsContinueBlockTest) {
2089   std::string shader = R"(
2090                OpCapability Shader
2091           %1 = OpExtInstImport "GLSL.std.450"
2092                OpMemoryModel Logical GLSL450
2093                OpEntryPoint Fragment %4 "main"
2094                OpExecutionMode %4 OriginUpperLeft
2095                OpSource ESSL 320
2096                OpName %4 "main"
2097           %2 = OpTypeVoid
2098           %3 = OpTypeFunction %2
2099           %6 = OpTypeBool
2100           %7 = OpConstantFalse %6
2101           %4 = OpFunction %2 None %3
2102          %12 = OpLabel
2103                OpBranch %13
2104          %13 = OpLabel
2105                OpLoopMerge %15 %14 None
2106                OpBranchConditional %7 %5 %15
2107           %5 = OpLabel
2108                OpSelectionMerge %11 None
2109                OpBranchConditional %7 %9 %10
2110           %9 = OpLabel
2111                OpBranch %11
2112          %10 = OpLabel
2113                OpBranch %14
2114          %11 = OpLabel
2115                OpBranch %14
2116          %14 = OpLabel
2117                OpBranch %13
2118          %15 = OpLabel
2119                OpReturn
2120                OpFunctionEnd
2121   )";
2122 
2123   const auto env = SPV_ENV_UNIVERSAL_1_3;
2124   const auto consumer = nullptr;
2125   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2126   spvtools::ValidatorOptions validator_options;
2127   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2128                                                kConsoleMessageConsumer));
2129   TransformationContext transformation_context(
2130       MakeUnique<FactManager>(context.get()), validator_options);
2131 
2132   ASSERT_FALSE(TransformationFlattenConditionalBranch(5, true, 0, 0, 0, {})
2133                    .IsApplicable(context.get(), transformation_context));
2134 }
2135 
TEST(TransformationFlattenConditionalBranchTest,ContainsSynonymCreation)2136 TEST(TransformationFlattenConditionalBranchTest, ContainsSynonymCreation) {
2137   std::string shader = R"(
2138                OpCapability Shader
2139           %1 = OpExtInstImport "GLSL.std.450"
2140                OpMemoryModel Logical GLSL450
2141                OpEntryPoint Fragment %4 "main"
2142                OpExecutionMode %4 OriginUpperLeft
2143                OpSource ESSL 320
2144                OpName %4 "main"
2145           %2 = OpTypeVoid
2146           %3 = OpTypeFunction %2
2147           %6 = OpTypeBool
2148           %7 = OpConstantFalse %6
2149           %8 = OpTypeInt 32 0
2150           %9 = OpTypePointer Function %8
2151          %10 = OpConstant %8 42
2152          %80 = OpConstant %8 0
2153           %4 = OpFunction %2 None %3
2154          %11 = OpLabel
2155          %20 = OpVariable %9 Function
2156                OpBranch %12
2157          %12 = OpLabel
2158                OpSelectionMerge %31 None
2159                OpBranchConditional %7 %30 %31
2160          %30 = OpLabel
2161                OpStore %20 %10
2162          %21 = OpLoad %8 %20
2163                OpBranch %31
2164          %31 = OpLabel
2165                OpBranch %14
2166          %14 = OpLabel
2167                OpReturn
2168                OpFunctionEnd
2169   )";
2170 
2171   const auto env = SPV_ENV_UNIVERSAL_1_3;
2172   const auto consumer = nullptr;
2173   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2174   spvtools::ValidatorOptions validator_options;
2175   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2176                                                kConsoleMessageConsumer));
2177   TransformationContext transformation_context(
2178       MakeUnique<FactManager>(context.get()), validator_options);
2179 
2180   transformation_context.GetFactManager()->AddFactDataSynonym(
2181       MakeDataDescriptor(10, {}), MakeDataDescriptor(21, {}));
2182   ASSERT_FALSE(TransformationFlattenConditionalBranch(
2183                    12, true, 0, 0, 0,
2184                    {MakeSideEffectWrapperInfo(
2185                         MakeInstructionDescriptor(30, SpvOpStore, 0), 100, 101),
2186                     MakeSideEffectWrapperInfo(
2187                         MakeInstructionDescriptor(21, SpvOpLoad, 0), 102, 103,
2188                         104, 105, 106, 80)})
2189                    .IsApplicable(context.get(), transformation_context));
2190 }
2191 
2192 }  // namespace
2193 }  // namespace fuzz
2194 }  // namespace spvtools
2195