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_duplicate_region_with_selection.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 "test/fuzz/fuzz_test_util.h"
21
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25
TEST(TransformationDuplicateRegionWithSelectionTest, BasicUseTest)26 TEST(TransformationDuplicateRegionWithSelectionTest, BasicUseTest) {
27 // This test handles a case where the ids from the original region are used in
28 // subsequent block.
29
30 std::string shader = R"(
31 OpCapability Shader
32 OpCapability VariablePointers
33 %1 = OpExtInstImport "GLSL.std.450"
34 OpMemoryModel Logical GLSL450
35 OpEntryPoint Fragment %4 "main"
36 OpExecutionMode %4 OriginUpperLeft
37 OpSource ESSL 310
38 OpName %4 "main"
39 OpName %10 "fun(i1;"
40 OpName %9 "a"
41 OpName %12 "b"
42 OpName %18 "c"
43 OpName %20 "param"
44 %2 = OpTypeVoid
45 %3 = OpTypeFunction %2
46 %6 = OpTypeInt 32 1
47 %7 = OpTypePointer Function %6
48 %8 = OpTypeFunction %2 %7
49 %14 = OpConstant %6 2
50 %16 = OpTypeBool
51 %17 = OpTypePointer Function %16
52 %19 = OpConstantTrue %16
53 %4 = OpFunction %2 None %3
54 %5 = OpLabel
55 %18 = OpVariable %17 Function
56 %20 = OpVariable %7 Function
57 OpStore %18 %19
58 OpStore %20 %14
59 %21 = OpFunctionCall %2 %10 %20
60 OpReturn
61 OpFunctionEnd
62 %10 = OpFunction %2 None %8
63 %9 = OpFunctionParameter %7
64 %11 = OpLabel
65 %12 = OpVariable %7 Function
66 OpBranch %800
67 %800 = OpLabel
68 %13 = OpLoad %6 %9
69 %15 = OpIAdd %6 %13 %14
70 OpStore %12 %15
71 OpBranch %900
72 %900 = OpLabel
73 %901 = OpIAdd %6 %15 %13
74 %902 = OpISub %6 %13 %15
75 OpReturn
76 OpFunctionEnd
77 )";
78
79 const auto env = SPV_ENV_UNIVERSAL_1_4;
80 const auto consumer = nullptr;
81 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
82 spvtools::ValidatorOptions validator_options;
83 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
84 kConsoleMessageConsumer));
85 TransformationContext transformation_context(
86 MakeUnique<FactManager>(context.get()), validator_options);
87 TransformationDuplicateRegionWithSelection transformation_good_1 =
88 TransformationDuplicateRegionWithSelection(
89 500, 19, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
90 {{13, 301}, {15, 302}});
91
92 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
93 transformation_context));
94 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
95 &transformation_context);
96
97 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
98 kConsoleMessageConsumer));
99 std::string expected_shader = R"(
100 OpCapability Shader
101 OpCapability VariablePointers
102 %1 = OpExtInstImport "GLSL.std.450"
103 OpMemoryModel Logical GLSL450
104 OpEntryPoint Fragment %4 "main"
105 OpExecutionMode %4 OriginUpperLeft
106 OpSource ESSL 310
107 OpName %4 "main"
108 OpName %10 "fun(i1;"
109 OpName %9 "a"
110 OpName %12 "b"
111 OpName %18 "c"
112 OpName %20 "param"
113 %2 = OpTypeVoid
114 %3 = OpTypeFunction %2
115 %6 = OpTypeInt 32 1
116 %7 = OpTypePointer Function %6
117 %8 = OpTypeFunction %2 %7
118 %14 = OpConstant %6 2
119 %16 = OpTypeBool
120 %17 = OpTypePointer Function %16
121 %19 = OpConstantTrue %16
122 %4 = OpFunction %2 None %3
123 %5 = OpLabel
124 %18 = OpVariable %17 Function
125 %20 = OpVariable %7 Function
126 OpStore %18 %19
127 OpStore %20 %14
128 %21 = OpFunctionCall %2 %10 %20
129 OpReturn
130 OpFunctionEnd
131 %10 = OpFunction %2 None %8
132 %9 = OpFunctionParameter %7
133 %11 = OpLabel
134 %12 = OpVariable %7 Function
135 OpBranch %500
136 %500 = OpLabel
137 OpSelectionMerge %501 None
138 OpBranchConditional %19 %800 %100
139 %800 = OpLabel
140 %13 = OpLoad %6 %9
141 %15 = OpIAdd %6 %13 %14
142 OpStore %12 %15
143 OpBranch %501
144 %100 = OpLabel
145 %201 = OpLoad %6 %9
146 %202 = OpIAdd %6 %201 %14
147 OpStore %12 %202
148 OpBranch %501
149 %501 = OpLabel
150 %301 = OpPhi %6 %13 %800 %201 %100
151 %302 = OpPhi %6 %15 %800 %202 %100
152 OpBranch %900
153 %900 = OpLabel
154 %901 = OpIAdd %6 %302 %301
155 %902 = OpISub %6 %301 %302
156 OpReturn
157 OpFunctionEnd
158 )";
159 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
160 }
161
162 TEST(TransformationDuplicateRegionWithSelectionTest, BasicExitBlockTest) {
163 // This test handles a case where the exit block of the region is the exit
164 // block of the containing function.
165
166 std::string shader = R"(
167 OpCapability Shader
168 OpCapability VariablePointers
169 %1 = OpExtInstImport "GLSL.std.450"
170 OpMemoryModel Logical GLSL450
171 OpEntryPoint Fragment %4 "main"
172 OpExecutionMode %4 OriginUpperLeft
173 OpSource ESSL 310
174 OpName %4 "main"
175 OpName %10 "fun(i1;"
176 OpName %9 "a"
177 OpName %12 "b"
178 OpName %18 "c"
179 OpName %20 "param"
180 %2 = OpTypeVoid
181 %3 = OpTypeFunction %2
182 %6 = OpTypeInt 32 1
183 %7 = OpTypePointer Function %6
184 %8 = OpTypeFunction %2 %7
185 %14 = OpConstant %6 2
186 %16 = OpTypeBool
187 %17 = OpTypePointer Function %16
188 %19 = OpConstantTrue %16
189 %4 = OpFunction %2 None %3
190 %5 = OpLabel
191 %18 = OpVariable %17 Function
192 %20 = OpVariable %7 Function
193 OpStore %18 %19
194 OpStore %20 %14
195 %21 = OpFunctionCall %2 %10 %20
196 OpReturn
197 OpFunctionEnd
198 %10 = OpFunction %2 None %8
199 %9 = OpFunctionParameter %7
200 %11 = OpLabel
201 %12 = OpVariable %7 Function
202 OpBranch %800
203 %800 = OpLabel
204 %13 = OpLoad %6 %9
205 %15 = OpIAdd %6 %13 %14
206 OpStore %12 %15
207 OpReturn
208 OpFunctionEnd
209 )";
210
211 const auto env = SPV_ENV_UNIVERSAL_1_4;
212 const auto consumer = nullptr;
213 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
214 spvtools::ValidatorOptions validator_options;
215 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
216 kConsoleMessageConsumer));
217 TransformationContext transformation_context(
218 MakeUnique<FactManager>(context.get()), validator_options);
219 TransformationDuplicateRegionWithSelection transformation_good_1 =
220 TransformationDuplicateRegionWithSelection(
221 500, 19, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
222 {{13, 301}, {15, 302}});
223
224 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
225 transformation_context));
226 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
227 &transformation_context);
228
229 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
230 kConsoleMessageConsumer));
231
232 std::string expected_shader = R"(
233 OpCapability Shader
234 OpCapability VariablePointers
235 %1 = OpExtInstImport "GLSL.std.450"
236 OpMemoryModel Logical GLSL450
237 OpEntryPoint Fragment %4 "main"
238 OpExecutionMode %4 OriginUpperLeft
239 OpSource ESSL 310
240 OpName %4 "main"
241 OpName %10 "fun(i1;"
242 OpName %9 "a"
243 OpName %12 "b"
244 OpName %18 "c"
245 OpName %20 "param"
246 %2 = OpTypeVoid
247 %3 = OpTypeFunction %2
248 %6 = OpTypeInt 32 1
249 %7 = OpTypePointer Function %6
250 %8 = OpTypeFunction %2 %7
251 %14 = OpConstant %6 2
252 %16 = OpTypeBool
253 %17 = OpTypePointer Function %16
254 %19 = OpConstantTrue %16
255 %4 = OpFunction %2 None %3
256 %5 = OpLabel
257 %18 = OpVariable %17 Function
258 %20 = OpVariable %7 Function
259 OpStore %18 %19
260 OpStore %20 %14
261 %21 = OpFunctionCall %2 %10 %20
262 OpReturn
263 OpFunctionEnd
264 %10 = OpFunction %2 None %8
265 %9 = OpFunctionParameter %7
266 %11 = OpLabel
267 %12 = OpVariable %7 Function
268 OpBranch %500
269 %500 = OpLabel
270 OpSelectionMerge %501 None
271 OpBranchConditional %19 %800 %100
272 %800 = OpLabel
273 %13 = OpLoad %6 %9
274 %15 = OpIAdd %6 %13 %14
275 OpStore %12 %15
276 OpBranch %501
277 %100 = OpLabel
278 %201 = OpLoad %6 %9
279 %202 = OpIAdd %6 %201 %14
280 OpStore %12 %202
281 OpBranch %501
282 %501 = OpLabel
283 %301 = OpPhi %6 %13 %800 %201 %100
284 %302 = OpPhi %6 %15 %800 %202 %100
285 OpReturn
286 OpFunctionEnd
287
288 )";
289 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
290 }
291
292 TEST(TransformationDuplicateRegionWithSelectionTest, NotApplicableCFGTest) {
293 // This test handles few cases where the transformation is not applicable
294 // because of the control flow graph or layout of the blocks.
295
296 std::string shader = R"(
297 OpCapability Shader
298 %1 = OpExtInstImport "GLSL.std.450"
299 OpMemoryModel Logical GLSL450
300 OpEntryPoint Fragment %4 "main"
301 OpExecutionMode %4 OriginUpperLeft
302 OpSource ESSL 310
303 OpName %4 "main"
304 OpName %10 "fun(i1;"
305 OpName %9 "a"
306 OpName %18 "b"
307 OpName %25 "c"
308 OpName %27 "param"
309 %2 = OpTypeVoid
310 %3 = OpTypeFunction %2
311 %6 = OpTypeInt 32 1
312 %7 = OpTypePointer Function %6
313 %8 = OpTypeFunction %2 %7
314 %13 = OpConstant %6 2
315 %14 = OpTypeBool
316 %24 = OpTypePointer Function %14
317 %26 = OpConstantTrue %14
318 %4 = OpFunction %2 None %3
319 %5 = OpLabel
320 %25 = OpVariable %24 Function
321 %27 = OpVariable %7 Function
322 OpStore %25 %26
323 OpStore %27 %13
324 %28 = OpFunctionCall %2 %10 %27
325 OpReturn
326 OpFunctionEnd
327 %10 = OpFunction %2 None %8
328 %9 = OpFunctionParameter %7
329 %11 = OpLabel
330 %18 = OpVariable %7 Function
331 %12 = OpLoad %6 %9
332 %15 = OpSLessThan %14 %12 %13
333 OpSelectionMerge %17 None
334 OpBranchConditional %15 %16 %21
335 %16 = OpLabel
336 %19 = OpLoad %6 %9
337 %20 = OpIAdd %6 %19 %13
338 OpStore %18 %20
339 OpBranch %17
340 %21 = OpLabel
341 %22 = OpLoad %6 %9
342 %23 = OpISub %6 %22 %13
343 OpStore %18 %23
344 OpBranch %17
345 %17 = OpLabel
346 OpReturn
347 OpFunctionEnd
348 )";
349
350 const auto env = SPV_ENV_UNIVERSAL_1_4;
351 const auto consumer = nullptr;
352 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
353 spvtools::ValidatorOptions validator_options;
354 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
355 kConsoleMessageConsumer));
356 TransformationContext transformation_context(
357 MakeUnique<FactManager>(context.get()), validator_options);
358 // Bad: |entry_block_id| refers to the entry block of the function (this
359 // transformation currently avoids such cases).
360 TransformationDuplicateRegionWithSelection transformation_bad_1 =
361 TransformationDuplicateRegionWithSelection(
362 500, 26, 501, 11, 11, {{11, 100}}, {{18, 201}, {12, 202}, {15, 203}},
363 {{18, 301}, {12, 302}, {15, 303}});
364 ASSERT_FALSE(
365 transformation_bad_1.IsApplicable(context.get(), transformation_context));
366
367 // Bad: The block with id 16 does not dominate the block with id 21.
368 TransformationDuplicateRegionWithSelection transformation_bad_2 =
369 TransformationDuplicateRegionWithSelection(
370 500, 26, 501, 16, 21, {{16, 100}, {21, 101}},
371 {{19, 201}, {20, 202}, {22, 203}, {23, 204}},
372 {{19, 301}, {20, 302}, {22, 303}, {23, 304}});
373 ASSERT_FALSE(
374 transformation_bad_2.IsApplicable(context.get(), transformation_context));
375
376 // Bad: The block with id 21 does not post-dominate the block with id 11.
377 TransformationDuplicateRegionWithSelection transformation_bad_3 =
378 TransformationDuplicateRegionWithSelection(
379 500, 26, 501, 11, 21, {{11, 100}, {21, 101}},
380 {{18, 201}, {12, 202}, {15, 203}, {22, 204}, {23, 205}},
381 {{18, 301}, {12, 302}, {15, 303}, {22, 304}, {23, 305}});
382 ASSERT_FALSE(
383 transformation_bad_3.IsApplicable(context.get(), transformation_context));
384
385 // Bad: The block with id 5 is contained in a different function than the
386 // block with id 11.
387 TransformationDuplicateRegionWithSelection transformation_bad_4 =
388 TransformationDuplicateRegionWithSelection(
389 500, 26, 501, 5, 11, {{5, 100}, {11, 101}},
390 {{25, 201}, {27, 202}, {28, 203}, {18, 204}, {12, 205}, {15, 206}},
391 {{25, 301}, {27, 302}, {28, 303}, {18, 304}, {12, 305}, {15, 306}});
392 ASSERT_FALSE(
393 transformation_bad_4.IsApplicable(context.get(), transformation_context));
394 }
395
396 TEST(TransformationDuplicateRegionWithSelectionTest, NotApplicableIdTest) {
397 // This test handles a case where the supplied ids are either not fresh, not
398 // distinct, not valid in their context or do not refer to the existing
399 // instructions.
400
401 std::string shader = R"(
402 OpCapability Shader
403 OpCapability VariablePointers
404 %1 = OpExtInstImport "GLSL.std.450"
405 OpMemoryModel Logical GLSL450
406 OpEntryPoint Fragment %4 "main"
407 OpExecutionMode %4 OriginUpperLeft
408 OpSource ESSL 310
409 OpName %4 "main"
410 OpName %10 "fun(i1;"
411 OpName %9 "a"
412 OpName %12 "b"
413 OpName %18 "c"
414 OpName %20 "param"
415 %2 = OpTypeVoid
416 %3 = OpTypeFunction %2
417 %6 = OpTypeInt 32 1
418 %7 = OpTypePointer Function %6
419 %8 = OpTypeFunction %2 %7
420 %14 = OpConstant %6 2
421 %16 = OpTypeBool
422 %17 = OpTypePointer Function %16
423 %19 = OpConstantTrue %16
424 %4 = OpFunction %2 None %3
425 %5 = OpLabel
426 %18 = OpVariable %17 Function
427 %20 = OpVariable %7 Function
428 OpStore %18 %19
429 OpStore %20 %14
430 %21 = OpFunctionCall %2 %10 %20
431 OpReturn
432 OpFunctionEnd
433 %10 = OpFunction %2 None %8
434 %9 = OpFunctionParameter %7
435 %11 = OpLabel
436 %12 = OpVariable %7 Function
437 OpBranch %800
438 %800 = OpLabel
439 %13 = OpLoad %6 %9
440 %15 = OpIAdd %6 %13 %14
441 OpStore %12 %15
442 OpReturn
443 OpFunctionEnd
444 )";
445
446 const auto env = SPV_ENV_UNIVERSAL_1_4;
447 const auto consumer = nullptr;
448 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
449 spvtools::ValidatorOptions validator_options;
450 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
451 kConsoleMessageConsumer));
452 TransformationContext transformation_context(
453 MakeUnique<FactManager>(context.get()), validator_options);
454 // Bad: A value in the |original_label_to_duplicate_label| is not a fresh id.
455 TransformationDuplicateRegionWithSelection transformation_bad_1 =
456 TransformationDuplicateRegionWithSelection(
457 500, 19, 501, 800, 800, {{800, 21}}, {{13, 201}, {15, 202}},
458 {{13, 301}, {15, 302}});
459
460 ASSERT_FALSE(
461 transformation_bad_1.IsApplicable(context.get(), transformation_context));
462
463 // Bad: Values in the |original_id_to_duplicate_id| are not distinct.
464 TransformationDuplicateRegionWithSelection transformation_bad_2 =
465 TransformationDuplicateRegionWithSelection(
466 500, 19, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 201}},
467 {{13, 301}, {15, 302}});
468 ASSERT_FALSE(
469 transformation_bad_2.IsApplicable(context.get(), transformation_context));
470
471 // Bad: Values in the |original_id_to_phi_id| are not fresh and are not
472 // distinct with previous values.
473 TransformationDuplicateRegionWithSelection transformation_bad_3 =
474 TransformationDuplicateRegionWithSelection(
475 500, 19, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
476 {{13, 18}, {15, 202}});
477 ASSERT_FALSE(
478 transformation_bad_3.IsApplicable(context.get(), transformation_context));
479
480 // Bad: |entry_block_id| does not refer to an existing instruction.
481 TransformationDuplicateRegionWithSelection transformation_bad_4 =
482 TransformationDuplicateRegionWithSelection(
483 500, 19, 501, 802, 800, {{800, 100}}, {{13, 201}, {15, 202}},
484 {{13, 301}, {15, 302}});
485 ASSERT_FALSE(
486 transformation_bad_4.IsApplicable(context.get(), transformation_context));
487
488 // Bad: |exit_block_id| does not refer to a block.
489 TransformationDuplicateRegionWithSelection transformation_bad_5 =
490 TransformationDuplicateRegionWithSelection(
491 500, 19, 501, 800, 9, {{800, 100}}, {{13, 201}, {15, 202}},
492 {{13, 301}, {15, 302}});
493 ASSERT_FALSE(
494 transformation_bad_5.IsApplicable(context.get(), transformation_context));
495
496 // Bad: |new_entry_fresh_id| is not fresh.
497 TransformationDuplicateRegionWithSelection transformation_bad_6 =
498 TransformationDuplicateRegionWithSelection(
499 20, 19, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
500 {{13, 301}, {15, 302}});
501 ASSERT_FALSE(
502 transformation_bad_6.IsApplicable(context.get(), transformation_context));
503
504 // Bad: |merge_label_fresh_id| is not fresh.
505 TransformationDuplicateRegionWithSelection transformation_bad_7 =
506 TransformationDuplicateRegionWithSelection(
507 500, 19, 20, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
508 {{13, 301}, {15, 302}});
509 ASSERT_FALSE(
510 transformation_bad_7.IsApplicable(context.get(), transformation_context));
511
512 #ifndef NDEBUG
513 // Bad: Instruction with id 15 is from the original region and is available
514 // at the end of the region but it is not present in the
515 // |original_id_to_phi_id|.
516 TransformationDuplicateRegionWithSelection transformation_bad_8 =
517 TransformationDuplicateRegionWithSelection(
518 500, 19, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
519 {{13, 301}});
520 ASSERT_DEATH(
521 transformation_bad_8.IsApplicable(context.get(), transformation_context),
522 "Bad attempt to query whether overflow ids are available.");
523
524 // Bad: Instruction with id 15 is from the original region but it is
525 // not present in the |original_id_to_duplicate_id|.
526 TransformationDuplicateRegionWithSelection transformation_bad_9 =
527 TransformationDuplicateRegionWithSelection(500, 19, 501, 800, 800,
528 {{800, 100}}, {{13, 201}},
529 {{13, 301}, {15, 302}});
530 ASSERT_DEATH(
531 transformation_bad_9.IsApplicable(context.get(), transformation_context),
532 "Bad attempt to query whether overflow ids are available.");
533 #endif
534
535 // Bad: |condition_id| does not refer to the valid instruction.
536 TransformationDuplicateRegionWithSelection transformation_bad_10 =
537 TransformationDuplicateRegionWithSelection(
538 500, 200, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
539 {{13, 301}, {15, 302}});
540
541 ASSERT_FALSE(transformation_bad_10.IsApplicable(context.get(),
542 transformation_context));
543
544 // Bad: |condition_id| does not refer to the instruction of type OpTypeBool
545 TransformationDuplicateRegionWithSelection transformation_bad_11 =
546 TransformationDuplicateRegionWithSelection(
547 500, 14, 501, 800, 800, {{800, 100}}, {{13, 201}, {15, 202}},
548 {{13, 301}, {15, 302}});
549
550 ASSERT_FALSE(transformation_bad_11.IsApplicable(context.get(),
551 transformation_context));
552 }
553
554 TEST(TransformationDuplicateRegionWithSelectionTest, NotApplicableCFGTest2) {
555 // This test handles few cases where the transformation is not applicable
556 // because of the control flow graph or the layout of the blocks.
557
558 std::string shader = R"(
559 OpCapability Shader
560 %1 = OpExtInstImport "GLSL.std.450"
561 OpMemoryModel Logical GLSL450
562 OpEntryPoint Fragment %4 "main"
563 OpExecutionMode %4 OriginUpperLeft
564 OpSource ESSL 310
565 OpName %4 "main"
566 OpName %6 "fun("
567 OpName %10 "s"
568 OpName %12 "i"
569 OpName %29 "b"
570 %2 = OpTypeVoid
571 %3 = OpTypeFunction %2
572 %8 = OpTypeInt 32 1
573 %9 = OpTypePointer Function %8
574 %11 = OpConstant %8 0
575 %19 = OpConstant %8 10
576 %20 = OpTypeBool
577 %26 = OpConstant %8 1
578 %28 = OpTypePointer Function %20
579 %30 = OpConstantTrue %20
580 %4 = OpFunction %2 None %3
581 %5 = OpLabel
582 %29 = OpVariable %28 Function
583 OpStore %29 %30
584 %31 = OpFunctionCall %2 %6
585 OpReturn
586 OpFunctionEnd
587 %6 = OpFunction %2 None %3
588 %7 = OpLabel
589 %10 = OpVariable %9 Function
590 %12 = OpVariable %9 Function
591 OpStore %10 %11
592 OpStore %12 %11
593 OpBranch %13
594 %13 = OpLabel
595 OpLoopMerge %15 %16 None
596 OpBranch %17
597 %17 = OpLabel
598 %18 = OpLoad %8 %12
599 %21 = OpSLessThan %20 %18 %19
600 OpBranchConditional %21 %14 %15
601 %14 = OpLabel
602 %22 = OpLoad %8 %10
603 %23 = OpLoad %8 %12
604 %24 = OpIAdd %8 %22 %23
605 OpStore %10 %24
606 OpBranch %16
607 %16 = OpLabel
608 OpBranch %50
609 %50 = OpLabel
610 %25 = OpLoad %8 %12
611 %27 = OpIAdd %8 %25 %26
612 OpStore %12 %27
613 OpBranch %13
614 %15 = OpLabel
615 OpReturn
616 OpFunctionEnd
617 )";
618
619 const auto env = SPV_ENV_UNIVERSAL_1_4;
620 const auto consumer = nullptr;
621 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
622 spvtools::ValidatorOptions validator_options;
623 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
624 kConsoleMessageConsumer));
625 TransformationContext transformation_context(
626 MakeUnique<FactManager>(context.get()), validator_options);
627 // Bad: The exit block cannot be a header of a loop, because the region won't
628 // be a single-entry, single-exit region.
629 TransformationDuplicateRegionWithSelection transformation_bad_1 =
630 TransformationDuplicateRegionWithSelection(500, 30, 501, 13, 13,
631 {{13, 100}}, {{}}, {{}});
632 ASSERT_FALSE(
633 transformation_bad_1.IsApplicable(context.get(), transformation_context));
634
635 // Bad: The block with id 13, the loop header, is in the region. The block
636 // with id 15, the loop merge block, is not in the region.
637 TransformationDuplicateRegionWithSelection transformation_bad_2 =
638 TransformationDuplicateRegionWithSelection(
639 500, 30, 501, 13, 17, {{13, 100}, {17, 101}}, {{18, 201}, {21, 202}},
640 {{18, 301}, {21, 302}});
641 ASSERT_FALSE(
642 transformation_bad_2.IsApplicable(context.get(), transformation_context));
643
644 // Bad: The block with id 13, the loop header, is not in the region. The block
645 // with id 16, the loop continue target, is in the region.
646 TransformationDuplicateRegionWithSelection transformation_bad_3 =
647 TransformationDuplicateRegionWithSelection(
648 500, 30, 501, 16, 50, {{16, 100}, {50, 101}}, {{25, 201}, {27, 202}},
649 {{25, 301}, {27, 302}});
650 ASSERT_FALSE(
651 transformation_bad_3.IsApplicable(context.get(), transformation_context));
652 }
653
654 TEST(TransformationDuplicateRegionWithSelectionTest, NotApplicableCFGTest3) {
655 // This test handles a case where for the block which is not the exit block,
656 // not all successors are in the region.
657
658 std::string shader = R"(
659 OpCapability Shader
660 %1 = OpExtInstImport "GLSL.std.450"
661 OpMemoryModel Logical GLSL450
662 OpEntryPoint Fragment %4 "main"
663 OpExecutionMode %4 OriginUpperLeft
664 OpSource ESSL 310
665 OpName %4 "main"
666 OpName %6 "fun("
667 OpName %14 "a"
668 OpName %19 "b"
669 %2 = OpTypeVoid
670 %3 = OpTypeFunction %2
671 %8 = OpTypeBool
672 %9 = OpConstantTrue %8
673 %12 = OpTypeInt 32 1
674 %13 = OpTypePointer Function %12
675 %15 = OpConstant %12 2
676 %17 = OpConstant %12 3
677 %18 = OpTypePointer Function %8
678 %4 = OpFunction %2 None %3
679 %5 = OpLabel
680 %19 = OpVariable %18 Function
681 OpStore %19 %9
682 %20 = OpFunctionCall %2 %6
683 OpReturn
684 OpFunctionEnd
685 %6 = OpFunction %2 None %3
686 %7 = OpLabel
687 %14 = OpVariable %13 Function
688 OpSelectionMerge %11 None
689 OpBranchConditional %9 %10 %16
690 %10 = OpLabel
691 OpStore %14 %15
692 OpBranch %11
693 %16 = OpLabel
694 OpStore %14 %17
695 OpBranch %11
696 %11 = OpLabel
697 OpReturn
698 OpFunctionEnd
699 )";
700
701 const auto env = SPV_ENV_UNIVERSAL_1_4;
702 const auto consumer = nullptr;
703 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
704 spvtools::ValidatorOptions validator_options;
705 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
706 kConsoleMessageConsumer));
707 TransformationContext transformation_context(
708 MakeUnique<FactManager>(context.get()), validator_options);
709 // Bad: The block with id 7, which is not an exit block, has two successors:
710 // the block with id 10 and the block with id 16. The block with id 16 is not
711 // in the region.
712 TransformationDuplicateRegionWithSelection transformation_bad_1 =
713 TransformationDuplicateRegionWithSelection(
714 500, 30, 501, 7, 10, {{13, 100}}, {{14, 201}}, {{14, 301}});
715 ASSERT_FALSE(
716 transformation_bad_1.IsApplicable(context.get(), transformation_context));
717 }
718
719 TEST(TransformationDuplicateRegionWithSelectionTest, MultipleBlocksLoopTest) {
720 // This test handles a case where the region consists of multiple blocks
721 // (they form a loop). The transformation is applicable and the region is
722 // duplicated.
723
724 std::string shader = R"(
725 OpCapability Shader
726 %1 = OpExtInstImport "GLSL.std.450"
727 OpMemoryModel Logical GLSL450
728 OpEntryPoint Fragment %4 "main"
729 OpExecutionMode %4 OriginUpperLeft
730 OpSource ESSL 310
731 OpName %4 "main"
732 OpName %6 "fun("
733 OpName %10 "s"
734 OpName %12 "i"
735 OpName %29 "b"
736 %2 = OpTypeVoid
737 %3 = OpTypeFunction %2
738 %8 = OpTypeInt 32 1
739 %9 = OpTypePointer Function %8
740 %11 = OpConstant %8 0
741 %19 = OpConstant %8 10
742 %20 = OpTypeBool
743 %26 = OpConstant %8 1
744 %28 = OpTypePointer Function %20
745 %30 = OpConstantTrue %20
746 %4 = OpFunction %2 None %3
747 %5 = OpLabel
748 %29 = OpVariable %28 Function
749 OpStore %29 %30
750 %31 = OpFunctionCall %2 %6
751 OpReturn
752 OpFunctionEnd
753 %6 = OpFunction %2 None %3
754 %7 = OpLabel
755 %10 = OpVariable %9 Function
756 %12 = OpVariable %9 Function
757 OpStore %10 %11
758 OpStore %12 %11
759 OpBranch %50
760 %50 = OpLabel
761 OpBranch %13
762 %13 = OpLabel
763 OpLoopMerge %15 %16 None
764 OpBranch %17
765 %17 = OpLabel
766 %18 = OpLoad %8 %12
767 %21 = OpSLessThan %20 %18 %19
768 OpBranchConditional %21 %14 %15
769 %14 = OpLabel
770 %22 = OpLoad %8 %10
771 %23 = OpLoad %8 %12
772 %24 = OpIAdd %8 %22 %23
773 OpStore %10 %24
774 OpBranch %16
775 %16 = OpLabel
776 %25 = OpLoad %8 %12
777 %27 = OpIAdd %8 %25 %26
778 OpStore %12 %27
779 OpBranch %13
780 %15 = OpLabel
781 OpReturn
782 OpFunctionEnd
783 )";
784
785 const auto env = SPV_ENV_UNIVERSAL_1_4;
786 const auto consumer = nullptr;
787 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
788 spvtools::ValidatorOptions validator_options;
789 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
790 kConsoleMessageConsumer));
791 TransformationContext transformation_context(
792 MakeUnique<FactManager>(context.get()), validator_options);
793 TransformationDuplicateRegionWithSelection transformation_good_1 =
794 TransformationDuplicateRegionWithSelection(
795 500, 30, 501, 50, 15,
796 {{50, 100}, {13, 101}, {14, 102}, {15, 103}, {16, 104}, {17, 105}},
797 {{22, 201},
798 {23, 202},
799 {24, 203},
800 {25, 204},
801 {27, 205},
802 {18, 206},
803 {21, 207}},
804 {{22, 301},
805 {23, 302},
806 {24, 303},
807 {25, 304},
808 {27, 305},
809 {18, 306},
810 {21, 307}});
811 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
812 transformation_context));
813 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
814 &transformation_context);
815 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
816 kConsoleMessageConsumer));
817
818 std::string expected_shader = R"(
819 OpCapability Shader
820 %1 = OpExtInstImport "GLSL.std.450"
821 OpMemoryModel Logical GLSL450
822 OpEntryPoint Fragment %4 "main"
823 OpExecutionMode %4 OriginUpperLeft
824 OpSource ESSL 310
825 OpName %4 "main"
826 OpName %6 "fun("
827 OpName %10 "s"
828 OpName %12 "i"
829 OpName %29 "b"
830 %2 = OpTypeVoid
831 %3 = OpTypeFunction %2
832 %8 = OpTypeInt 32 1
833 %9 = OpTypePointer Function %8
834 %11 = OpConstant %8 0
835 %19 = OpConstant %8 10
836 %20 = OpTypeBool
837 %26 = OpConstant %8 1
838 %28 = OpTypePointer Function %20
839 %30 = OpConstantTrue %20
840 %4 = OpFunction %2 None %3
841 %5 = OpLabel
842 %29 = OpVariable %28 Function
843 OpStore %29 %30
844 %31 = OpFunctionCall %2 %6
845 OpReturn
846 OpFunctionEnd
847 %6 = OpFunction %2 None %3
848 %7 = OpLabel
849 %10 = OpVariable %9 Function
850 %12 = OpVariable %9 Function
851 OpStore %10 %11
852 OpStore %12 %11
853 OpBranch %500
854 %500 = OpLabel
855 OpSelectionMerge %501 None
856 OpBranchConditional %30 %50 %100
857 %50 = OpLabel
858 OpBranch %13
859 %13 = OpLabel
860 OpLoopMerge %15 %16 None
861 OpBranch %17
862 %17 = OpLabel
863 %18 = OpLoad %8 %12
864 %21 = OpSLessThan %20 %18 %19
865 OpBranchConditional %21 %14 %15
866 %14 = OpLabel
867 %22 = OpLoad %8 %10
868 %23 = OpLoad %8 %12
869 %24 = OpIAdd %8 %22 %23
870 OpStore %10 %24
871 OpBranch %16
872 %16 = OpLabel
873 %25 = OpLoad %8 %12
874 %27 = OpIAdd %8 %25 %26
875 OpStore %12 %27
876 OpBranch %13
877 %15 = OpLabel
878 OpBranch %501
879 %100 = OpLabel
880 OpBranch %101
881 %101 = OpLabel
882 OpLoopMerge %103 %104 None
883 OpBranch %105
884 %105 = OpLabel
885 %206 = OpLoad %8 %12
886 %207 = OpSLessThan %20 %206 %19
887 OpBranchConditional %207 %102 %103
888 %102 = OpLabel
889 %201 = OpLoad %8 %10
890 %202 = OpLoad %8 %12
891 %203 = OpIAdd %8 %201 %202
892 OpStore %10 %203
893 OpBranch %104
894 %104 = OpLabel
895 %204 = OpLoad %8 %12
896 %205 = OpIAdd %8 %204 %26
897 OpStore %12 %205
898 OpBranch %101
899 %103 = OpLabel
900 OpBranch %501
901 %501 = OpLabel
902 %306 = OpPhi %8 %18 %15 %206 %103
903 %307 = OpPhi %20 %21 %15 %207 %103
904 OpReturn
905 OpFunctionEnd
906 )";
907 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
908 }
909
910 TEST(TransformationDuplicateRegionWithSelectionTest,
911 ResolvingOpPhiExitBlockTest) {
912 // This test handles a case where the region under the transformation is
913 // referenced in OpPhi instructions. Since the new merge block becomes the
914 // exit of the region, these OpPhi instructions need to be updated.
915
916 std::string shader = R"(
917 OpCapability Shader
918 %1 = OpExtInstImport "GLSL.std.450"
919 OpMemoryModel Logical GLSL450
920 OpEntryPoint Fragment %4 "main"
921 OpExecutionMode %4 OriginUpperLeft
922 OpSource ESSL 310
923 OpName %4 "main"
924 OpName %10 "fun(i1;"
925 OpName %9 "a"
926 OpName %12 "s"
927 OpName %26 "b"
928 OpName %29 "param"
929 %2 = OpTypeVoid
930 %3 = OpTypeFunction %2
931 %6 = OpTypeInt 32 1
932 %7 = OpTypePointer Function %6
933 %8 = OpTypeFunction %2 %7
934 %13 = OpConstant %6 0
935 %15 = OpConstant %6 2
936 %16 = OpTypeBool
937 %25 = OpTypePointer Function %16
938 %27 = OpConstantTrue %16
939 %28 = OpConstant %6 3
940 %4 = OpFunction %2 None %3
941 %5 = OpLabel
942 %26 = OpVariable %25 Function
943 %29 = OpVariable %7 Function
944 OpStore %26 %27
945 OpStore %29 %28
946 %30 = OpFunctionCall %2 %10 %29
947 OpReturn
948 OpFunctionEnd
949 %10 = OpFunction %2 None %8
950 %9 = OpFunctionParameter %7
951 %11 = OpLabel
952 %12 = OpVariable %7 Function
953 OpStore %12 %13
954 %14 = OpLoad %6 %9
955 %17 = OpSLessThan %16 %14 %15
956 OpSelectionMerge %19 None
957 OpBranchConditional %17 %18 %22
958 %18 = OpLabel
959 %20 = OpLoad %6 %9
960 %21 = OpIAdd %6 %20 %15
961 OpStore %12 %21
962 OpBranch %19
963 %22 = OpLabel
964 %23 = OpLoad %6 %9
965 %24 = OpIMul %6 %23 %15
966 OpStore %12 %24
967 OpBranch %19
968 %19 = OpLabel
969 %40 = OpPhi %6 %21 %18 %24 %22
970 OpReturn
971 OpFunctionEnd
972 )";
973
974 const auto env = SPV_ENV_UNIVERSAL_1_4;
975 const auto consumer = nullptr;
976 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
977 spvtools::ValidatorOptions validator_options;
978 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
979 kConsoleMessageConsumer));
980 TransformationContext transformation_context(
981 MakeUnique<FactManager>(context.get()), validator_options);
982
983 TransformationDuplicateRegionWithSelection transformation_good_1 =
984 TransformationDuplicateRegionWithSelection(
985 500, 27, 501, 22, 22, {{22, 100}}, {{23, 201}, {24, 202}},
986 {{23, 301}, {24, 302}});
987
988 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
989 transformation_context));
990 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
991 &transformation_context);
992 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
993 kConsoleMessageConsumer));
994
995 std::string expected_shader = R"(
996 OpCapability Shader
997 %1 = OpExtInstImport "GLSL.std.450"
998 OpMemoryModel Logical GLSL450
999 OpEntryPoint Fragment %4 "main"
1000 OpExecutionMode %4 OriginUpperLeft
1001 OpSource ESSL 310
1002 OpName %4 "main"
1003 OpName %10 "fun(i1;"
1004 OpName %9 "a"
1005 OpName %12 "s"
1006 OpName %26 "b"
1007 OpName %29 "param"
1008 %2 = OpTypeVoid
1009 %3 = OpTypeFunction %2
1010 %6 = OpTypeInt 32 1
1011 %7 = OpTypePointer Function %6
1012 %8 = OpTypeFunction %2 %7
1013 %13 = OpConstant %6 0
1014 %15 = OpConstant %6 2
1015 %16 = OpTypeBool
1016 %25 = OpTypePointer Function %16
1017 %27 = OpConstantTrue %16
1018 %28 = OpConstant %6 3
1019 %4 = OpFunction %2 None %3
1020 %5 = OpLabel
1021 %26 = OpVariable %25 Function
1022 %29 = OpVariable %7 Function
1023 OpStore %26 %27
1024 OpStore %29 %28
1025 %30 = OpFunctionCall %2 %10 %29
1026 OpReturn
1027 OpFunctionEnd
1028 %10 = OpFunction %2 None %8
1029 %9 = OpFunctionParameter %7
1030 %11 = OpLabel
1031 %12 = OpVariable %7 Function
1032 OpStore %12 %13
1033 %14 = OpLoad %6 %9
1034 %17 = OpSLessThan %16 %14 %15
1035 OpSelectionMerge %19 None
1036 OpBranchConditional %17 %18 %500
1037 %18 = OpLabel
1038 %20 = OpLoad %6 %9
1039 %21 = OpIAdd %6 %20 %15
1040 OpStore %12 %21
1041 OpBranch %19
1042 %500 = OpLabel
1043 OpSelectionMerge %501 None
1044 OpBranchConditional %27 %22 %100
1045 %22 = OpLabel
1046 %23 = OpLoad %6 %9
1047 %24 = OpIMul %6 %23 %15
1048 OpStore %12 %24
1049 OpBranch %501
1050 %100 = OpLabel
1051 %201 = OpLoad %6 %9
1052 %202 = OpIMul %6 %201 %15
1053 OpStore %12 %202
1054 OpBranch %501
1055 %501 = OpLabel
1056 %301 = OpPhi %6 %23 %22 %201 %100
1057 %302 = OpPhi %6 %24 %22 %202 %100
1058 OpBranch %19
1059 %19 = OpLabel
1060 %40 = OpPhi %6 %21 %18 %302 %501
1061 OpReturn
1062 OpFunctionEnd
1063 )";
1064 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1065 }
1066
1067 TEST(TransformationDuplicateRegionWithSelectionTest, NotApplicableEarlyReturn) {
1068 // This test handles a case where one of the blocks has successor outside of
1069 // the region, which has an early return from the function, so that the
1070 // transformation is not applicable.
1071
1072 std::string shader = R"(
1073 OpCapability Shader
1074 %1 = OpExtInstImport "GLSL.std.450"
1075 OpMemoryModel Logical GLSL450
1076 OpEntryPoint Fragment %4 "main"
1077 OpExecutionMode %4 OriginUpperLeft
1078 OpSource ESSL 310
1079 OpName %4 "main"
1080 OpName %10 "fun(i1;"
1081 OpName %9 "a"
1082 OpName %12 "s"
1083 OpName %27 "b"
1084 OpName %30 "param"
1085 %2 = OpTypeVoid
1086 %3 = OpTypeFunction %2
1087 %6 = OpTypeInt 32 1
1088 %7 = OpTypePointer Function %6
1089 %8 = OpTypeFunction %2 %7
1090 %13 = OpConstant %6 0
1091 %15 = OpConstant %6 2
1092 %16 = OpTypeBool
1093 %26 = OpTypePointer Function %16
1094 %28 = OpConstantTrue %16
1095 %29 = OpConstant %6 3
1096 %4 = OpFunction %2 None %3
1097 %5 = OpLabel
1098 %27 = OpVariable %26 Function
1099 %30 = OpVariable %7 Function
1100 OpStore %27 %28
1101 OpStore %30 %29
1102 %31 = OpFunctionCall %2 %10 %30
1103 OpReturn
1104 OpFunctionEnd
1105 %10 = OpFunction %2 None %8
1106 %9 = OpFunctionParameter %7
1107 %11 = OpLabel
1108 %12 = OpVariable %7 Function
1109 OpBranch %50
1110 %50 = OpLabel
1111 OpStore %12 %13
1112 %14 = OpLoad %6 %9
1113 %17 = OpSLessThan %16 %14 %15
1114 OpSelectionMerge %19 None
1115 OpBranchConditional %17 %18 %22
1116 %18 = OpLabel
1117 %20 = OpLoad %6 %9
1118 %21 = OpIAdd %6 %20 %15
1119 OpStore %12 %21
1120 OpBranch %19
1121 %22 = OpLabel
1122 OpReturn
1123 %19 = OpLabel
1124 OpReturn
1125 OpFunctionEnd
1126 )";
1127
1128 const auto env = SPV_ENV_UNIVERSAL_1_4;
1129 const auto consumer = nullptr;
1130 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1131 spvtools::ValidatorOptions validator_options;
1132 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1133 kConsoleMessageConsumer));
1134 TransformationContext transformation_context(
1135 MakeUnique<FactManager>(context.get()), validator_options);
1136 // Bad: The block with id 50, which is the entry block, has two successors:
1137 // the block with id 18 and the block with id 22. The block 22 has an early
1138 // return from the function, so that the entry block is not post-dominated by
1139 // the exit block.
1140 TransformationDuplicateRegionWithSelection transformation_bad_1 =
1141 TransformationDuplicateRegionWithSelection(
1142 500, 28, 501, 50, 19, {{50, 100}, {18, 101}, {22, 102}, {19, 103}},
1143 {{14, 202}, {17, 203}, {20, 204}, {21, 205}},
1144 {{14, 302}, {17, 303}, {20, 304}, {21, 305}});
1145 ASSERT_FALSE(
1146 transformation_bad_1.IsApplicable(context.get(), transformation_context));
1147 }
1148
1149 TEST(TransformationDuplicateRegionWithSelectionTest,
1150 ResolvingOpPhiEntryBlockOnePredecessor) {
1151 // This test handles a case where the entry block has an OpPhi instruction
1152 // referring to its predecessor. After transformation, this instruction needs
1153 // to be updated.
1154
1155 std::string shader = R"(
1156 OpCapability Shader
1157 %1 = OpExtInstImport "GLSL.std.450"
1158 OpMemoryModel Logical GLSL450
1159 OpEntryPoint Fragment %4 "main"
1160 OpExecutionMode %4 OriginUpperLeft
1161 OpSource ESSL 310
1162 OpName %4 "main"
1163 OpName %10 "fun(i1;"
1164 OpName %9 "a"
1165 OpName %12 "s"
1166 OpName %14 "t"
1167 OpName %20 "b"
1168 OpName %23 "param"
1169 %2 = OpTypeVoid
1170 %3 = OpTypeFunction %2
1171 %6 = OpTypeInt 32 1
1172 %7 = OpTypePointer Function %6
1173 %8 = OpTypeFunction %2 %7
1174 %13 = OpConstant %6 0
1175 %15 = OpConstant %6 2
1176 %18 = OpTypeBool
1177 %19 = OpTypePointer Function %18
1178 %21 = OpConstantTrue %18
1179 %22 = OpConstant %6 3
1180 %4 = OpFunction %2 None %3
1181 %5 = OpLabel
1182 %20 = OpVariable %19 Function
1183 %23 = OpVariable %7 Function
1184 OpStore %20 %21
1185 OpStore %23 %22
1186 %24 = OpFunctionCall %2 %10 %23
1187 OpReturn
1188 OpFunctionEnd
1189 %10 = OpFunction %2 None %8
1190 %9 = OpFunctionParameter %7
1191 %11 = OpLabel
1192 %12 = OpVariable %7 Function
1193 %14 = OpVariable %7 Function
1194 OpStore %12 %13
1195 %16 = OpLoad %6 %12
1196 %17 = OpIMul %6 %15 %16
1197 OpStore %14 %17
1198 OpBranch %50
1199 %50 = OpLabel
1200 %51 = OpPhi %6 %17 %11
1201 OpReturn
1202 OpFunctionEnd
1203 )";
1204
1205 const auto env = SPV_ENV_UNIVERSAL_1_4;
1206 const auto consumer = nullptr;
1207 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1208 spvtools::ValidatorOptions validator_options;
1209 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1210 kConsoleMessageConsumer));
1211 TransformationContext transformation_context(
1212 MakeUnique<FactManager>(context.get()), validator_options);
1213
1214 TransformationDuplicateRegionWithSelection transformation_good_1 =
1215 TransformationDuplicateRegionWithSelection(
1216 500, 21, 501, 50, 50, {{50, 100}}, {{51, 201}}, {{51, 301}});
1217 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
1218 transformation_context));
1219 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
1220 &transformation_context);
1221 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1222 kConsoleMessageConsumer));
1223
1224 std::string expected_shader = R"(
1225 OpCapability Shader
1226 %1 = OpExtInstImport "GLSL.std.450"
1227 OpMemoryModel Logical GLSL450
1228 OpEntryPoint Fragment %4 "main"
1229 OpExecutionMode %4 OriginUpperLeft
1230 OpSource ESSL 310
1231 OpName %4 "main"
1232 OpName %10 "fun(i1;"
1233 OpName %9 "a"
1234 OpName %12 "s"
1235 OpName %14 "t"
1236 OpName %20 "b"
1237 OpName %23 "param"
1238 %2 = OpTypeVoid
1239 %3 = OpTypeFunction %2
1240 %6 = OpTypeInt 32 1
1241 %7 = OpTypePointer Function %6
1242 %8 = OpTypeFunction %2 %7
1243 %13 = OpConstant %6 0
1244 %15 = OpConstant %6 2
1245 %18 = OpTypeBool
1246 %19 = OpTypePointer Function %18
1247 %21 = OpConstantTrue %18
1248 %22 = OpConstant %6 3
1249 %4 = OpFunction %2 None %3
1250 %5 = OpLabel
1251 %20 = OpVariable %19 Function
1252 %23 = OpVariable %7 Function
1253 OpStore %20 %21
1254 OpStore %23 %22
1255 %24 = OpFunctionCall %2 %10 %23
1256 OpReturn
1257 OpFunctionEnd
1258 %10 = OpFunction %2 None %8
1259 %9 = OpFunctionParameter %7
1260 %11 = OpLabel
1261 %12 = OpVariable %7 Function
1262 %14 = OpVariable %7 Function
1263 OpStore %12 %13
1264 %16 = OpLoad %6 %12
1265 %17 = OpIMul %6 %15 %16
1266 OpStore %14 %17
1267 OpBranch %500
1268 %500 = OpLabel
1269 OpSelectionMerge %501 None
1270 OpBranchConditional %21 %50 %100
1271 %50 = OpLabel
1272 %51 = OpPhi %6 %17 %500
1273 OpBranch %501
1274 %100 = OpLabel
1275 %201 = OpPhi %6 %17 %500
1276 OpBranch %501
1277 %501 = OpLabel
1278 %301 = OpPhi %6 %51 %50 %201 %100
1279 OpReturn
1280 OpFunctionEnd
1281 )";
1282 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1283 }
1284
1285 TEST(TransformationDuplicateRegionWithSelectionTest,
1286 NotApplicableNoVariablePointerCapability) {
1287 // This test handles a case where the transformation would create an OpPhi
1288 // instruction with pointer operands, however there is no cab
1289 // CapabilityVariablePointers. Hence, the transformation is not applicable.
1290
1291 std::string shader = R"(
1292 OpCapability Shader
1293 %1 = OpExtInstImport "GLSL.std.450"
1294 OpMemoryModel Logical GLSL450
1295 OpEntryPoint Fragment %4 "main"
1296 OpExecutionMode %4 OriginUpperLeft
1297 OpSource ESSL 310
1298 OpName %4 "main"
1299 OpName %10 "fun(i1;"
1300 OpName %9 "a"
1301 OpName %12 "s"
1302 OpName %14 "t"
1303 OpName %20 "b"
1304 OpName %23 "param"
1305 %2 = OpTypeVoid
1306 %3 = OpTypeFunction %2
1307 %6 = OpTypeInt 32 1
1308 %7 = OpTypePointer Function %6
1309 %8 = OpTypeFunction %2 %7
1310 %13 = OpConstant %6 0
1311 %15 = OpConstant %6 2
1312 %18 = OpTypeBool
1313 %19 = OpTypePointer Function %18
1314 %21 = OpConstantTrue %18
1315 %22 = OpConstant %6 3
1316 %4 = OpFunction %2 None %3
1317 %5 = OpLabel
1318 %20 = OpVariable %19 Function
1319 %23 = OpVariable %7 Function
1320 OpStore %20 %21
1321 OpStore %23 %22
1322 %24 = OpFunctionCall %2 %10 %23
1323 OpReturn
1324 OpFunctionEnd
1325 %10 = OpFunction %2 None %8
1326 %9 = OpFunctionParameter %7
1327 %11 = OpLabel
1328 %12 = OpVariable %7 Function
1329 %14 = OpVariable %7 Function
1330 OpStore %12 %13
1331 %16 = OpLoad %6 %12
1332 %17 = OpIMul %6 %15 %16
1333 OpStore %14 %17
1334 OpBranch %50
1335 %50 = OpLabel
1336 %51 = OpCopyObject %7 %12
1337 OpBranch %52
1338 %52 = OpLabel
1339 %53 = OpCopyObject %7 %51
1340 OpReturn
1341 OpFunctionEnd
1342 )";
1343
1344 const auto env = SPV_ENV_UNIVERSAL_1_4;
1345 const auto consumer = nullptr;
1346 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1347 spvtools::ValidatorOptions validator_options;
1348 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1349 kConsoleMessageConsumer));
1350 TransformationContext transformation_context(
1351 MakeUnique<FactManager>(context.get()), validator_options);
1352 // Bad: There is no required capability CapabilityVariablePointers
1353 TransformationDuplicateRegionWithSelection transformation_bad_1 =
1354 TransformationDuplicateRegionWithSelection(
1355 500, 21, 501, 50, 50, {{50, 100}}, {{51, 201}}, {{51, 301}});
1356 ASSERT_FALSE(
1357 transformation_bad_1.IsApplicable(context.get(), transformation_context));
1358 }
1359
1360 TEST(TransformationDuplicateRegionWithSelectionTest,
1361 ExitBlockTerminatorOpUnreachable) {
1362 // This test handles a case where the exit block ends with OpUnreachable.
1363
1364 std::string shader = R"(
1365 OpCapability Shader
1366 %1 = OpExtInstImport "GLSL.std.450"
1367 OpMemoryModel Logical GLSL450
1368 OpEntryPoint Fragment %4 "main"
1369 OpExecutionMode %4 OriginUpperLeft
1370 OpSource ESSL 310
1371 OpName %4 "main"
1372 OpName %6 "fun("
1373 OpName %10 "s"
1374 OpName %17 "b"
1375 %2 = OpTypeVoid
1376 %3 = OpTypeFunction %2
1377 %8 = OpTypeInt 32 1
1378 %9 = OpTypePointer Function %8
1379 %11 = OpConstant %8 0
1380 %13 = OpConstant %8 2
1381 %15 = OpTypeBool
1382 %16 = OpTypePointer Function %15
1383 %18 = OpConstantTrue %15
1384 %4 = OpFunction %2 None %3
1385 %5 = OpLabel
1386 %17 = OpVariable %16 Function
1387 OpStore %17 %18
1388 %19 = OpFunctionCall %2 %6
1389 OpReturn
1390 OpFunctionEnd
1391 %6 = OpFunction %2 None %3
1392 %7 = OpLabel
1393 %10 = OpVariable %9 Function
1394 OpBranch %50
1395 %50 = OpLabel
1396 OpStore %10 %11
1397 %12 = OpLoad %8 %10
1398 %14 = OpIAdd %8 %12 %13
1399 OpStore %10 %14
1400 OpUnreachable
1401 OpFunctionEnd
1402 )";
1403
1404 const auto env = SPV_ENV_UNIVERSAL_1_4;
1405 const auto consumer = nullptr;
1406 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1407 spvtools::ValidatorOptions validator_options;
1408 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1409 kConsoleMessageConsumer));
1410 TransformationContext transformation_context(
1411 MakeUnique<FactManager>(context.get()), validator_options);
1412
1413 TransformationDuplicateRegionWithSelection transformation_good_1 =
1414 TransformationDuplicateRegionWithSelection(
1415 500, 18, 501, 50, 50, {{50, 100}}, {{12, 201}, {14, 202}},
1416 {{12, 301}, {14, 302}});
1417 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
1418 transformation_context));
1419 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
1420 &transformation_context);
1421 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1422 kConsoleMessageConsumer));
1423
1424 std::string expected_shader = R"(
1425 OpCapability Shader
1426 %1 = OpExtInstImport "GLSL.std.450"
1427 OpMemoryModel Logical GLSL450
1428 OpEntryPoint Fragment %4 "main"
1429 OpExecutionMode %4 OriginUpperLeft
1430 OpSource ESSL 310
1431 OpName %4 "main"
1432 OpName %6 "fun("
1433 OpName %10 "s"
1434 OpName %17 "b"
1435 %2 = OpTypeVoid
1436 %3 = OpTypeFunction %2
1437 %8 = OpTypeInt 32 1
1438 %9 = OpTypePointer Function %8
1439 %11 = OpConstant %8 0
1440 %13 = OpConstant %8 2
1441 %15 = OpTypeBool
1442 %16 = OpTypePointer Function %15
1443 %18 = OpConstantTrue %15
1444 %4 = OpFunction %2 None %3
1445 %5 = OpLabel
1446 %17 = OpVariable %16 Function
1447 OpStore %17 %18
1448 %19 = OpFunctionCall %2 %6
1449 OpReturn
1450 OpFunctionEnd
1451 %6 = OpFunction %2 None %3
1452 %7 = OpLabel
1453 %10 = OpVariable %9 Function
1454 OpBranch %500
1455 %500 = OpLabel
1456 OpSelectionMerge %501 None
1457 OpBranchConditional %18 %50 %100
1458 %50 = OpLabel
1459 OpStore %10 %11
1460 %12 = OpLoad %8 %10
1461 %14 = OpIAdd %8 %12 %13
1462 OpStore %10 %14
1463 OpBranch %501
1464 %100 = OpLabel
1465 OpStore %10 %11
1466 %201 = OpLoad %8 %10
1467 %202 = OpIAdd %8 %201 %13
1468 OpStore %10 %202
1469 OpBranch %501
1470 %501 = OpLabel
1471 %301 = OpPhi %8 %12 %50 %201 %100
1472 %302 = OpPhi %8 %14 %50 %202 %100
1473 OpUnreachable
1474 OpFunctionEnd
1475 )";
1476 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1477 }
1478
1479 TEST(TransformationDuplicateRegionWithSelectionTest,
1480 ExitBlockTerminatorOpKill) {
1481 // This test handles a case where the exit block ends with OpKill.
1482
1483 std::string shader = R"(
1484 OpCapability Shader
1485 %1 = OpExtInstImport "GLSL.std.450"
1486 OpMemoryModel Logical GLSL450
1487 OpEntryPoint Fragment %4 "main"
1488 OpExecutionMode %4 OriginUpperLeft
1489 OpSource ESSL 310
1490 OpName %4 "main"
1491 OpName %6 "fun("
1492 OpName %10 "s"
1493 OpName %17 "b"
1494 %2 = OpTypeVoid
1495 %3 = OpTypeFunction %2
1496 %8 = OpTypeInt 32 1
1497 %9 = OpTypePointer Function %8
1498 %11 = OpConstant %8 0
1499 %13 = OpConstant %8 2
1500 %15 = OpTypeBool
1501 %16 = OpTypePointer Function %15
1502 %18 = OpConstantTrue %15
1503 %4 = OpFunction %2 None %3
1504 %5 = OpLabel
1505 %17 = OpVariable %16 Function
1506 OpStore %17 %18
1507 %19 = OpFunctionCall %2 %6
1508 OpReturn
1509 OpFunctionEnd
1510 %6 = OpFunction %2 None %3
1511 %7 = OpLabel
1512 %10 = OpVariable %9 Function
1513 OpBranch %50
1514 %50 = OpLabel
1515 OpStore %10 %11
1516 %12 = OpLoad %8 %10
1517 %14 = OpIAdd %8 %12 %13
1518 OpStore %10 %14
1519 OpKill
1520 OpFunctionEnd
1521 )";
1522
1523 const auto env = SPV_ENV_UNIVERSAL_1_4;
1524 const auto consumer = nullptr;
1525 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1526 spvtools::ValidatorOptions validator_options;
1527 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1528 kConsoleMessageConsumer));
1529 TransformationContext transformation_context(
1530 MakeUnique<FactManager>(context.get()), validator_options);
1531
1532 TransformationDuplicateRegionWithSelection transformation_good_1 =
1533 TransformationDuplicateRegionWithSelection(
1534 500, 18, 501, 50, 50, {{50, 100}}, {{12, 201}, {14, 202}},
1535 {{12, 301}, {14, 302}});
1536 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
1537 transformation_context));
1538 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
1539 &transformation_context);
1540 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1541 kConsoleMessageConsumer));
1542
1543 std::string expected_shader = R"(
1544 OpCapability Shader
1545 %1 = OpExtInstImport "GLSL.std.450"
1546 OpMemoryModel Logical GLSL450
1547 OpEntryPoint Fragment %4 "main"
1548 OpExecutionMode %4 OriginUpperLeft
1549 OpSource ESSL 310
1550 OpName %4 "main"
1551 OpName %6 "fun("
1552 OpName %10 "s"
1553 OpName %17 "b"
1554 %2 = OpTypeVoid
1555 %3 = OpTypeFunction %2
1556 %8 = OpTypeInt 32 1
1557 %9 = OpTypePointer Function %8
1558 %11 = OpConstant %8 0
1559 %13 = OpConstant %8 2
1560 %15 = OpTypeBool
1561 %16 = OpTypePointer Function %15
1562 %18 = OpConstantTrue %15
1563 %4 = OpFunction %2 None %3
1564 %5 = OpLabel
1565 %17 = OpVariable %16 Function
1566 OpStore %17 %18
1567 %19 = OpFunctionCall %2 %6
1568 OpReturn
1569 OpFunctionEnd
1570 %6 = OpFunction %2 None %3
1571 %7 = OpLabel
1572 %10 = OpVariable %9 Function
1573 OpBranch %500
1574 %500 = OpLabel
1575 OpSelectionMerge %501 None
1576 OpBranchConditional %18 %50 %100
1577 %50 = OpLabel
1578 OpStore %10 %11
1579 %12 = OpLoad %8 %10
1580 %14 = OpIAdd %8 %12 %13
1581 OpStore %10 %14
1582 OpBranch %501
1583 %100 = OpLabel
1584 OpStore %10 %11
1585 %201 = OpLoad %8 %10
1586 %202 = OpIAdd %8 %201 %13
1587 OpStore %10 %202
1588 OpBranch %501
1589 %501 = OpLabel
1590 %301 = OpPhi %8 %12 %50 %201 %100
1591 %302 = OpPhi %8 %14 %50 %202 %100
1592 OpKill
1593 OpFunctionEnd
1594 )";
1595
1596 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1597 }
1598
1599 TEST(TransformationDuplicateRegionWithSelectionTest,
1600 ContinueExitBlockNotApplicable) {
1601 // This test handles a case where the exit block is the continue target and
1602 // the transformation is not applicable.
1603
1604 std::string shader = R"(
1605 OpCapability Shader
1606 %1 = OpExtInstImport "GLSL.std.450"
1607 OpMemoryModel Logical GLSL450
1608 OpEntryPoint Fragment %4 "main"
1609 OpExecutionMode %4 OriginUpperLeft
1610 OpSource ESSL 310
1611 OpName %4 "main"
1612 OpName %8 "s"
1613 OpName %10 "i"
1614 %2 = OpTypeVoid
1615 %3 = OpTypeFunction %2
1616 %6 = OpTypeInt 32 1
1617 %7 = OpTypePointer Function %6
1618 %9 = OpConstant %6 0
1619 %17 = OpConstant %6 10
1620 %18 = OpTypeBool
1621 %24 = OpConstant %6 5
1622 %30 = OpConstant %6 1
1623 %50 = OpConstantTrue %18
1624 %4 = OpFunction %2 None %3
1625 %5 = OpLabel
1626 %8 = OpVariable %7 Function
1627 %10 = OpVariable %7 Function
1628 OpStore %8 %9
1629 OpStore %10 %9
1630 OpBranch %11
1631 %11 = OpLabel
1632 OpLoopMerge %13 %14 None
1633 OpBranch %15
1634 %15 = OpLabel
1635 %16 = OpLoad %6 %10
1636 %19 = OpSLessThan %18 %16 %17
1637 OpBranchConditional %19 %12 %13
1638 %12 = OpLabel
1639 %20 = OpLoad %6 %10
1640 %21 = OpLoad %6 %8
1641 %22 = OpIAdd %6 %21 %20
1642 OpStore %8 %22
1643 %23 = OpLoad %6 %10
1644 %25 = OpIEqual %18 %23 %24
1645 OpSelectionMerge %27 None
1646 OpBranchConditional %25 %26 %27
1647 %26 = OpLabel
1648 OpBranch %13
1649 %27 = OpLabel
1650 OpBranch %14
1651 %14 = OpLabel
1652 %29 = OpLoad %6 %10
1653 %31 = OpIAdd %6 %29 %30
1654 OpStore %10 %31
1655 OpBranch %11
1656 %13 = OpLabel
1657 OpReturn
1658 OpFunctionEnd
1659 )";
1660
1661 const auto env = SPV_ENV_UNIVERSAL_1_4;
1662 const auto consumer = nullptr;
1663 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1664 spvtools::ValidatorOptions validator_options;
1665 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1666 kConsoleMessageConsumer));
1667 TransformationContext transformation_context(
1668 MakeUnique<FactManager>(context.get()), validator_options);
1669 TransformationDuplicateRegionWithSelection transformation_bad =
1670 TransformationDuplicateRegionWithSelection(
1671 500, 50, 501, 27, 14, {{27, 101}, {14, 102}}, {{29, 201}, {31, 202}},
1672 {{29, 301}, {31, 302}});
1673
1674 ASSERT_FALSE(
1675 transformation_bad.IsApplicable(context.get(), transformation_context));
1676 }
1677
1678 TEST(TransformationDuplicateRegionWithSelectionTest,
1679 MultiplePredecessorsNotApplicableTest) {
1680 // This test handles a case where the entry block has multiple predecessors
1681 // and the transformation is not applicable.
1682
1683 std::string shader = R"(
1684 OpCapability Shader
1685 %1 = OpExtInstImport "GLSL.std.450"
1686 OpMemoryModel Logical GLSL450
1687 OpEntryPoint Fragment %4 "main"
1688 OpExecutionMode %4 OriginUpperLeft
1689 OpSource ESSL 310
1690 OpName %4 "main"
1691 OpName %10 "fun1(i1;"
1692 OpName %9 "a"
1693 OpName %18 "b"
1694 OpName %24 "b"
1695 OpName %27 "param"
1696 %2 = OpTypeVoid
1697 %3 = OpTypeFunction %2
1698 %6 = OpTypeInt 32 1
1699 %7 = OpTypePointer Function %6
1700 %8 = OpTypeFunction %2 %7
1701 %13 = OpConstant %6 2
1702 %14 = OpTypeBool
1703 %23 = OpTypePointer Function %14
1704 %25 = OpConstantTrue %14
1705 %26 = OpConstant %6 1
1706 %4 = OpFunction %2 None %3
1707 %5 = OpLabel
1708 %24 = OpVariable %23 Function
1709 %27 = OpVariable %7 Function
1710 OpStore %24 %25
1711 OpStore %27 %26
1712 %28 = OpFunctionCall %2 %10 %27
1713 OpReturn
1714 OpFunctionEnd
1715 %10 = OpFunction %2 None %8
1716 %9 = OpFunctionParameter %7
1717 %11 = OpLabel
1718 %18 = OpVariable %7 Function
1719 %12 = OpLoad %6 %9
1720 %15 = OpSLessThan %14 %12 %13
1721 OpSelectionMerge %17 None
1722 OpBranchConditional %15 %16 %20
1723 %16 = OpLabel
1724 %19 = OpLoad %6 %9
1725 OpStore %18 %19
1726 OpBranch %60
1727 %20 = OpLabel
1728 %21 = OpLoad %6 %9
1729 %22 = OpIAdd %6 %21 %13
1730 OpStore %18 %22
1731 OpBranch %60
1732 %60 = OpLabel
1733 OpBranch %17
1734 %17 = OpLabel
1735 OpReturn
1736 OpFunctionEnd
1737 )";
1738
1739 const auto env = SPV_ENV_UNIVERSAL_1_4;
1740 const auto consumer = nullptr;
1741 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1742 spvtools::ValidatorOptions validator_options;
1743 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1744 kConsoleMessageConsumer));
1745 TransformationContext transformation_context(
1746 MakeUnique<FactManager>(context.get()), validator_options);
1747
1748 TransformationDuplicateRegionWithSelection transformation_bad =
1749 TransformationDuplicateRegionWithSelection(500, 25, 501, 60, 60,
1750 {{60, 101}}, {{}}, {{}});
1751
1752 ASSERT_FALSE(
1753 transformation_bad.IsApplicable(context.get(), transformation_context));
1754 }
1755
1756 TEST(TransformationDuplicateRegionWithSelectionTest, OverflowIds) {
1757 // This test checks that the transformation correctly uses overflow ids, when
1758 // they are both needed and provided.
1759
1760 std::string shader = R"(
1761 OpCapability Shader
1762 %1 = OpExtInstImport "GLSL.std.450"
1763 OpMemoryModel Logical GLSL450
1764 OpEntryPoint Fragment %4 "main"
1765 OpExecutionMode %4 OriginUpperLeft
1766 OpSource ESSL 310
1767 OpName %4 "main"
1768 OpName %6 "fun("
1769 OpName %10 "s"
1770 OpName %17 "b"
1771 %2 = OpTypeVoid
1772 %3 = OpTypeFunction %2
1773 %8 = OpTypeInt 32 1
1774 %9 = OpTypePointer Function %8
1775 %11 = OpConstant %8 0
1776 %13 = OpConstant %8 2
1777 %15 = OpTypeBool
1778 %16 = OpTypePointer Function %15
1779 %18 = OpConstantTrue %15
1780 %4 = OpFunction %2 None %3
1781 %5 = OpLabel
1782 %17 = OpVariable %16 Function
1783 OpStore %17 %18
1784 %19 = OpFunctionCall %2 %6
1785 OpReturn
1786 OpFunctionEnd
1787 %6 = OpFunction %2 None %3
1788 %7 = OpLabel
1789 %10 = OpVariable %9 Function
1790 OpBranch %50
1791 %50 = OpLabel
1792 OpStore %10 %11
1793 %12 = OpLoad %8 %10
1794 %14 = OpIAdd %8 %12 %13
1795 OpStore %10 %14
1796 OpKill
1797 OpFunctionEnd
1798 )";
1799
1800 const auto env = SPV_ENV_UNIVERSAL_1_4;
1801 const auto consumer = nullptr;
1802 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1803 spvtools::ValidatorOptions validator_options;
1804 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1805 kConsoleMessageConsumer));
1806 auto overflow_ids_unique_ptr = MakeUnique<CounterOverflowIdSource>(1000);
1807 auto overflow_ids_ptr = overflow_ids_unique_ptr.get();
1808 TransformationContext transformation_context(
1809 MakeUnique<FactManager>(context.get()), validator_options,
1810 std::move(overflow_ids_unique_ptr));
1811
1812 // The mappings do not provide sufficient ids, thus overflow ids are required.
1813 TransformationDuplicateRegionWithSelection transformation_good_1 =
1814 TransformationDuplicateRegionWithSelection(500, 18, 501, 50, 50, {},
1815 {{12, 201}}, {{14, 302}});
1816 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
1817 transformation_context));
1818 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
1819 &transformation_context,
1820 overflow_ids_ptr->GetIssuedOverflowIds());
1821 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1822 kConsoleMessageConsumer));
1823
1824 std::string expected_shader = R"(
1825 OpCapability Shader
1826 %1 = OpExtInstImport "GLSL.std.450"
1827 OpMemoryModel Logical GLSL450
1828 OpEntryPoint Fragment %4 "main"
1829 OpExecutionMode %4 OriginUpperLeft
1830 OpSource ESSL 310
1831 OpName %4 "main"
1832 OpName %6 "fun("
1833 OpName %10 "s"
1834 OpName %17 "b"
1835 %2 = OpTypeVoid
1836 %3 = OpTypeFunction %2
1837 %8 = OpTypeInt 32 1
1838 %9 = OpTypePointer Function %8
1839 %11 = OpConstant %8 0
1840 %13 = OpConstant %8 2
1841 %15 = OpTypeBool
1842 %16 = OpTypePointer Function %15
1843 %18 = OpConstantTrue %15
1844 %4 = OpFunction %2 None %3
1845 %5 = OpLabel
1846 %17 = OpVariable %16 Function
1847 OpStore %17 %18
1848 %19 = OpFunctionCall %2 %6
1849 OpReturn
1850 OpFunctionEnd
1851 %6 = OpFunction %2 None %3
1852 %7 = OpLabel
1853 %10 = OpVariable %9 Function
1854 OpBranch %500
1855 %500 = OpLabel
1856 OpSelectionMerge %501 None
1857 OpBranchConditional %18 %50 %1000
1858 %50 = OpLabel
1859 OpStore %10 %11
1860 %12 = OpLoad %8 %10
1861 %14 = OpIAdd %8 %12 %13
1862 OpStore %10 %14
1863 OpBranch %501
1864 %1000 = OpLabel
1865 OpStore %10 %11
1866 %201 = OpLoad %8 %10
1867 %1002 = OpIAdd %8 %201 %13
1868 OpStore %10 %1002
1869 OpBranch %501
1870 %501 = OpLabel
1871 %1001 = OpPhi %8 %12 %50 %201 %1000
1872 %302 = OpPhi %8 %14 %50 %1002 %1000
1873 OpKill
1874 OpFunctionEnd
1875 )";
1876
1877 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1878 }
1879
1880 TEST(TransformationDuplicateRegionWithSelectionTest,
1881 RegionExitIsOpBranchConditional) {
1882 // Checks the case where the exit block of a region ends with
1883 // OpBranchConditional (but is not a header).
1884 std::string shader = R"(
1885 OpCapability Shader
1886 %1 = OpExtInstImport "GLSL.std.450"
1887 OpMemoryModel Logical GLSL450
1888 OpEntryPoint Fragment %4 "main"
1889 OpExecutionMode %4 OriginUpperLeft
1890 OpSource ESSL 320
1891 OpName %4 "main"
1892 OpName %8 "i"
1893 %2 = OpTypeVoid
1894 %3 = OpTypeFunction %2
1895 %6 = OpTypeInt 32 1
1896 %7 = OpTypePointer Function %6
1897 %9 = OpConstant %6 0
1898 %16 = OpConstant %6 100
1899 %17 = OpTypeBool
1900 %50 = OpConstantTrue %17
1901 %20 = OpConstant %6 1
1902 %4 = OpFunction %2 None %3
1903 %5 = OpLabel
1904 %8 = OpVariable %7 Function
1905 OpStore %8 %9
1906 OpBranch %10
1907 %10 = OpLabel
1908 OpLoopMerge %12 %13 None
1909 OpBranch %14
1910 %14 = OpLabel
1911 %15 = OpLoad %6 %8
1912 %18 = OpSLessThan %17 %15 %16
1913 OpBranchConditional %18 %11 %12
1914 %11 = OpLabel
1915 %19 = OpLoad %6 %8
1916 %21 = OpIAdd %6 %19 %20
1917 OpStore %8 %21
1918 OpBranchConditional %50 %13 %12
1919 %13 = OpLabel
1920 %22 = OpLoad %6 %8
1921 %23 = OpIAdd %6 %22 %20
1922 OpStore %8 %23
1923 OpBranch %10
1924 %12 = OpLabel
1925 OpReturn
1926 OpFunctionEnd
1927 )";
1928
1929 const auto env = SPV_ENV_UNIVERSAL_1_4;
1930 const auto consumer = nullptr;
1931 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1932 spvtools::ValidatorOptions validator_options;
1933 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1934 kConsoleMessageConsumer));
1935 TransformationContext transformation_context(
1936 MakeUnique<FactManager>(context.get()), validator_options);
1937
1938 TransformationDuplicateRegionWithSelection transformation_good_1 =
1939 TransformationDuplicateRegionWithSelection(
1940 600, 50, 601, 11, 11, {{11, 602}}, {{19, 603}, {21, 604}},
1941 {{19, 605}, {21, 606}});
1942 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
1943 transformation_context));
1944 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
1945 &transformation_context);
1946 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1947 kConsoleMessageConsumer));
1948
1949 std::string expected_shader = R"(
1950 OpCapability Shader
1951 %1 = OpExtInstImport "GLSL.std.450"
1952 OpMemoryModel Logical GLSL450
1953 OpEntryPoint Fragment %4 "main"
1954 OpExecutionMode %4 OriginUpperLeft
1955 OpSource ESSL 320
1956 OpName %4 "main"
1957 OpName %8 "i"
1958 %2 = OpTypeVoid
1959 %3 = OpTypeFunction %2
1960 %6 = OpTypeInt 32 1
1961 %7 = OpTypePointer Function %6
1962 %9 = OpConstant %6 0
1963 %16 = OpConstant %6 100
1964 %17 = OpTypeBool
1965 %50 = OpConstantTrue %17
1966 %20 = OpConstant %6 1
1967 %4 = OpFunction %2 None %3
1968 %5 = OpLabel
1969 %8 = OpVariable %7 Function
1970 OpStore %8 %9
1971 OpBranch %10
1972 %10 = OpLabel
1973 OpLoopMerge %12 %13 None
1974 OpBranch %14
1975 %14 = OpLabel
1976 %15 = OpLoad %6 %8
1977 %18 = OpSLessThan %17 %15 %16
1978 OpBranchConditional %18 %600 %12
1979 %600 = OpLabel
1980 OpSelectionMerge %601 None
1981 OpBranchConditional %50 %11 %602
1982 %11 = OpLabel
1983 %19 = OpLoad %6 %8
1984 %21 = OpIAdd %6 %19 %20
1985 OpStore %8 %21
1986 OpBranch %601
1987 %602 = OpLabel
1988 %603 = OpLoad %6 %8
1989 %604 = OpIAdd %6 %603 %20
1990 OpStore %8 %604
1991 OpBranch %601
1992 %601 = OpLabel
1993 %605 = OpPhi %6 %19 %11 %603 %602
1994 %606 = OpPhi %6 %21 %11 %604 %602
1995 OpBranchConditional %50 %13 %12
1996 %13 = OpLabel
1997 %22 = OpLoad %6 %8
1998 %23 = OpIAdd %6 %22 %20
1999 OpStore %8 %23
2000 OpBranch %10
2001 %12 = OpLabel
2002 OpReturn
2003 OpFunctionEnd
2004 )";
2005
2006 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
2007 }
2008
2009 TEST(TransformationDuplicateRegionWithSelectionTest,
2010 RegionExitIsOpBranchConditionalUsingBooleanDefinedInBlock) {
2011 std::string shader = R"(
2012 OpCapability Shader
2013 %1 = OpExtInstImport "GLSL.std.450"
2014 OpMemoryModel Logical GLSL450
2015 OpEntryPoint Fragment %4 "main"
2016 OpExecutionMode %4 OriginUpperLeft
2017 OpSource ESSL 320
2018 OpName %4 "main"
2019 OpName %8 "i"
2020 %2 = OpTypeVoid
2021 %3 = OpTypeFunction %2
2022 %6 = OpTypeInt 32 1
2023 %7 = OpTypePointer Function %6
2024 %9 = OpConstant %6 0
2025 %16 = OpConstant %6 100
2026 %17 = OpTypeBool
2027 %50 = OpConstantTrue %17
2028 %20 = OpConstant %6 1
2029 %4 = OpFunction %2 None %3
2030 %5 = OpLabel
2031 %8 = OpVariable %7 Function
2032 OpStore %8 %9
2033 OpBranch %10
2034 %10 = OpLabel
2035 OpLoopMerge %12 %13 None
2036 OpBranch %14
2037 %14 = OpLabel
2038 %15 = OpLoad %6 %8
2039 %18 = OpSLessThan %17 %15 %16
2040 OpBranchConditional %18 %11 %12
2041 %11 = OpLabel
2042 %19 = OpLoad %6 %8
2043 %21 = OpIAdd %6 %19 %20
2044 %70 = OpCopyObject %17 %50
2045 OpStore %8 %21
2046 OpBranchConditional %70 %13 %12
2047 %13 = OpLabel
2048 %22 = OpLoad %6 %8
2049 %23 = OpIAdd %6 %22 %20
2050 OpStore %8 %23
2051 OpBranch %10
2052 %12 = OpLabel
2053 OpReturn
2054 OpFunctionEnd
2055 )";
2056
2057 const auto env = SPV_ENV_UNIVERSAL_1_4;
2058 const auto consumer = nullptr;
2059 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2060 spvtools::ValidatorOptions validator_options;
2061 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2062 kConsoleMessageConsumer));
2063 TransformationContext transformation_context(
2064 MakeUnique<FactManager>(context.get()), validator_options);
2065
2066 TransformationDuplicateRegionWithSelection transformation_good_1 =
2067 TransformationDuplicateRegionWithSelection(
2068 600, 50, 601, 11, 11, {{11, 602}}, {{19, 603}, {21, 604}, {70, 608}},
2069 {{19, 605}, {21, 606}, {70, 607}});
2070 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
2071 transformation_context));
2072 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
2073 &transformation_context);
2074 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2075 kConsoleMessageConsumer));
2076
2077 std::string expected_shader = R"(
2078 OpCapability Shader
2079 %1 = OpExtInstImport "GLSL.std.450"
2080 OpMemoryModel Logical GLSL450
2081 OpEntryPoint Fragment %4 "main"
2082 OpExecutionMode %4 OriginUpperLeft
2083 OpSource ESSL 320
2084 OpName %4 "main"
2085 OpName %8 "i"
2086 %2 = OpTypeVoid
2087 %3 = OpTypeFunction %2
2088 %6 = OpTypeInt 32 1
2089 %7 = OpTypePointer Function %6
2090 %9 = OpConstant %6 0
2091 %16 = OpConstant %6 100
2092 %17 = OpTypeBool
2093 %50 = OpConstantTrue %17
2094 %20 = OpConstant %6 1
2095 %4 = OpFunction %2 None %3
2096 %5 = OpLabel
2097 %8 = OpVariable %7 Function
2098 OpStore %8 %9
2099 OpBranch %10
2100 %10 = OpLabel
2101 OpLoopMerge %12 %13 None
2102 OpBranch %14
2103 %14 = OpLabel
2104 %15 = OpLoad %6 %8
2105 %18 = OpSLessThan %17 %15 %16
2106 OpBranchConditional %18 %600 %12
2107 %600 = OpLabel
2108 OpSelectionMerge %601 None
2109 OpBranchConditional %50 %11 %602
2110 %11 = OpLabel
2111 %19 = OpLoad %6 %8
2112 %21 = OpIAdd %6 %19 %20
2113 %70 = OpCopyObject %17 %50
2114 OpStore %8 %21
2115 OpBranch %601
2116 %602 = OpLabel
2117 %603 = OpLoad %6 %8
2118 %604 = OpIAdd %6 %603 %20
2119 %608 = OpCopyObject %17 %50
2120 OpStore %8 %604
2121 OpBranch %601
2122 %601 = OpLabel
2123 %605 = OpPhi %6 %19 %11 %603 %602
2124 %606 = OpPhi %6 %21 %11 %604 %602
2125 %607 = OpPhi %17 %70 %11 %608 %602
2126 OpBranchConditional %607 %13 %12
2127 %13 = OpLabel
2128 %22 = OpLoad %6 %8
2129 %23 = OpIAdd %6 %22 %20
2130 OpStore %8 %23
2131 OpBranch %10
2132 %12 = OpLabel
2133 OpReturn
2134 OpFunctionEnd
2135 )";
2136
2137 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
2138 }
2139
2140 TEST(TransformationDuplicateRegionWithSelectionTest,
2141 RegionExitUsesOpReturnValueWithIdDefinedInRegion) {
2142 std::string shader = R"(
2143 OpCapability Shader
2144 %1 = OpExtInstImport "GLSL.std.450"
2145 OpMemoryModel Logical GLSL450
2146 OpEntryPoint Fragment %4 "main"
2147 OpExecutionMode %4 OriginUpperLeft
2148 OpSource ESSL 320
2149 %2 = OpTypeVoid
2150 %3 = OpTypeFunction %2
2151 %6 = OpTypeInt 32 1
2152 %7 = OpTypeFunction %6
2153 %10 = OpConstant %6 2
2154 %30 = OpTypeBool
2155 %31 = OpConstantTrue %30
2156 %4 = OpFunction %2 None %3
2157 %5 = OpLabel
2158 %13 = OpFunctionCall %6 %8
2159 OpReturn
2160 OpFunctionEnd
2161 %8 = OpFunction %6 None %7
2162 %9 = OpLabel
2163 OpBranch %20
2164 %20 = OpLabel
2165 %21 = OpCopyObject %6 %10
2166 OpReturnValue %21
2167 OpFunctionEnd
2168 )";
2169
2170 const auto env = SPV_ENV_UNIVERSAL_1_4;
2171 const auto consumer = nullptr;
2172 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2173 spvtools::ValidatorOptions validator_options;
2174 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2175 kConsoleMessageConsumer));
2176 TransformationContext transformation_context(
2177 MakeUnique<FactManager>(context.get()), validator_options);
2178
2179 TransformationDuplicateRegionWithSelection transformation_good_1 =
2180 TransformationDuplicateRegionWithSelection(
2181 600, 31, 601, 20, 20, {{20, 602}}, {{21, 603}}, {{21, 605}});
2182 ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
2183 transformation_context));
2184 ApplyAndCheckFreshIds(transformation_good_1, context.get(),
2185 &transformation_context);
2186 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2187 kConsoleMessageConsumer));
2188
2189 std::string expected_shader = R"(
2190 OpCapability Shader
2191 %1 = OpExtInstImport "GLSL.std.450"
2192 OpMemoryModel Logical GLSL450
2193 OpEntryPoint Fragment %4 "main"
2194 OpExecutionMode %4 OriginUpperLeft
2195 OpSource ESSL 320
2196 %2 = OpTypeVoid
2197 %3 = OpTypeFunction %2
2198 %6 = OpTypeInt 32 1
2199 %7 = OpTypeFunction %6
2200 %10 = OpConstant %6 2
2201 %30 = OpTypeBool
2202 %31 = OpConstantTrue %30
2203 %4 = OpFunction %2 None %3
2204 %5 = OpLabel
2205 %13 = OpFunctionCall %6 %8
2206 OpReturn
2207 OpFunctionEnd
2208 %8 = OpFunction %6 None %7
2209 %9 = OpLabel
2210 OpBranch %600
2211 %600 = OpLabel
2212 OpSelectionMerge %601 None
2213 OpBranchConditional %31 %20 %602
2214 %20 = OpLabel
2215 %21 = OpCopyObject %6 %10
2216 OpBranch %601
2217 %602 = OpLabel
2218 %603 = OpCopyObject %6 %10
2219 OpBranch %601
2220 %601 = OpLabel
2221 %605 = OpPhi %6 %21 %20 %603 %602
2222 OpReturnValue %605
2223 OpFunctionEnd
2224 )";
2225
2226 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
2227 }
2228
2229 TEST(TransformationDuplicateRegionWithSelectionTest,
2230 InapplicableDueToOpTypeSampledImage) {
2231 std::string reference_shader = R"(
2232 OpCapability Shader
2233 %1 = OpExtInstImport "GLSL.std.450"
2234 OpMemoryModel Logical GLSL450
2235 OpEntryPoint Fragment %4 "main" %10
2236 OpExecutionMode %4 OriginUpperLeft
2237 OpSource ESSL 320
2238 OpDecorate %10 RelaxedPrecision
2239 OpDecorate %10 DescriptorSet 0
2240 OpDecorate %10 Binding 0
2241 %2 = OpTypeVoid
2242 %3 = OpTypeFunction %2
2243 %6 = OpTypeFloat 32
2244 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
2245 %8 = OpTypeSampledImage %7
2246 %9 = OpTypePointer UniformConstant %8
2247 %10 = OpVariable %9 UniformConstant
2248 %12 = OpTypeVector %6 2
2249 %13 = OpConstant %6 0
2250 %14 = OpConstantComposite %12 %13 %13
2251 %15 = OpTypeVector %6 4
2252 %30 = OpTypeBool
2253 %31 = OpConstantTrue %30
2254 %4 = OpFunction %2 None %3
2255 %5 = OpLabel
2256 OpBranch %20
2257 %20 = OpLabel
2258 %11 = OpLoad %8 %10
2259 OpBranch %21
2260 %21 = OpLabel
2261 %16 = OpImageSampleImplicitLod %15 %11 %14
2262 OpReturn
2263 OpFunctionEnd
2264 )";
2265
2266 const auto env = SPV_ENV_UNIVERSAL_1_4;
2267 const auto consumer = nullptr;
2268 const auto context =
2269 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
2270 spvtools::ValidatorOptions validator_options;
2271 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2272 kConsoleMessageConsumer));
2273 TransformationContext transformation_context(
2274 MakeUnique<FactManager>(context.get()), validator_options);
2275
2276 ASSERT_FALSE(TransformationDuplicateRegionWithSelection(
2277 600, 31, 601, 20, 20, {{20, 602}}, {{11, 603}}, {{11, 605}})
2278 .IsApplicable(context.get(), transformation_context));
2279 }
2280
2281 TEST(TransformationDuplicateRegionWithSelectionTest,
2282 DoNotProduceOpPhiWithVoidType) {
2283 std::string reference_shader = R"(
2284 OpCapability Shader
2285 %1 = OpExtInstImport "GLSL.std.450"
2286 OpMemoryModel Logical GLSL450
2287 OpEntryPoint Fragment %4 "main"
2288 OpExecutionMode %4 OriginUpperLeft
2289 OpSource ESSL 320
2290 %2 = OpTypeVoid
2291 %3 = OpTypeFunction %2
2292 %10 = OpTypeBool
2293 %11 = OpConstantTrue %10
2294 %4 = OpFunction %2 None %3
2295 %12 = OpLabel
2296 OpBranch %5
2297 %5 = OpLabel
2298 %8 = OpFunctionCall %2 %6
2299 OpReturn
2300 OpFunctionEnd
2301 %6 = OpFunction %2 None %3
2302 %7 = OpLabel
2303 OpReturn
2304 OpFunctionEnd
2305 )";
2306
2307 const auto env = SPV_ENV_UNIVERSAL_1_4;
2308 const auto consumer = nullptr;
2309 const auto context =
2310 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
2311 spvtools::ValidatorOptions validator_options;
2312 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2313 kConsoleMessageConsumer));
2314 TransformationContext transformation_context(
2315 MakeUnique<FactManager>(context.get()), validator_options);
2316
2317 TransformationDuplicateRegionWithSelection transformation(
2318 100, 11, 101, 5, 5, {{5, 102}}, {{8, 103}}, {});
2319 ASSERT_TRUE(
2320 transformation.IsApplicable(context.get(), transformation_context));
2321 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
2322 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2323 kConsoleMessageConsumer));
2324
2325 std::string expected_shader = R"(
2326 OpCapability Shader
2327 %1 = OpExtInstImport "GLSL.std.450"
2328 OpMemoryModel Logical GLSL450
2329 OpEntryPoint Fragment %4 "main"
2330 OpExecutionMode %4 OriginUpperLeft
2331 OpSource ESSL 320
2332 %2 = OpTypeVoid
2333 %3 = OpTypeFunction %2
2334 %10 = OpTypeBool
2335 %11 = OpConstantTrue %10
2336 %4 = OpFunction %2 None %3
2337 %12 = OpLabel
2338 OpBranch %100
2339 %100 = OpLabel
2340 OpSelectionMerge %101 None
2341 OpBranchConditional %11 %5 %102
2342 %5 = OpLabel
2343 %8 = OpFunctionCall %2 %6
2344 OpBranch %101
2345 %102 = OpLabel
2346 %103 = OpFunctionCall %2 %6
2347 OpBranch %101
2348 %101 = OpLabel
2349 OpReturn
2350 OpFunctionEnd
2351 %6 = OpFunction %2 None %3
2352 %7 = OpLabel
2353 OpReturn
2354 OpFunctionEnd
2355 )";
2356
2357 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
2358 }
2359
2360 TEST(TransformationDuplicateRegionWithSelectionTest,
2361 DoNotProduceOpPhiWithDisallowedType) {
2362 std::string reference_shader = R"(
2363 OpCapability Shader
2364 %1 = OpExtInstImport "GLSL.std.450"
2365 OpMemoryModel Logical GLSL450
2366 OpEntryPoint Fragment %4 "main"
2367 OpExecutionMode %4 OriginUpperLeft
2368 OpSource ESSL 320
2369 OpDecorate %13 DescriptorSet 0
2370 OpDecorate %13 Binding 0
2371 %2 = OpTypeVoid
2372 %3 = OpTypeFunction %2
2373 %6 = OpTypeFloat 32
2374 %7 = OpTypeVector %6 2
2375 %8 = OpTypePointer Function %7
2376 %10 = OpTypeImage %6 2D 0 0 0 1 Unknown
2377 %11 = OpTypeSampledImage %10
2378 %12 = OpTypePointer UniformConstant %11
2379 %13 = OpVariable %12 UniformConstant
2380 %15 = OpConstant %6 1
2381 %16 = OpConstantComposite %7 %15 %15
2382 %17 = OpTypeVector %6 4
2383 %19 = OpTypeInt 32 0
2384 %20 = OpConstant %19 0
2385 %22 = OpTypePointer Function %6
2386 %90 = OpTypeBool
2387 %91 = OpConstantTrue %90
2388 %4 = OpFunction %2 None %3
2389 %5 = OpLabel
2390 %9 = OpVariable %8 Function
2391 OpBranch %81
2392 %81 = OpLabel
2393 %14 = OpLoad %11 %13
2394 %18 = OpImageSampleImplicitLod %17 %14 %16
2395 %21 = OpCompositeExtract %6 %18 0
2396 %23 = OpAccessChain %22 %9 %20
2397 OpStore %23 %21
2398 OpBranch %80
2399 %80 = OpLabel
2400 OpReturn
2401 OpFunctionEnd
2402 )";
2403
2404 const auto env = SPV_ENV_UNIVERSAL_1_3;
2405 const auto consumer = nullptr;
2406 const auto context =
2407 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
2408 spvtools::ValidatorOptions validator_options;
2409 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2410 kConsoleMessageConsumer));
2411 TransformationContext transformation_context(
2412 MakeUnique<FactManager>(context.get()), validator_options);
2413
2414 TransformationDuplicateRegionWithSelection transformation(
2415 100, 91, 101, 81, 81, {{81, 102}},
2416 {{14, 103}, {18, 104}, {21, 105}, {23, 106}}, {{18, 107}, {21, 108}});
2417 ASSERT_TRUE(
2418 transformation.IsApplicable(context.get(), transformation_context));
2419 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
2420 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2421 kConsoleMessageConsumer));
2422
2423 std::string expected_shader = R"(
2424 OpCapability Shader
2425 %1 = OpExtInstImport "GLSL.std.450"
2426 OpMemoryModel Logical GLSL450
2427 OpEntryPoint Fragment %4 "main"
2428 OpExecutionMode %4 OriginUpperLeft
2429 OpSource ESSL 320
2430 OpDecorate %13 DescriptorSet 0
2431 OpDecorate %13 Binding 0
2432 %2 = OpTypeVoid
2433 %3 = OpTypeFunction %2
2434 %6 = OpTypeFloat 32
2435 %7 = OpTypeVector %6 2
2436 %8 = OpTypePointer Function %7
2437 %10 = OpTypeImage %6 2D 0 0 0 1 Unknown
2438 %11 = OpTypeSampledImage %10
2439 %12 = OpTypePointer UniformConstant %11
2440 %13 = OpVariable %12 UniformConstant
2441 %15 = OpConstant %6 1
2442 %16 = OpConstantComposite %7 %15 %15
2443 %17 = OpTypeVector %6 4
2444 %19 = OpTypeInt 32 0
2445 %20 = OpConstant %19 0
2446 %22 = OpTypePointer Function %6
2447 %90 = OpTypeBool
2448 %91 = OpConstantTrue %90
2449 %4 = OpFunction %2 None %3
2450 %5 = OpLabel
2451 %9 = OpVariable %8 Function
2452 OpBranch %100
2453 %100 = OpLabel
2454 OpSelectionMerge %101 None
2455 OpBranchConditional %91 %81 %102
2456 %81 = OpLabel
2457 %14 = OpLoad %11 %13
2458 %18 = OpImageSampleImplicitLod %17 %14 %16
2459 %21 = OpCompositeExtract %6 %18 0
2460 %23 = OpAccessChain %22 %9 %20
2461 OpStore %23 %21
2462 OpBranch %101
2463 %102 = OpLabel
2464 %103 = OpLoad %11 %13
2465 %104 = OpImageSampleImplicitLod %17 %103 %16
2466 %105 = OpCompositeExtract %6 %104 0
2467 %106 = OpAccessChain %22 %9 %20
2468 OpStore %106 %105
2469 OpBranch %101
2470 %101 = OpLabel
2471 %107 = OpPhi %17 %18 %81 %104 %102
2472 %108 = OpPhi %6 %21 %81 %105 %102
2473 OpBranch %80
2474 %80 = OpLabel
2475 OpReturn
2476 OpFunctionEnd
2477 )";
2478
2479 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
2480 }
2481
2482 } // namespace
2483 } // namespace fuzz
2484 } // namespace spvtools
2485