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