• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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