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
21namespace spvtools {
22namespace fuzz {
23namespace {
24
25TEST(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
267TEST(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
382TEST(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
607TEST(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
849TEST(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
1004TEST(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