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