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