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