1 // Copyright (c) 2020 Vasyl Teliman
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_propagate_instruction_up.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "test/fuzz/fuzz_test_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24
TEST(TransformationPropagateInstructionUpTest,BasicTest)25 TEST(TransformationPropagateInstructionUpTest, BasicTest) {
26 std::string shader = R"(
27 OpCapability Shader
28 %1 = OpExtInstImport "GLSL.std.450"
29 OpMemoryModel Logical GLSL450
30 OpEntryPoint Fragment %4 "main"
31 OpExecutionMode %4 OriginUpperLeft
32 OpSource ESSL 310
33 %2 = OpTypeVoid
34 %3 = OpTypeFunction %2
35 %6 = OpTypeFloat 32
36 %7 = OpTypePointer Function %6
37 %9 = OpConstant %6 3.5
38 %11 = OpConstant %6 3.4000001
39 %12 = OpTypeBool
40 %17 = OpConstant %6 4
41 %20 = OpConstant %6 45
42 %27 = OpTypePointer Function %6
43 %4 = OpFunction %2 None %3
44
45 %5 = OpLabel
46 %26 = OpVariable %27 Function
47 %13 = OpFOrdEqual %12 %9 %11
48 OpSelectionMerge %15 None
49 OpBranchConditional %13 %14 %19
50
51 %14 = OpLabel
52 %18 = OpFMod %6 %9 %17
53 OpBranch %15
54
55 %19 = OpLabel
56 %22 = OpFAdd %6 %11 %20
57 OpBranch %15
58
59 %15 = OpLabel
60 %21 = OpPhi %6 %18 %14 %22 %19
61 %23 = OpFMul %6 %21 %21
62 %24 = OpFDiv %6 %21 %23
63 OpBranch %25
64
65 %25 = OpLabel
66 %28 = OpPhi %6 %20 %15
67 OpStore %26 %28
68 OpReturn
69
70 OpFunctionEnd
71 )";
72
73 const auto env = SPV_ENV_UNIVERSAL_1_3;
74 const auto consumer = nullptr;
75 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
76 spvtools::ValidatorOptions validator_options;
77 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
78 kConsoleMessageConsumer));
79 TransformationContext transformation_context(
80 MakeUnique<FactManager>(context.get()), validator_options);
81 // |block_id| is invalid.
82 ASSERT_FALSE(TransformationPropagateInstructionUp(40, {{}}).IsApplicable(
83 context.get(), transformation_context));
84 ASSERT_FALSE(TransformationPropagateInstructionUp(26, {{}}).IsApplicable(
85 context.get(), transformation_context));
86
87 // |block_id| has no predecessors.
88 ASSERT_FALSE(TransformationPropagateInstructionUp(5, {{}}).IsApplicable(
89 context.get(), transformation_context));
90
91 // |block_id| has no valid instructions to propagate.
92 ASSERT_FALSE(TransformationPropagateInstructionUp(25, {{{15, 40}}})
93 .IsApplicable(context.get(), transformation_context));
94
95 // Not all predecessors have fresh ids.
96 ASSERT_FALSE(TransformationPropagateInstructionUp(15, {{{19, 40}, {40, 41}}})
97 .IsApplicable(context.get(), transformation_context));
98
99 // Not all ids are fresh.
100 ASSERT_FALSE(
101 TransformationPropagateInstructionUp(15, {{{19, 40}, {14, 14}, {40, 42}}})
102 .IsApplicable(context.get(), transformation_context));
103 ASSERT_FALSE(
104 TransformationPropagateInstructionUp(15, {{{19, 19}, {14, 40}, {40, 42}}})
105 .IsApplicable(context.get(), transformation_context));
106
107 // Fresh ids have duplicates.
108 ASSERT_FALSE(
109 TransformationPropagateInstructionUp(15, {{{19, 40}, {14, 40}, {19, 41}}})
110 .IsApplicable(context.get(), transformation_context));
111
112 // Valid transformations.
113 {
114 TransformationPropagateInstructionUp transformation(14, {{{5, 40}}});
115 ASSERT_TRUE(
116 transformation.IsApplicable(context.get(), transformation_context));
117 ApplyAndCheckFreshIds(transformation, context.get(),
118 &transformation_context);
119 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
120 context.get(), validator_options, kConsoleMessageConsumer));
121 }
122 {
123 TransformationPropagateInstructionUp transformation(19, {{{5, 41}}});
124 ASSERT_TRUE(
125 transformation.IsApplicable(context.get(), transformation_context));
126 ApplyAndCheckFreshIds(transformation, context.get(),
127 &transformation_context);
128 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
129 context.get(), validator_options, kConsoleMessageConsumer));
130 }
131
132 std::string after_transformation = R"(
133 OpCapability Shader
134 %1 = OpExtInstImport "GLSL.std.450"
135 OpMemoryModel Logical GLSL450
136 OpEntryPoint Fragment %4 "main"
137 OpExecutionMode %4 OriginUpperLeft
138 OpSource ESSL 310
139 %2 = OpTypeVoid
140 %3 = OpTypeFunction %2
141 %6 = OpTypeFloat 32
142 %7 = OpTypePointer Function %6
143 %9 = OpConstant %6 3.5
144 %11 = OpConstant %6 3.4000001
145 %12 = OpTypeBool
146 %17 = OpConstant %6 4
147 %20 = OpConstant %6 45
148 %27 = OpTypePointer Function %6
149 %4 = OpFunction %2 None %3
150
151 %5 = OpLabel
152 %26 = OpVariable %27 Function
153 %13 = OpFOrdEqual %12 %9 %11
154 %40 = OpFMod %6 %9 %17 ; propagated from %14
155 %41 = OpFAdd %6 %11 %20 ; propagated from %19
156 OpSelectionMerge %15 None
157 OpBranchConditional %13 %14 %19
158
159 %14 = OpLabel
160 %18 = OpPhi %6 %40 %5 ; propagated into %5
161 OpBranch %15
162
163 %19 = OpLabel
164 %22 = OpPhi %6 %41 %5 ; propagated into %5
165 OpBranch %15
166
167 %15 = OpLabel
168 %21 = OpPhi %6 %18 %14 %22 %19
169 %23 = OpFMul %6 %21 %21
170 %24 = OpFDiv %6 %21 %23
171 OpBranch %25
172
173 %25 = OpLabel
174 %28 = OpPhi %6 %20 %15
175 OpStore %26 %28
176 OpReturn
177
178 OpFunctionEnd
179 )";
180
181 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
182
183 {
184 TransformationPropagateInstructionUp transformation(15,
185 {{{14, 43}, {19, 44}}});
186 ASSERT_TRUE(
187 transformation.IsApplicable(context.get(), transformation_context));
188 ApplyAndCheckFreshIds(transformation, context.get(),
189 &transformation_context);
190 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
191 context.get(), validator_options, kConsoleMessageConsumer));
192 }
193
194 after_transformation = R"(
195 OpCapability Shader
196 %1 = OpExtInstImport "GLSL.std.450"
197 OpMemoryModel Logical GLSL450
198 OpEntryPoint Fragment %4 "main"
199 OpExecutionMode %4 OriginUpperLeft
200 OpSource ESSL 310
201 %2 = OpTypeVoid
202 %3 = OpTypeFunction %2
203 %6 = OpTypeFloat 32
204 %7 = OpTypePointer Function %6
205 %9 = OpConstant %6 3.5
206 %11 = OpConstant %6 3.4000001
207 %12 = OpTypeBool
208 %17 = OpConstant %6 4
209 %20 = OpConstant %6 45
210 %27 = OpTypePointer Function %6
211 %4 = OpFunction %2 None %3
212
213 %5 = OpLabel
214 %26 = OpVariable %27 Function
215 %13 = OpFOrdEqual %12 %9 %11
216 %40 = OpFMod %6 %9 %17
217 %41 = OpFAdd %6 %11 %20
218 OpSelectionMerge %15 None
219 OpBranchConditional %13 %14 %19
220
221 %14 = OpLabel
222 %18 = OpPhi %6 %40 %5
223 %43 = OpFMul %6 %18 %18 ; propagated from %15
224 OpBranch %15
225
226 %19 = OpLabel
227 %22 = OpPhi %6 %41 %5
228 %44 = OpFMul %6 %22 %22 ; propagated from %15
229 OpBranch %15
230
231 %15 = OpLabel
232 %23 = OpPhi %6 %43 %14 %44 %19 ; propagated into %14 and %19
233 %21 = OpPhi %6 %18 %14 %22 %19
234 %24 = OpFDiv %6 %21 %23
235 OpBranch %25
236
237 %25 = OpLabel
238 %28 = OpPhi %6 %20 %15
239 OpStore %26 %28
240 OpReturn
241
242 OpFunctionEnd
243 )";
244
245 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
246
247 {
248 TransformationPropagateInstructionUp transformation(15,
249 {{{14, 45}, {19, 46}}});
250 ASSERT_TRUE(
251 transformation.IsApplicable(context.get(), transformation_context));
252 ApplyAndCheckFreshIds(transformation, context.get(),
253 &transformation_context);
254 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
255 context.get(), validator_options, kConsoleMessageConsumer));
256 }
257
258 after_transformation = R"(
259 OpCapability Shader
260 %1 = OpExtInstImport "GLSL.std.450"
261 OpMemoryModel Logical GLSL450
262 OpEntryPoint Fragment %4 "main"
263 OpExecutionMode %4 OriginUpperLeft
264 OpSource ESSL 310
265 %2 = OpTypeVoid
266 %3 = OpTypeFunction %2
267 %6 = OpTypeFloat 32
268 %7 = OpTypePointer Function %6
269 %9 = OpConstant %6 3.5
270 %11 = OpConstant %6 3.4000001
271 %12 = OpTypeBool
272 %17 = OpConstant %6 4
273 %20 = OpConstant %6 45
274 %27 = OpTypePointer Function %6
275 %4 = OpFunction %2 None %3
276
277 %5 = OpLabel
278 %26 = OpVariable %27 Function
279 %13 = OpFOrdEqual %12 %9 %11
280 %40 = OpFMod %6 %9 %17
281 %41 = OpFAdd %6 %11 %20
282 OpSelectionMerge %15 None
283 OpBranchConditional %13 %14 %19
284
285 %14 = OpLabel
286 %18 = OpPhi %6 %40 %5
287 %43 = OpFMul %6 %18 %18
288 %45 = OpFDiv %6 %18 %43 ; propagated from %15
289 OpBranch %15
290
291 %19 = OpLabel
292 %22 = OpPhi %6 %41 %5
293 %44 = OpFMul %6 %22 %22
294 %46 = OpFDiv %6 %22 %44 ; propagated from %15
295 OpBranch %15
296
297 %15 = OpLabel
298 %24 = OpPhi %6 %45 %14 %46 %19 ; propagated into %14 and %19
299 %23 = OpPhi %6 %43 %14 %44 %19
300 %21 = OpPhi %6 %18 %14 %22 %19
301 OpBranch %25
302
303 %25 = OpLabel
304 %28 = OpPhi %6 %20 %15
305 OpStore %26 %28
306 OpReturn
307
308 OpFunctionEnd
309 )";
310
311 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
312 }
313
TEST(TransformationPropagateInstructionUpTest,BlockDominatesPredecessor1)314 TEST(TransformationPropagateInstructionUpTest, BlockDominatesPredecessor1) {
315 std::string shader = R"(
316 OpCapability Shader
317 %1 = OpExtInstImport "GLSL.std.450"
318 OpMemoryModel Logical GLSL450
319 OpEntryPoint Fragment %4 "main"
320 OpExecutionMode %4 OriginUpperLeft
321 OpSource ESSL 310
322 %2 = OpTypeVoid
323 %3 = OpTypeFunction %2
324 %6 = OpTypeFloat 32
325 %7 = OpTypePointer Function %6
326 %9 = OpConstant %6 3.5
327 %11 = OpConstant %6 3.4000001
328 %12 = OpTypeBool
329 %17 = OpConstant %6 4
330 %20 = OpConstant %6 45
331 %4 = OpFunction %2 None %3
332
333 %5 = OpLabel
334 %13 = OpFOrdEqual %12 %9 %11
335 OpSelectionMerge %15 None
336 OpBranchConditional %13 %14 %19
337
338 %14 = OpLabel
339 %18 = OpFMod %6 %9 %17
340 OpBranch %15
341
342 %19 = OpLabel
343 %22 = OpFAdd %6 %11 %20
344 OpBranch %15
345
346 %15 = OpLabel ; dominates %26
347 %21 = OpPhi %6 %18 %14 %22 %19 %28 %26
348 %23 = OpFMul %6 %21 %21
349 %24 = OpFDiv %6 %21 %23
350 OpLoopMerge %27 %26 None
351 OpBranch %26
352
353 %26 = OpLabel
354 %28 = OpFAdd %6 %24 %23
355 OpBranch %15
356
357 %27 = OpLabel
358 OpReturn
359
360 OpFunctionEnd
361 )";
362
363 const auto env = SPV_ENV_UNIVERSAL_1_3;
364 const auto consumer = nullptr;
365 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
366 spvtools::ValidatorOptions validator_options;
367 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
368 kConsoleMessageConsumer));
369 TransformationContext transformation_context(
370 MakeUnique<FactManager>(context.get()), validator_options);
371 TransformationPropagateInstructionUp transformation(
372 15, {{{14, 40}, {19, 41}, {26, 42}}});
373 ASSERT_TRUE(
374 transformation.IsApplicable(context.get(), transformation_context));
375 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
376 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
377 kConsoleMessageConsumer));
378
379 std::string after_transformation = R"(
380 OpCapability Shader
381 %1 = OpExtInstImport "GLSL.std.450"
382 OpMemoryModel Logical GLSL450
383 OpEntryPoint Fragment %4 "main"
384 OpExecutionMode %4 OriginUpperLeft
385 OpSource ESSL 310
386 %2 = OpTypeVoid
387 %3 = OpTypeFunction %2
388 %6 = OpTypeFloat 32
389 %7 = OpTypePointer Function %6
390 %9 = OpConstant %6 3.5
391 %11 = OpConstant %6 3.4000001
392 %12 = OpTypeBool
393 %17 = OpConstant %6 4
394 %20 = OpConstant %6 45
395 %4 = OpFunction %2 None %3
396
397 %5 = OpLabel
398 %13 = OpFOrdEqual %12 %9 %11
399 OpSelectionMerge %15 None
400 OpBranchConditional %13 %14 %19
401
402 %14 = OpLabel
403 %18 = OpFMod %6 %9 %17
404 %40 = OpFMul %6 %18 %18 ; propagated from %15
405 OpBranch %15
406
407 %19 = OpLabel
408 %22 = OpFAdd %6 %11 %20
409 %41 = OpFMul %6 %22 %22 ; propagated from %15
410 OpBranch %15
411
412 %15 = OpLabel
413 %23 = OpPhi %6 %40 %14 %41 %19 %42 %26 ; propagated into %14, %19, %26
414 %21 = OpPhi %6 %18 %14 %22 %19 %28 %26
415 %24 = OpFDiv %6 %21 %23
416 OpLoopMerge %27 %26 None
417 OpBranch %26
418
419 %26 = OpLabel
420 %28 = OpFAdd %6 %24 %23
421 %42 = OpFMul %6 %28 %28 ; propagated from %15
422 OpBranch %15
423
424 %27 = OpLabel
425 OpReturn
426
427 OpFunctionEnd
428 )";
429
430 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
431 }
432
TEST(TransformationPropagateInstructionUpTest,BlockDominatesPredecessor2)433 TEST(TransformationPropagateInstructionUpTest, BlockDominatesPredecessor2) {
434 std::string shader = R"(
435 OpCapability Shader
436 %1 = OpExtInstImport "GLSL.std.450"
437 OpMemoryModel Logical GLSL450
438 OpEntryPoint Fragment %4 "main"
439 OpExecutionMode %4 OriginUpperLeft
440 OpSource ESSL 310
441 %2 = OpTypeVoid
442 %3 = OpTypeFunction %2
443 %6 = OpTypeFloat 32
444 %7 = OpTypePointer Function %6
445 %9 = OpConstant %6 3.5
446 %11 = OpConstant %6 3.4000001
447 %12 = OpTypeBool
448 %17 = OpConstant %6 4
449 %20 = OpConstant %6 45
450 %4 = OpFunction %2 None %3
451
452 %5 = OpLabel
453 %13 = OpFOrdEqual %12 %9 %11
454 OpSelectionMerge %15 None
455 OpBranchConditional %13 %14 %19
456
457 %14 = OpLabel
458 %18 = OpFMod %6 %9 %17
459 OpBranch %15
460
461 %19 = OpLabel
462 %22 = OpFAdd %6 %11 %20
463 OpBranch %15
464
465 %15 = OpLabel ; doesn't dominate %26
466 %21 = OpPhi %6 %18 %14 %22 %19 %20 %26
467 %23 = OpFMul %6 %21 %21
468 %24 = OpFDiv %6 %21 %23
469 OpLoopMerge %27 %26 None
470 OpBranch %27
471
472 %26 = OpLabel
473 OpBranch %15
474
475 %27 = OpLabel
476 OpReturn
477
478 OpFunctionEnd
479 )";
480
481 const auto env = SPV_ENV_UNIVERSAL_1_3;
482 const auto consumer = nullptr;
483 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
484 spvtools::ValidatorOptions validator_options;
485 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
486 kConsoleMessageConsumer));
487 TransformationContext transformation_context(
488 MakeUnique<FactManager>(context.get()), validator_options);
489 TransformationPropagateInstructionUp transformation(
490 15, {{{14, 40}, {19, 41}, {26, 42}}});
491 ASSERT_TRUE(
492 transformation.IsApplicable(context.get(), transformation_context));
493 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
494 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
495 kConsoleMessageConsumer));
496
497 std::string after_transformation = R"(
498 OpCapability Shader
499 %1 = OpExtInstImport "GLSL.std.450"
500 OpMemoryModel Logical GLSL450
501 OpEntryPoint Fragment %4 "main"
502 OpExecutionMode %4 OriginUpperLeft
503 OpSource ESSL 310
504 %2 = OpTypeVoid
505 %3 = OpTypeFunction %2
506 %6 = OpTypeFloat 32
507 %7 = OpTypePointer Function %6
508 %9 = OpConstant %6 3.5
509 %11 = OpConstant %6 3.4000001
510 %12 = OpTypeBool
511 %17 = OpConstant %6 4
512 %20 = OpConstant %6 45
513 %4 = OpFunction %2 None %3
514
515 %5 = OpLabel
516 %13 = OpFOrdEqual %12 %9 %11
517 OpSelectionMerge %15 None
518 OpBranchConditional %13 %14 %19
519
520 %14 = OpLabel
521 %18 = OpFMod %6 %9 %17
522 %40 = OpFMul %6 %18 %18 ; propagated from %15
523 OpBranch %15
524
525 %19 = OpLabel
526 %22 = OpFAdd %6 %11 %20
527 %41 = OpFMul %6 %22 %22 ; propagated from %15
528 OpBranch %15
529
530 %15 = OpLabel
531 %23 = OpPhi %6 %40 %14 %41 %19 %42 %26 ; propagated into %14, %19, %26
532 %21 = OpPhi %6 %18 %14 %22 %19 %20 %26
533 %24 = OpFDiv %6 %21 %23
534 OpLoopMerge %27 %26 None
535 OpBranch %27
536
537 %26 = OpLabel
538 %42 = OpFMul %6 %20 %20 ; propagated from %15
539 OpBranch %15
540
541 %27 = OpLabel
542 OpReturn
543
544 OpFunctionEnd
545 )";
546
547 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
548 }
549
TEST(TransformationPropagateInstructionUpTest,BlockDominatesPredecessor3)550 TEST(TransformationPropagateInstructionUpTest, BlockDominatesPredecessor3) {
551 std::string shader = R"(
552 OpCapability Shader
553 %1 = OpExtInstImport "GLSL.std.450"
554 OpMemoryModel Logical GLSL450
555 OpEntryPoint Fragment %4 "main"
556 OpExecutionMode %4 OriginUpperLeft
557 OpSource ESSL 310
558 %2 = OpTypeVoid
559 %3 = OpTypeFunction %2
560 %6 = OpTypeFloat 32
561 %7 = OpTypePointer Function %6
562 %9 = OpConstant %6 3.5
563 %11 = OpConstant %6 3.4000001
564 %12 = OpTypeBool
565 %17 = OpConstant %6 4
566 %20 = OpConstant %6 45
567 %4 = OpFunction %2 None %3
568
569 %5 = OpLabel
570 %13 = OpFOrdEqual %12 %9 %11
571 OpSelectionMerge %15 None
572 OpBranchConditional %13 %14 %19
573
574 %14 = OpLabel
575 %18 = OpFMod %6 %9 %17
576 OpBranch %15
577
578 %19 = OpLabel
579 %22 = OpFAdd %6 %11 %20
580 OpBranch %15
581
582 %15 = OpLabel ; branches to itself
583 %21 = OpPhi %6 %18 %14 %22 %19 %24 %15
584 %23 = OpFMul %6 %21 %21
585 %24 = OpFDiv %6 %21 %23
586 OpLoopMerge %27 %15 None
587 OpBranch %15
588
589 %27 = OpLabel
590 OpReturn
591
592 OpFunctionEnd
593 )";
594
595 const auto env = SPV_ENV_UNIVERSAL_1_3;
596 const auto consumer = nullptr;
597 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
598 spvtools::ValidatorOptions validator_options;
599 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
600 kConsoleMessageConsumer));
601 TransformationContext transformation_context(
602 MakeUnique<FactManager>(context.get()), validator_options);
603 TransformationPropagateInstructionUp transformation(
604 15, {{{14, 40}, {19, 41}, {15, 42}}});
605 ASSERT_TRUE(
606 transformation.IsApplicable(context.get(), transformation_context));
607 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
608 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
609 kConsoleMessageConsumer));
610
611 std::string after_transformation = R"(
612 OpCapability Shader
613 %1 = OpExtInstImport "GLSL.std.450"
614 OpMemoryModel Logical GLSL450
615 OpEntryPoint Fragment %4 "main"
616 OpExecutionMode %4 OriginUpperLeft
617 OpSource ESSL 310
618 %2 = OpTypeVoid
619 %3 = OpTypeFunction %2
620 %6 = OpTypeFloat 32
621 %7 = OpTypePointer Function %6
622 %9 = OpConstant %6 3.5
623 %11 = OpConstant %6 3.4000001
624 %12 = OpTypeBool
625 %17 = OpConstant %6 4
626 %20 = OpConstant %6 45
627 %4 = OpFunction %2 None %3
628
629 %5 = OpLabel
630 %13 = OpFOrdEqual %12 %9 %11
631 OpSelectionMerge %15 None
632 OpBranchConditional %13 %14 %19
633
634 %14 = OpLabel
635 %18 = OpFMod %6 %9 %17
636 %40 = OpFMul %6 %18 %18 ; propagated from %15
637 OpBranch %15
638
639 %19 = OpLabel
640 %22 = OpFAdd %6 %11 %20
641 %41 = OpFMul %6 %22 %22 ; propagated from %15
642 OpBranch %15
643
644 %15 = OpLabel
645 %23 = OpPhi %6 %40 %14 %41 %19 %42 %15 ; propagated into %14, %19, %15
646 %21 = OpPhi %6 %18 %14 %22 %19 %24 %15
647 %24 = OpFDiv %6 %21 %23
648 %42 = OpFMul %6 %24 %24 ; propagated from %15
649 OpLoopMerge %27 %15 None
650 OpBranch %15
651
652 %27 = OpLabel
653 OpReturn
654
655 OpFunctionEnd
656 )";
657
658 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
659 }
660
TEST(TransformationPropagateInstructionUpTest,HandlesVariablePointersCapability)661 TEST(TransformationPropagateInstructionUpTest,
662 HandlesVariablePointersCapability) {
663 std::string shader = R"(
664 OpCapability Shader
665 %1 = OpExtInstImport "GLSL.std.450"
666 OpMemoryModel Logical GLSL450
667 OpEntryPoint Fragment %4 "main"
668 OpExecutionMode %4 OriginUpperLeft
669 OpSource ESSL 310
670 %2 = OpTypeVoid
671 %3 = OpTypeFunction %2
672 %6 = OpTypeFloat 32
673 %11 = OpConstant %6 23
674 %7 = OpTypePointer Function %6
675 %4 = OpFunction %2 None %3
676
677 %5 = OpLabel
678 %8 = OpVariable %7 Function
679 OpBranch %9
680
681 %9 = OpLabel
682 %10 = OpCopyObject %7 %8
683 OpStore %10 %11
684 OpReturn
685
686 OpFunctionEnd
687 )";
688
689 const auto env = SPV_ENV_UNIVERSAL_1_3;
690 const auto consumer = nullptr;
691 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
692 spvtools::ValidatorOptions validator_options;
693 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
694 kConsoleMessageConsumer));
695 TransformationContext transformation_context(
696 MakeUnique<FactManager>(context.get()), validator_options);
697 // Required capabilities haven't yet been specified.
698 TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
699 ASSERT_FALSE(
700 transformation.IsApplicable(context.get(), transformation_context));
701
702 context->AddCapability(SpvCapabilityVariablePointers);
703
704 ASSERT_TRUE(
705 transformation.IsApplicable(context.get(), transformation_context));
706 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
707 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
708 kConsoleMessageConsumer));
709
710 std::string after_transformation = R"(
711 OpCapability Shader
712 OpCapability VariablePointers
713 %1 = OpExtInstImport "GLSL.std.450"
714 OpMemoryModel Logical GLSL450
715 OpEntryPoint Fragment %4 "main"
716 OpExecutionMode %4 OriginUpperLeft
717 OpSource ESSL 310
718 %2 = OpTypeVoid
719 %3 = OpTypeFunction %2
720 %6 = OpTypeFloat 32
721 %11 = OpConstant %6 23
722 %7 = OpTypePointer Function %6
723 %4 = OpFunction %2 None %3
724
725 %5 = OpLabel
726 %8 = OpVariable %7 Function
727 %40 = OpCopyObject %7 %8 ; propagated from %9
728 OpBranch %9
729
730 %9 = OpLabel
731 %10 = OpPhi %7 %40 %5 ; propagated into %5
732 OpStore %10 %11
733 OpReturn
734
735 OpFunctionEnd
736 )";
737
738 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
739 }
740
TEST(TransformationPropagateInstructionUpTest,HandlesVariablePointersStorageBufferCapability)741 TEST(TransformationPropagateInstructionUpTest,
742 HandlesVariablePointersStorageBufferCapability) {
743 std::string shader = R"(
744 OpCapability Shader
745 %1 = OpExtInstImport "GLSL.std.450"
746 OpMemoryModel Logical GLSL450
747 OpEntryPoint Fragment %4 "main"
748 OpExecutionMode %4 OriginUpperLeft
749 OpSource ESSL 310
750 %2 = OpTypeVoid
751 %3 = OpTypeFunction %2
752 %6 = OpTypeFloat 32
753 %11 = OpConstant %6 23
754 %7 = OpTypePointer Function %6
755 %4 = OpFunction %2 None %3
756
757 %5 = OpLabel
758 %8 = OpVariable %7 Function
759 OpBranch %9
760
761 %9 = OpLabel
762 %10 = OpCopyObject %7 %8
763 OpStore %10 %11
764 OpReturn
765
766 OpFunctionEnd
767 )";
768
769 const auto env = SPV_ENV_UNIVERSAL_1_3;
770 const auto consumer = nullptr;
771 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
772 spvtools::ValidatorOptions validator_options;
773 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
774 kConsoleMessageConsumer));
775 TransformationContext transformation_context(
776 MakeUnique<FactManager>(context.get()), validator_options);
777 // Required capabilities haven't yet been specified
778 TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
779 ASSERT_FALSE(
780 transformation.IsApplicable(context.get(), transformation_context));
781
782 context->AddCapability(SpvCapabilityVariablePointersStorageBuffer);
783
784 ASSERT_TRUE(
785 transformation.IsApplicable(context.get(), transformation_context));
786 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
787 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
788 kConsoleMessageConsumer));
789
790 std::string after_transformation = R"(
791 OpCapability Shader
792 OpCapability VariablePointersStorageBuffer
793 %1 = OpExtInstImport "GLSL.std.450"
794 OpMemoryModel Logical GLSL450
795 OpEntryPoint Fragment %4 "main"
796 OpExecutionMode %4 OriginUpperLeft
797 OpSource ESSL 310
798 %2 = OpTypeVoid
799 %3 = OpTypeFunction %2
800 %6 = OpTypeFloat 32
801 %11 = OpConstant %6 23
802 %7 = OpTypePointer Function %6
803 %4 = OpFunction %2 None %3
804
805 %5 = OpLabel
806 %8 = OpVariable %7 Function
807 %40 = OpCopyObject %7 %8 ; propagated from %9
808 OpBranch %9
809
810 %9 = OpLabel
811 %10 = OpPhi %7 %40 %5 ; propagated into %5
812 OpStore %10 %11
813 OpReturn
814
815 OpFunctionEnd
816 )";
817
818 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
819 }
820
TEST(TransformationPropagateInstructionUpTest,MultipleIdenticalPredecessors)821 TEST(TransformationPropagateInstructionUpTest, MultipleIdenticalPredecessors) {
822 std::string shader = R"(
823 OpCapability Shader
824 %1 = OpExtInstImport "GLSL.std.450"
825 OpMemoryModel Logical GLSL450
826 OpEntryPoint Fragment %4 "main"
827 OpExecutionMode %4 OriginUpperLeft
828 OpSource ESSL 310
829 %2 = OpTypeVoid
830 %3 = OpTypeFunction %2
831 %6 = OpTypeFloat 32
832 %11 = OpConstant %6 23
833 %12 = OpTypeBool
834 %13 = OpConstantTrue %12
835 %4 = OpFunction %2 None %3
836
837 %5 = OpLabel
838 OpSelectionMerge %9 None
839 OpBranchConditional %13 %9 %9
840
841 %9 = OpLabel
842 %14 = OpPhi %6 %11 %5
843 %10 = OpCopyObject %6 %14
844 OpReturn
845
846 OpFunctionEnd
847 )";
848
849 const auto env = SPV_ENV_UNIVERSAL_1_3;
850 const auto consumer = nullptr;
851 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
852 spvtools::ValidatorOptions validator_options;
853 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
854 kConsoleMessageConsumer));
855 TransformationContext transformation_context(
856 MakeUnique<FactManager>(context.get()), validator_options);
857 TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
858 ASSERT_TRUE(
859 transformation.IsApplicable(context.get(), transformation_context));
860 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
861 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
862 kConsoleMessageConsumer));
863
864 std::string after_transformation = R"(
865 OpCapability Shader
866 %1 = OpExtInstImport "GLSL.std.450"
867 OpMemoryModel Logical GLSL450
868 OpEntryPoint Fragment %4 "main"
869 OpExecutionMode %4 OriginUpperLeft
870 OpSource ESSL 310
871 %2 = OpTypeVoid
872 %3 = OpTypeFunction %2
873 %6 = OpTypeFloat 32
874 %11 = OpConstant %6 23
875 %12 = OpTypeBool
876 %13 = OpConstantTrue %12
877 %4 = OpFunction %2 None %3
878
879 %5 = OpLabel
880 %40 = OpCopyObject %6 %11
881 OpSelectionMerge %9 None
882 OpBranchConditional %13 %9 %9
883
884 %9 = OpLabel
885 %10 = OpPhi %6 %40 %5
886 %14 = OpPhi %6 %11 %5
887 OpReturn
888
889 OpFunctionEnd
890 )";
891
892 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
893 }
894
TEST(TransformationPropagateInstructionUpTest,InapplicableDueToOpTypeSampledImage)895 TEST(TransformationPropagateInstructionUpTest,
896 InapplicableDueToOpTypeSampledImage) {
897 std::string shader = R"(
898 OpCapability Shader
899 %1 = OpExtInstImport "GLSL.std.450"
900 OpMemoryModel Logical GLSL450
901 OpEntryPoint Fragment %4 "main" %10
902 OpExecutionMode %4 OriginUpperLeft
903 OpSource ESSL 320
904 OpDecorate %10 RelaxedPrecision
905 OpDecorate %10 DescriptorSet 0
906 OpDecorate %10 Binding 0
907 %2 = OpTypeVoid
908 %3 = OpTypeFunction %2
909 %6 = OpTypeFloat 32
910 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
911 %8 = OpTypeSampledImage %7
912 %9 = OpTypePointer UniformConstant %8
913 %10 = OpVariable %9 UniformConstant
914 %12 = OpTypeVector %6 2
915 %13 = OpConstant %6 0
916 %14 = OpConstantComposite %12 %13 %13
917 %15 = OpTypeVector %6 4
918 %30 = OpTypeBool
919 %31 = OpConstantTrue %30
920 %4 = OpFunction %2 None %3
921 %5 = OpLabel
922 %11 = OpLoad %8 %10
923 OpSelectionMerge %20 None
924 OpBranchConditional %31 %40 %41
925 %40 = OpLabel
926 OpBranch %20
927 %41 = OpLabel
928 OpBranch %20
929 %20 = OpLabel
930 %50 = OpCopyObject %8 %11
931 %16 = OpImageSampleImplicitLod %15 %50 %14
932 OpReturn
933 OpFunctionEnd
934 )";
935
936 const auto env = SPV_ENV_UNIVERSAL_1_5;
937 const auto consumer = nullptr;
938 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
939 spvtools::ValidatorOptions validator_options;
940 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
941 kConsoleMessageConsumer));
942 TransformationContext transformation_context(
943 MakeUnique<FactManager>(context.get()), validator_options);
944
945 ASSERT_FALSE(
946 TransformationPropagateInstructionUp(20, {{{40, 100}, {41, 101}}})
947 .IsApplicable(context.get(), transformation_context));
948 }
949
950 } // namespace
951 } // namespace fuzz
952 } // namespace spvtools
953