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