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