1 // Copyright (c) 2020 André Perez Maselco
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_inline_function.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/counter_overflow_id_source.h"
19 #include "source/fuzz/fuzzer_util.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "test/fuzz/fuzz_test_util.h"
22
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26
TEST(TransformationInlineFunctionTest,IsApplicable)27 TEST(TransformationInlineFunctionTest, IsApplicable) {
28 std::string shader = R"(
29 OpCapability Shader
30 %1 = OpExtInstImport "GLSL.std.450"
31 OpMemoryModel Logical GLSL450
32 OpEntryPoint Fragment %52 "main"
33 OpExecutionMode %52 OriginUpperLeft
34 OpName %56 "function_with_void_return"
35
36 ; Types
37 %2 = OpTypeBool
38 %3 = OpTypeFloat 32
39 %4 = OpTypeVector %3 4
40 %5 = OpTypePointer Function %4
41 %6 = OpTypeVoid
42 %7 = OpTypeFunction %6
43 %8 = OpTypeFunction %3 %5 %5
44
45 ; Constant scalars
46 %9 = OpConstant %3 1
47 %10 = OpConstant %3 2
48 %11 = OpConstant %3 3
49 %12 = OpConstant %3 4
50 %13 = OpConstant %3 5
51 %14 = OpConstant %3 6
52 %15 = OpConstant %3 7
53 %16 = OpConstant %3 8
54 %17 = OpConstantTrue %2
55
56 ; Constant vectors
57 %18 = OpConstantComposite %4 %9 %10 %11 %12
58 %19 = OpConstantComposite %4 %13 %14 %15 %16
59
60 ; function with void return
61 %20 = OpFunction %6 None %7
62 %21 = OpLabel
63 OpReturn
64 OpFunctionEnd
65
66 ; function with early return
67 %22 = OpFunction %6 None %7
68 %23 = OpLabel
69 OpSelectionMerge %26 None
70 OpBranchConditional %17 %24 %25
71 %24 = OpLabel
72 OpReturn
73 %25 = OpLabel
74 OpBranch %26
75 %26 = OpLabel
76 OpReturn
77 OpFunctionEnd
78
79 ; function containing an OpKill instruction
80 %27 = OpFunction %6 None %7
81 %28 = OpLabel
82 OpKill
83 OpFunctionEnd
84
85 ; function containing an OpUnreachable instruction
86 %29 = OpFunction %6 None %7
87 %30 = OpLabel
88 OpUnreachable
89 OpFunctionEnd
90
91 ; dot product function
92 %31 = OpFunction %3 None %8
93 %32 = OpFunctionParameter %5
94 %33 = OpFunctionParameter %5
95 %34 = OpLabel
96 %35 = OpLoad %4 %32
97 %36 = OpLoad %4 %33
98 %37 = OpCompositeExtract %3 %35 0
99 %38 = OpCompositeExtract %3 %36 0
100 %39 = OpFMul %3 %37 %38
101 %40 = OpCompositeExtract %3 %35 1
102 %41 = OpCompositeExtract %3 %36 1
103 %42 = OpFMul %3 %40 %41
104 %43 = OpCompositeExtract %3 %35 2
105 %44 = OpCompositeExtract %3 %36 2
106 %45 = OpFMul %3 %43 %44
107 %46 = OpCompositeExtract %3 %35 3
108 %47 = OpCompositeExtract %3 %36 3
109 %48 = OpFMul %3 %46 %47
110 %49 = OpFAdd %3 %39 %42
111 %50 = OpFAdd %3 %45 %49
112 %51 = OpFAdd %3 %48 %50
113 OpReturnValue %51
114 OpFunctionEnd
115
116 ; main function
117 %52 = OpFunction %6 None %7
118 %53 = OpLabel
119 %54 = OpVariable %5 Function
120 %55 = OpVariable %5 Function
121 %56 = OpFunctionCall %6 %20 ; function with void return
122 OpBranch %57
123 %57 = OpLabel
124 %59 = OpFunctionCall %6 %22 ; function with early return
125 OpBranch %60
126 %60 = OpLabel
127 %61 = OpFunctionCall %6 %27 ; function containing OpKill
128 OpBranch %62
129 %62 = OpLabel
130 %63 = OpFunctionCall %6 %29 ; function containing OpUnreachable
131 OpBranch %64
132 %64 = OpLabel
133 OpStore %54 %18
134 OpStore %55 %19
135 %65 = OpFunctionCall %3 %31 %54 %55 ; dot product function
136 OpBranch %66
137 %66 = OpLabel
138 OpReturn
139 OpFunctionEnd
140 )";
141
142 const auto env = SPV_ENV_UNIVERSAL_1_5;
143 const auto consumer = nullptr;
144 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
145 spvtools::ValidatorOptions validator_options;
146 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
147 kConsoleMessageConsumer));
148 TransformationContext transformation_context(
149 MakeUnique<FactManager>(context.get()), validator_options);
150 // Tests undefined OpFunctionCall instruction.
151 auto transformation = TransformationInlineFunction(67, {});
152 ASSERT_FALSE(
153 transformation.IsApplicable(context.get(), transformation_context));
154
155 // Tests false OpFunctionCall instruction.
156 transformation = TransformationInlineFunction(42, {});
157 ASSERT_FALSE(
158 transformation.IsApplicable(context.get(), transformation_context));
159
160 // Tests use of called function with void return.
161 transformation = TransformationInlineFunction(56, {});
162 ASSERT_FALSE(
163 transformation.IsApplicable(context.get(), transformation_context));
164
165 // Tests called function having an early return.
166 transformation =
167 TransformationInlineFunction(59, {{24, 67}, {25, 68}, {26, 69}});
168 ASSERT_FALSE(
169 transformation.IsApplicable(context.get(), transformation_context));
170
171 // Tests called function containing an OpKill instruction.
172 transformation = TransformationInlineFunction(61, {});
173 ASSERT_FALSE(
174 transformation.IsApplicable(context.get(), transformation_context));
175
176 // Tests called function containing an OpUnreachable instruction.
177 transformation = TransformationInlineFunction(63, {});
178 ASSERT_FALSE(
179 transformation.IsApplicable(context.get(), transformation_context));
180
181 // Tests applicable transformation.
182 transformation = TransformationInlineFunction(65, {{35, 67},
183 {36, 68},
184 {37, 69},
185 {38, 70},
186 {39, 71},
187 {40, 72},
188 {41, 73},
189 {42, 74},
190 {43, 75},
191 {44, 76},
192 {45, 77},
193 {46, 78},
194 {47, 79},
195 {48, 80},
196 {49, 81},
197 {50, 82},
198 {51, 83}});
199 ASSERT_TRUE(
200 transformation.IsApplicable(context.get(), transformation_context));
201 }
202
TEST(TransformationInlineFunctionTest,Apply)203 TEST(TransformationInlineFunctionTest, Apply) {
204 std::string reference_shader = R"(
205 OpCapability Shader
206 %1 = OpExtInstImport "GLSL.std.450"
207 OpMemoryModel Logical GLSL450
208 OpEntryPoint Vertex %39 "main"
209
210 ; Types
211 %2 = OpTypeFloat 32
212 %3 = OpTypeVector %2 4
213 %4 = OpTypePointer Function %3
214 %5 = OpTypeVoid
215 %6 = OpTypeFunction %5
216 %7 = OpTypeFunction %2 %4 %4
217
218 ; Constant scalars
219 %8 = OpConstant %2 1
220 %9 = OpConstant %2 2
221 %10 = OpConstant %2 3
222 %11 = OpConstant %2 4
223 %12 = OpConstant %2 5
224 %13 = OpConstant %2 6
225 %14 = OpConstant %2 7
226 %15 = OpConstant %2 8
227
228 ; Constant vectors
229 %16 = OpConstantComposite %3 %8 %9 %10 %11
230 %17 = OpConstantComposite %3 %12 %13 %14 %15
231
232 ; dot product function
233 %18 = OpFunction %2 None %7
234 %19 = OpFunctionParameter %4
235 %20 = OpFunctionParameter %4
236 %21 = OpLabel
237 %22 = OpLoad %3 %19
238 %23 = OpLoad %3 %20
239 %24 = OpCompositeExtract %2 %22 0
240 %25 = OpCompositeExtract %2 %23 0
241 %26 = OpFMul %2 %24 %25
242 %27 = OpCompositeExtract %2 %22 1
243 %28 = OpCompositeExtract %2 %23 1
244 %29 = OpFMul %2 %27 %28
245 %30 = OpCompositeExtract %2 %22 2
246 %31 = OpCompositeExtract %2 %23 2
247 %32 = OpFMul %2 %30 %31
248 %33 = OpCompositeExtract %2 %22 3
249 %34 = OpCompositeExtract %2 %23 3
250 %35 = OpFMul %2 %33 %34
251 %36 = OpFAdd %2 %26 %29
252 %37 = OpFAdd %2 %32 %36
253 %38 = OpFAdd %2 %35 %37
254 OpReturnValue %38
255 OpFunctionEnd
256
257 ; main function
258 %39 = OpFunction %5 None %6
259 %40 = OpLabel
260 %41 = OpVariable %4 Function
261 %42 = OpVariable %4 Function
262 OpStore %41 %16
263 OpStore %42 %17
264 %43 = OpFunctionCall %2 %18 %41 %42 ; dot product function call
265 OpBranch %44
266 %44 = OpLabel
267 OpReturn
268 OpFunctionEnd
269 )";
270
271 const auto env = SPV_ENV_UNIVERSAL_1_5;
272 const auto consumer = nullptr;
273 const auto context =
274 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
275 spvtools::ValidatorOptions validator_options;
276 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
277 kConsoleMessageConsumer));
278 TransformationContext transformation_context(
279 MakeUnique<FactManager>(context.get()), validator_options);
280 auto transformation = TransformationInlineFunction(43, {{22, 45},
281 {23, 46},
282 {24, 47},
283 {25, 48},
284 {26, 49},
285 {27, 50},
286 {28, 51},
287 {29, 52},
288 {30, 53},
289 {31, 54},
290 {32, 55},
291 {33, 56},
292 {34, 57},
293 {35, 58},
294 {36, 59},
295 {37, 60},
296 {38, 61}});
297 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
298
299 std::string variant_shader = R"(
300 OpCapability Shader
301 %1 = OpExtInstImport "GLSL.std.450"
302 OpMemoryModel Logical GLSL450
303 OpEntryPoint Vertex %39 "main"
304
305 ; Types
306 %2 = OpTypeFloat 32
307 %3 = OpTypeVector %2 4
308 %4 = OpTypePointer Function %3
309 %5 = OpTypeVoid
310 %6 = OpTypeFunction %5
311 %7 = OpTypeFunction %2 %4 %4
312
313 ; Constant scalars
314 %8 = OpConstant %2 1
315 %9 = OpConstant %2 2
316 %10 = OpConstant %2 3
317 %11 = OpConstant %2 4
318 %12 = OpConstant %2 5
319 %13 = OpConstant %2 6
320 %14 = OpConstant %2 7
321 %15 = OpConstant %2 8
322
323 ; Constant vectors
324 %16 = OpConstantComposite %3 %8 %9 %10 %11
325 %17 = OpConstantComposite %3 %12 %13 %14 %15
326
327 ; dot product function
328 %18 = OpFunction %2 None %7
329 %19 = OpFunctionParameter %4
330 %20 = OpFunctionParameter %4
331 %21 = OpLabel
332 %22 = OpLoad %3 %19
333 %23 = OpLoad %3 %20
334 %24 = OpCompositeExtract %2 %22 0
335 %25 = OpCompositeExtract %2 %23 0
336 %26 = OpFMul %2 %24 %25
337 %27 = OpCompositeExtract %2 %22 1
338 %28 = OpCompositeExtract %2 %23 1
339 %29 = OpFMul %2 %27 %28
340 %30 = OpCompositeExtract %2 %22 2
341 %31 = OpCompositeExtract %2 %23 2
342 %32 = OpFMul %2 %30 %31
343 %33 = OpCompositeExtract %2 %22 3
344 %34 = OpCompositeExtract %2 %23 3
345 %35 = OpFMul %2 %33 %34
346 %36 = OpFAdd %2 %26 %29
347 %37 = OpFAdd %2 %32 %36
348 %38 = OpFAdd %2 %35 %37
349 OpReturnValue %38
350 OpFunctionEnd
351
352 ; main function
353 %39 = OpFunction %5 None %6
354 %40 = OpLabel
355 %41 = OpVariable %4 Function
356 %42 = OpVariable %4 Function
357 OpStore %41 %16
358 OpStore %42 %17
359 %45 = OpLoad %3 %41
360 %46 = OpLoad %3 %42
361 %47 = OpCompositeExtract %2 %45 0
362 %48 = OpCompositeExtract %2 %46 0
363 %49 = OpFMul %2 %47 %48
364 %50 = OpCompositeExtract %2 %45 1
365 %51 = OpCompositeExtract %2 %46 1
366 %52 = OpFMul %2 %50 %51
367 %53 = OpCompositeExtract %2 %45 2
368 %54 = OpCompositeExtract %2 %46 2
369 %55 = OpFMul %2 %53 %54
370 %56 = OpCompositeExtract %2 %45 3
371 %57 = OpCompositeExtract %2 %46 3
372 %58 = OpFMul %2 %56 %57
373 %59 = OpFAdd %2 %49 %52
374 %60 = OpFAdd %2 %55 %59
375 %61 = OpFAdd %2 %58 %60
376 %43 = OpCopyObject %2 %61
377 OpBranch %44
378 %44 = OpLabel
379 OpReturn
380 OpFunctionEnd
381 )";
382
383 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
384 kConsoleMessageConsumer));
385 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
386 }
387
TEST(TransformationInlineFunctionTest,ApplyToMultipleFunctions)388 TEST(TransformationInlineFunctionTest, ApplyToMultipleFunctions) {
389 std::string reference_shader = R"(
390 OpCapability Shader
391 %1 = OpExtInstImport "GLSL.std.450"
392 OpMemoryModel Logical GLSL450
393 OpEntryPoint Vertex %15 "main"
394
395 ; Types
396 %2 = OpTypeInt 32 1
397 %3 = OpTypeBool
398 %4 = OpTypePointer Private %2
399 %5 = OpTypePointer Function %2
400 %6 = OpTypeVoid
401 %7 = OpTypeFunction %6
402 %8 = OpTypeFunction %2 %5
403 %9 = OpTypeFunction %2 %2
404
405 ; Constants
406 %10 = OpConstant %2 0
407 %11 = OpConstant %2 1
408 %12 = OpConstant %2 2
409 %13 = OpConstant %2 3
410
411 ; Global variable
412 %14 = OpVariable %4 Private
413
414 ; main function
415 %15 = OpFunction %6 None %7
416 %16 = OpLabel
417 %17 = OpVariable %5 Function
418 %18 = OpVariable %5 Function
419 %19 = OpVariable %5 Function
420 OpStore %17 %13
421 %20 = OpLoad %2 %17
422 OpStore %18 %20
423 %21 = OpFunctionCall %2 %36 %18
424 OpBranch %22
425 %22 = OpLabel
426 %23 = OpFunctionCall %2 %36 %18
427 OpStore %17 %21
428 %24 = OpLoad %2 %17
429 %25 = OpFunctionCall %2 %54 %24
430 OpBranch %26
431 %26 = OpLabel
432 %27 = OpFunctionCall %2 %54 %24
433 %28 = OpLoad %2 %17
434 %29 = OpIAdd %2 %28 %25
435 OpStore %17 %29
436 %30 = OpFunctionCall %6 %67
437 OpBranch %31
438 %31 = OpLabel
439 %32 = OpFunctionCall %6 %67
440 %33 = OpLoad %2 %14
441 %34 = OpLoad %2 %17
442 %35 = OpIAdd %2 %34 %33
443 OpStore %17 %35
444 OpReturn
445 OpFunctionEnd
446
447 ; Function %36
448 %36 = OpFunction %2 None %8
449 %37 = OpFunctionParameter %5
450 %38 = OpLabel
451 %39 = OpVariable %5 Function
452 %40 = OpVariable %5 Function
453 OpStore %39 %10
454 OpBranch %41
455 %41 = OpLabel
456 OpLoopMerge %52 %49 None
457 OpBranch %42
458 %42 = OpLabel
459 %43 = OpLoad %2 %39
460 %44 = OpLoad %2 %37
461 %45 = OpSLessThan %3 %43 %44
462 OpBranchConditional %45 %46 %52
463 %46 = OpLabel
464 %47 = OpLoad %2 %40
465 %48 = OpIAdd %2 %47 %11
466 OpStore %40 %48
467 OpBranch %49
468 %49 = OpLabel
469 %50 = OpLoad %2 %39
470 %51 = OpIAdd %2 %50 %12
471 OpStore %39 %51
472 OpBranch %41
473 %52 = OpLabel
474 %53 = OpLoad %2 %40
475 OpReturnValue %53
476 OpFunctionEnd
477
478 ; Function %54
479 %54 = OpFunction %2 None %9
480 %55 = OpFunctionParameter %2
481 %56 = OpLabel
482 %57 = OpVariable %5 Function
483 OpStore %57 %10
484 %58 = OpSGreaterThan %3 %55 %10
485 OpSelectionMerge %62 None
486 OpBranchConditional %58 %64 %59
487 %59 = OpLabel
488 %60 = OpLoad %2 %57
489 %61 = OpISub %2 %60 %12
490 OpStore %57 %61
491 OpBranch %62
492 %62 = OpLabel
493 %63 = OpLoad %2 %57
494 OpReturnValue %63
495 %64 = OpLabel
496 %65 = OpLoad %2 %57
497 %66 = OpIAdd %2 %65 %11
498 OpStore %57 %66
499 OpBranch %62
500 OpFunctionEnd
501
502 ; Function %67
503 %67 = OpFunction %6 None %7
504 %68 = OpLabel
505 OpStore %14 %12
506 OpReturn
507 OpFunctionEnd
508 )";
509
510 const auto env = SPV_ENV_UNIVERSAL_1_3;
511 const auto consumer = nullptr;
512 const auto context =
513 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
514 spvtools::ValidatorOptions validator_options;
515 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
516 kConsoleMessageConsumer));
517 TransformationContext transformation_context(
518 MakeUnique<FactManager>(context.get()), validator_options);
519 auto transformation = TransformationInlineFunction(30, {});
520 ASSERT_TRUE(
521 transformation.IsApplicable(context.get(), transformation_context));
522 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
523
524 // Tests a parameter included in the id map.
525 transformation = TransformationInlineFunction(25, {{55, 69},
526 {56, 70},
527 {57, 71},
528 {58, 72},
529 {59, 73},
530 {60, 74},
531 {61, 75},
532 {62, 76},
533 {63, 77},
534 {64, 78},
535 {65, 79},
536 {66, 80}});
537 ASSERT_FALSE(
538 transformation.IsApplicable(context.get(), transformation_context));
539
540 #ifndef NDEBUG
541 // Tests the id of the returned value not included in the id map.
542 transformation = TransformationInlineFunction(25, {{56, 69},
543 {57, 70},
544 {58, 71},
545 {59, 72},
546 {60, 73},
547 {61, 74},
548 {62, 75},
549 {64, 76},
550 {65, 77},
551 {66, 78}});
552 ASSERT_DEATH(
553 transformation.IsApplicable(context.get(), transformation_context),
554 "Bad attempt to query whether overflow ids are available.");
555 #endif
556
557 transformation = TransformationInlineFunction(25, {{57, 69},
558 {58, 70},
559 {59, 71},
560 {60, 72},
561 {61, 73},
562 {62, 74},
563 {63, 75},
564 {64, 76},
565 {65, 77},
566 {66, 78}});
567 ASSERT_TRUE(
568 transformation.IsApplicable(context.get(), transformation_context));
569 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
570
571 transformation = TransformationInlineFunction(21, {{39, 79},
572 {40, 80},
573 {41, 81},
574 {42, 82},
575 {43, 83},
576 {44, 84},
577 {45, 85},
578 {46, 86},
579 {47, 87},
580 {48, 88},
581 {49, 89},
582 {50, 90},
583 {51, 91},
584 {52, 92},
585 {53, 93}});
586 ASSERT_TRUE(
587 transformation.IsApplicable(context.get(), transformation_context));
588 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
589
590 std::string variant_shader = R"(
591 OpCapability Shader
592 %1 = OpExtInstImport "GLSL.std.450"
593 OpMemoryModel Logical GLSL450
594 OpEntryPoint Vertex %15 "main"
595
596 ; Types
597 %2 = OpTypeInt 32 1
598 %3 = OpTypeBool
599 %4 = OpTypePointer Private %2
600 %5 = OpTypePointer Function %2
601 %6 = OpTypeVoid
602 %7 = OpTypeFunction %6
603 %8 = OpTypeFunction %2 %5
604 %9 = OpTypeFunction %2 %2
605
606 ; Constants
607 %10 = OpConstant %2 0
608 %11 = OpConstant %2 1
609 %12 = OpConstant %2 2
610 %13 = OpConstant %2 3
611
612 ; Global variable
613 %14 = OpVariable %4 Private
614
615 ; main function
616 %15 = OpFunction %6 None %7
617 %16 = OpLabel
618 %80 = OpVariable %5 Function
619 %79 = OpVariable %5 Function
620 %69 = OpVariable %5 Function
621 %17 = OpVariable %5 Function
622 %18 = OpVariable %5 Function
623 %19 = OpVariable %5 Function
624 OpStore %17 %13
625 %20 = OpLoad %2 %17
626 OpStore %18 %20
627 OpStore %79 %10
628 OpBranch %81
629 %81 = OpLabel
630 OpLoopMerge %92 %89 None
631 OpBranch %82
632 %82 = OpLabel
633 %83 = OpLoad %2 %79
634 %84 = OpLoad %2 %18
635 %85 = OpSLessThan %3 %83 %84
636 OpBranchConditional %85 %86 %92
637 %86 = OpLabel
638 %87 = OpLoad %2 %80
639 %88 = OpIAdd %2 %87 %11
640 OpStore %80 %88
641 OpBranch %89
642 %89 = OpLabel
643 %90 = OpLoad %2 %79
644 %91 = OpIAdd %2 %90 %12
645 OpStore %79 %91
646 OpBranch %81
647 %92 = OpLabel
648 %93 = OpLoad %2 %80
649 %21 = OpCopyObject %2 %93
650 OpBranch %22
651 %22 = OpLabel
652 %23 = OpFunctionCall %2 %36 %18
653 OpStore %17 %21
654 %24 = OpLoad %2 %17
655 OpStore %69 %10
656 %70 = OpSGreaterThan %3 %24 %10
657 OpSelectionMerge %74 None
658 OpBranchConditional %70 %76 %71
659 %71 = OpLabel
660 %72 = OpLoad %2 %69
661 %73 = OpISub %2 %72 %12
662 OpStore %69 %73
663 OpBranch %74
664 %74 = OpLabel
665 %75 = OpLoad %2 %69
666 %25 = OpCopyObject %2 %75
667 OpBranch %26
668 %76 = OpLabel
669 %77 = OpLoad %2 %69
670 %78 = OpIAdd %2 %77 %11
671 OpStore %69 %78
672 OpBranch %74
673 %26 = OpLabel
674 %27 = OpFunctionCall %2 %54 %24
675 %28 = OpLoad %2 %17
676 %29 = OpIAdd %2 %28 %25
677 OpStore %17 %29
678 OpStore %14 %12
679 OpBranch %31
680 %31 = OpLabel
681 %32 = OpFunctionCall %6 %67
682 %33 = OpLoad %2 %14
683 %34 = OpLoad %2 %17
684 %35 = OpIAdd %2 %34 %33
685 OpStore %17 %35
686 OpReturn
687 OpFunctionEnd
688
689 ; Function %36
690 %36 = OpFunction %2 None %8
691 %37 = OpFunctionParameter %5
692 %38 = OpLabel
693 %39 = OpVariable %5 Function
694 %40 = OpVariable %5 Function
695 OpStore %39 %10
696 OpBranch %41
697 %41 = OpLabel
698 OpLoopMerge %52 %49 None
699 OpBranch %42
700 %42 = OpLabel
701 %43 = OpLoad %2 %39
702 %44 = OpLoad %2 %37
703 %45 = OpSLessThan %3 %43 %44
704 OpBranchConditional %45 %46 %52
705 %46 = OpLabel
706 %47 = OpLoad %2 %40
707 %48 = OpIAdd %2 %47 %11
708 OpStore %40 %48
709 OpBranch %49
710 %49 = OpLabel
711 %50 = OpLoad %2 %39
712 %51 = OpIAdd %2 %50 %12
713 OpStore %39 %51
714 OpBranch %41
715 %52 = OpLabel
716 %53 = OpLoad %2 %40
717 OpReturnValue %53
718 OpFunctionEnd
719
720 ; Function %54
721 %54 = OpFunction %2 None %9
722 %55 = OpFunctionParameter %2
723 %56 = OpLabel
724 %57 = OpVariable %5 Function
725 OpStore %57 %10
726 %58 = OpSGreaterThan %3 %55 %10
727 OpSelectionMerge %62 None
728 OpBranchConditional %58 %64 %59
729 %59 = OpLabel
730 %60 = OpLoad %2 %57
731 %61 = OpISub %2 %60 %12
732 OpStore %57 %61
733 OpBranch %62
734 %62 = OpLabel
735 %63 = OpLoad %2 %57
736 OpReturnValue %63
737 %64 = OpLabel
738 %65 = OpLoad %2 %57
739 %66 = OpIAdd %2 %65 %11
740 OpStore %57 %66
741 OpBranch %62
742 OpFunctionEnd
743
744 ; Function %67
745 %67 = OpFunction %6 None %7
746 %68 = OpLabel
747 OpStore %14 %12
748 OpReturn
749 OpFunctionEnd
750 )";
751
752 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
753 kConsoleMessageConsumer));
754 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
755 }
756
TEST(TransformationInlineFunctionTest,HandlesOpPhisInTheSecondBlock)757 TEST(TransformationInlineFunctionTest, HandlesOpPhisInTheSecondBlock) {
758 std::string shader = R"(
759 OpCapability Shader
760 %1 = OpExtInstImport "GLSL.std.450"
761 OpMemoryModel Logical GLSL450
762 OpEntryPoint Fragment %4 "main"
763 OpExecutionMode %4 OriginUpperLeft
764 %2 = OpTypeVoid
765 %3 = OpTypeFunction %2
766 %10 = OpTypeInt 32 0
767 %11 = OpUndef %10
768 %4 = OpFunction %2 None %3
769 %5 = OpLabel
770 %6 = OpFunctionCall %2 %7
771 OpBranch %14
772 %14 = OpLabel
773 OpReturn
774 OpFunctionEnd
775 %7 = OpFunction %2 None %3
776 %8 = OpLabel
777 OpBranch %13
778 %13 = OpLabel
779 %12 = OpPhi %10 %11 %8
780 OpReturn
781 OpFunctionEnd
782 )";
783
784 const auto env = SPV_ENV_UNIVERSAL_1_3;
785 const auto consumer = nullptr;
786 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
787 spvtools::ValidatorOptions validator_options;
788 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
789 kConsoleMessageConsumer));
790 TransformationContext transformation_context(
791 MakeUnique<FactManager>(context.get()), validator_options);
792 TransformationInlineFunction transformation(6,
793 {{{8, 20}, {13, 21}, {12, 22}}});
794 ASSERT_TRUE(
795 transformation.IsApplicable(context.get(), transformation_context));
796 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
797 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
798 kConsoleMessageConsumer));
799
800 std::string after_transformation = R"(
801 OpCapability Shader
802 %1 = OpExtInstImport "GLSL.std.450"
803 OpMemoryModel Logical GLSL450
804 OpEntryPoint Fragment %4 "main"
805 OpExecutionMode %4 OriginUpperLeft
806 %2 = OpTypeVoid
807 %3 = OpTypeFunction %2
808 %10 = OpTypeInt 32 0
809 %11 = OpUndef %10
810 %4 = OpFunction %2 None %3
811 %5 = OpLabel
812 OpBranch %21
813 %21 = OpLabel
814 %22 = OpPhi %10 %11 %5
815 OpBranch %14
816 %14 = OpLabel
817 OpReturn
818 OpFunctionEnd
819 %7 = OpFunction %2 None %3
820 %8 = OpLabel
821 OpBranch %13
822 %13 = OpLabel
823 %12 = OpPhi %10 %11 %8
824 OpReturn
825 OpFunctionEnd
826 )";
827
828 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
829 }
830
TEST(TransformationInlineFunctionTest,OverflowIds)831 TEST(TransformationInlineFunctionTest, OverflowIds) {
832 std::string reference_shader = R"(
833 OpCapability Shader
834 %1 = OpExtInstImport "GLSL.std.450"
835 OpMemoryModel Logical GLSL450
836 OpEntryPoint Vertex %39 "main"
837
838 ; Types
839 %2 = OpTypeFloat 32
840 %3 = OpTypeVector %2 4
841 %4 = OpTypePointer Function %3
842 %5 = OpTypeVoid
843 %6 = OpTypeFunction %5
844 %7 = OpTypeFunction %2 %4 %4
845
846 ; Constant scalars
847 %8 = OpConstant %2 1
848 %9 = OpConstant %2 2
849 %10 = OpConstant %2 3
850 %11 = OpConstant %2 4
851 %12 = OpConstant %2 5
852 %13 = OpConstant %2 6
853 %14 = OpConstant %2 7
854 %15 = OpConstant %2 8
855
856 ; Constant vectors
857 %16 = OpConstantComposite %3 %8 %9 %10 %11
858 %17 = OpConstantComposite %3 %12 %13 %14 %15
859
860 ; dot product function
861 %18 = OpFunction %2 None %7
862 %19 = OpFunctionParameter %4
863 %20 = OpFunctionParameter %4
864 %21 = OpLabel
865 %22 = OpLoad %3 %19
866 %23 = OpLoad %3 %20
867 %24 = OpCompositeExtract %2 %22 0
868 %25 = OpCompositeExtract %2 %23 0
869 %26 = OpFMul %2 %24 %25
870 %27 = OpCompositeExtract %2 %22 1
871 %28 = OpCompositeExtract %2 %23 1
872 %29 = OpFMul %2 %27 %28
873 OpBranch %100
874 %100 = OpLabel
875 %30 = OpCompositeExtract %2 %22 2
876 %31 = OpCompositeExtract %2 %23 2
877 %32 = OpFMul %2 %30 %31
878 %33 = OpCompositeExtract %2 %22 3
879 %34 = OpCompositeExtract %2 %23 3
880 %35 = OpFMul %2 %33 %34
881 %36 = OpFAdd %2 %26 %29
882 %37 = OpFAdd %2 %32 %36
883 %38 = OpFAdd %2 %35 %37
884 OpReturnValue %38
885 OpFunctionEnd
886
887 ; main function
888 %39 = OpFunction %5 None %6
889 %40 = OpLabel
890 %41 = OpVariable %4 Function
891 %42 = OpVariable %4 Function
892 OpStore %41 %16
893 OpStore %42 %17
894 %43 = OpFunctionCall %2 %18 %41 %42 ; dot product function call
895 OpBranch %44
896 %44 = OpLabel
897 OpReturn
898 OpFunctionEnd
899 )";
900
901 const auto env = SPV_ENV_UNIVERSAL_1_5;
902 const auto consumer = nullptr;
903 const auto context =
904 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
905 spvtools::ValidatorOptions validator_options;
906 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
907 kConsoleMessageConsumer));
908 auto overflow_ids_unique_ptr = MakeUnique<CounterOverflowIdSource>(1000);
909 auto overflow_ids_ptr = overflow_ids_unique_ptr.get();
910 TransformationContext transformation_context(
911 MakeUnique<FactManager>(context.get()), validator_options,
912 std::move(overflow_ids_unique_ptr));
913 auto transformation = TransformationInlineFunction(43, {{22, 45},
914 {23, 46},
915 {24, 47},
916 {25, 48},
917 {26, 49},
918 {27, 50},
919 {28, 51},
920 {29, 52}});
921
922 // The following ids are left un-mapped; overflow ids will be required for
923 // them: 30, 31, 32, 33, 34, 35, 36, 37, 38, 100
924
925 ASSERT_TRUE(
926 transformation.IsApplicable(context.get(), transformation_context));
927
928 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context,
929 overflow_ids_ptr->GetIssuedOverflowIds());
930
931 std::string variant_shader = R"(
932 OpCapability Shader
933 %1 = OpExtInstImport "GLSL.std.450"
934 OpMemoryModel Logical GLSL450
935 OpEntryPoint Vertex %39 "main"
936
937 ; Types
938 %2 = OpTypeFloat 32
939 %3 = OpTypeVector %2 4
940 %4 = OpTypePointer Function %3
941 %5 = OpTypeVoid
942 %6 = OpTypeFunction %5
943 %7 = OpTypeFunction %2 %4 %4
944
945 ; Constant scalars
946 %8 = OpConstant %2 1
947 %9 = OpConstant %2 2
948 %10 = OpConstant %2 3
949 %11 = OpConstant %2 4
950 %12 = OpConstant %2 5
951 %13 = OpConstant %2 6
952 %14 = OpConstant %2 7
953 %15 = OpConstant %2 8
954
955 ; Constant vectors
956 %16 = OpConstantComposite %3 %8 %9 %10 %11
957 %17 = OpConstantComposite %3 %12 %13 %14 %15
958
959 ; dot product function
960 %18 = OpFunction %2 None %7
961 %19 = OpFunctionParameter %4
962 %20 = OpFunctionParameter %4
963 %21 = OpLabel
964 %22 = OpLoad %3 %19
965 %23 = OpLoad %3 %20
966 %24 = OpCompositeExtract %2 %22 0
967 %25 = OpCompositeExtract %2 %23 0
968 %26 = OpFMul %2 %24 %25
969 %27 = OpCompositeExtract %2 %22 1
970 %28 = OpCompositeExtract %2 %23 1
971 %29 = OpFMul %2 %27 %28
972 OpBranch %100
973 %100 = OpLabel
974 %30 = OpCompositeExtract %2 %22 2
975 %31 = OpCompositeExtract %2 %23 2
976 %32 = OpFMul %2 %30 %31
977 %33 = OpCompositeExtract %2 %22 3
978 %34 = OpCompositeExtract %2 %23 3
979 %35 = OpFMul %2 %33 %34
980 %36 = OpFAdd %2 %26 %29
981 %37 = OpFAdd %2 %32 %36
982 %38 = OpFAdd %2 %35 %37
983 OpReturnValue %38
984 OpFunctionEnd
985
986 ; main function
987 %39 = OpFunction %5 None %6
988 %40 = OpLabel
989 %41 = OpVariable %4 Function
990 %42 = OpVariable %4 Function
991 OpStore %41 %16
992 OpStore %42 %17
993 %45 = OpLoad %3 %41
994 %46 = OpLoad %3 %42
995 %47 = OpCompositeExtract %2 %45 0
996 %48 = OpCompositeExtract %2 %46 0
997 %49 = OpFMul %2 %47 %48
998 %50 = OpCompositeExtract %2 %45 1
999 %51 = OpCompositeExtract %2 %46 1
1000 %52 = OpFMul %2 %50 %51
1001 OpBranch %1000
1002 %1000 = OpLabel
1003 %1001 = OpCompositeExtract %2 %45 2
1004 %1002 = OpCompositeExtract %2 %46 2
1005 %1003 = OpFMul %2 %1001 %1002
1006 %1004 = OpCompositeExtract %2 %45 3
1007 %1005 = OpCompositeExtract %2 %46 3
1008 %1006 = OpFMul %2 %1004 %1005
1009 %1007 = OpFAdd %2 %49 %52
1010 %1008 = OpFAdd %2 %1003 %1007
1011 %1009 = OpFAdd %2 %1006 %1008
1012 %43 = OpCopyObject %2 %1009
1013 OpBranch %44
1014 %44 = OpLabel
1015 OpReturn
1016 OpFunctionEnd
1017 )";
1018
1019 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1020 kConsoleMessageConsumer));
1021 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
1022 }
1023
TEST(TransformationInlineFunctionTest,OpPhiInBlockFollowingCall)1024 TEST(TransformationInlineFunctionTest, OpPhiInBlockFollowingCall) {
1025 // This test checks that if the block after the inlined function call has an
1026 // OpPhi instruction and the called function contains multiple blocks then the
1027 // OpPhi instruction gets updated to refer to the return block of the inlined
1028 // function, since the block containing the call will no longer be a
1029 // predecessor.
1030
1031 std::string reference_shader = R"(
1032 OpCapability Shader
1033 %1 = OpExtInstImport "GLSL.std.450"
1034 OpMemoryModel Logical GLSL450
1035 OpEntryPoint Fragment %4 "main"
1036 OpExecutionMode %4 OriginUpperLeft
1037 OpSource ESSL 320
1038 %2 = OpTypeVoid
1039 %3 = OpTypeFunction %2
1040 %13 = OpTypeBool
1041 %14 = OpConstantTrue %13
1042 %4 = OpFunction %2 None %3
1043 %5 = OpLabel
1044 OpBranch %10
1045 %10 = OpLabel
1046 %8 = OpFunctionCall %2 %6
1047 OpBranch %11
1048 %11 = OpLabel
1049 %12 = OpPhi %13 %14 %10
1050 OpReturn
1051 OpFunctionEnd
1052 %6 = OpFunction %2 None %3
1053 %7 = OpLabel
1054 OpBranch %20
1055 %20 = OpLabel
1056 OpReturn
1057 OpFunctionEnd
1058 )";
1059
1060 const auto env = SPV_ENV_UNIVERSAL_1_5;
1061 const auto consumer = nullptr;
1062 const auto context =
1063 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
1064 spvtools::ValidatorOptions validator_options;
1065 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1066 kConsoleMessageConsumer));
1067 TransformationContext transformation_context(
1068 MakeUnique<FactManager>(context.get()), validator_options);
1069 auto transformation = TransformationInlineFunction(8, {{7, 100}, {20, 101}});
1070
1071 ASSERT_TRUE(
1072 transformation.IsApplicable(context.get(), transformation_context));
1073
1074 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1075
1076 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1077 kConsoleMessageConsumer));
1078
1079 std::string variant_shader = R"(
1080 OpCapability Shader
1081 %1 = OpExtInstImport "GLSL.std.450"
1082 OpMemoryModel Logical GLSL450
1083 OpEntryPoint Fragment %4 "main"
1084 OpExecutionMode %4 OriginUpperLeft
1085 OpSource ESSL 320
1086 %2 = OpTypeVoid
1087 %3 = OpTypeFunction %2
1088 %13 = OpTypeBool
1089 %14 = OpConstantTrue %13
1090 %4 = OpFunction %2 None %3
1091 %5 = OpLabel
1092 OpBranch %10
1093 %10 = OpLabel
1094 OpBranch %101
1095 %101 = OpLabel
1096 OpBranch %11
1097 %11 = OpLabel
1098 %12 = OpPhi %13 %14 %101
1099 OpReturn
1100 OpFunctionEnd
1101 %6 = OpFunction %2 None %3
1102 %7 = OpLabel
1103 OpBranch %20
1104 %20 = OpLabel
1105 OpReturn
1106 OpFunctionEnd
1107 )";
1108
1109 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1110 kConsoleMessageConsumer));
1111 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
1112 }
1113
1114 } // namespace
1115 } // namespace fuzz
1116 } // namespace spvtools
1117