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