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