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