1 // Copyright (c) 2019 Google LLC
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/fuzzer_pass_donate_modules.h"
16
17 #include <algorithm>
18
19 #include "gtest/gtest.h"
20 #include "source/fuzz/pseudo_random_generator.h"
21 #include "test/fuzz/fuzz_test_util.h"
22
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26
TEST(FuzzerPassDonateModulesTest,BasicDonation)27 TEST(FuzzerPassDonateModulesTest, BasicDonation) {
28 std::string recipient_shader = R"(
29 OpCapability Shader
30 %1 = OpExtInstImport "GLSL.std.450"
31 OpMemoryModel Logical GLSL450
32 OpEntryPoint Fragment %4 "main"
33 OpExecutionMode %4 OriginUpperLeft
34 OpSource ESSL 310
35 OpName %4 "main"
36 OpName %10 "m"
37 OpName %16 "v"
38 OpDecorate %16 RelaxedPrecision
39 OpDecorate %20 RelaxedPrecision
40 %2 = OpTypeVoid
41 %3 = OpTypeFunction %2
42 %6 = OpTypeFloat 32
43 %7 = OpTypeVector %6 3
44 %8 = OpTypeMatrix %7 2
45 %9 = OpTypePointer Private %8
46 %10 = OpVariable %9 Private
47 %11 = OpTypeInt 32 1
48 %12 = OpConstant %11 0
49 %13 = OpTypeInt 32 0
50 %14 = OpTypeVector %13 4
51 %15 = OpTypePointer Private %14
52 %16 = OpVariable %15 Private
53 %17 = OpConstant %13 2
54 %18 = OpTypePointer Private %13
55 %22 = OpConstant %13 0
56 %23 = OpTypePointer Private %6
57 %4 = OpFunction %2 None %3
58 %5 = OpLabel
59 %19 = OpAccessChain %18 %16 %17
60 %20 = OpLoad %13 %19
61 %21 = OpConvertUToF %6 %20
62 %24 = OpAccessChain %23 %10 %12 %22
63 OpStore %24 %21
64 OpReturn
65 OpFunctionEnd
66 )";
67
68 std::string donor_shader = R"(
69 OpCapability Shader
70 %1 = OpExtInstImport "GLSL.std.450"
71 OpMemoryModel Logical GLSL450
72 OpEntryPoint Fragment %4 "main"
73 OpExecutionMode %4 OriginUpperLeft
74 OpSource ESSL 310
75 OpName %4 "main"
76 OpName %12 "bar(mf24;"
77 OpName %11 "m"
78 OpName %20 "foo(vu4;"
79 OpName %19 "v"
80 OpName %23 "x"
81 OpName %26 "param"
82 OpName %29 "result"
83 OpName %31 "i"
84 OpName %81 "param"
85 %2 = OpTypeVoid
86 %3 = OpTypeFunction %2
87 %6 = OpTypeFloat 32
88 %7 = OpTypeVector %6 4
89 %8 = OpTypeMatrix %7 2
90 %9 = OpTypePointer Function %8
91 %10 = OpTypeFunction %6 %9
92 %14 = OpTypeInt 32 0
93 %15 = OpTypeVector %14 4
94 %16 = OpTypePointer Function %15
95 %17 = OpTypeInt 32 1
96 %18 = OpTypeFunction %17 %16
97 %22 = OpTypePointer Function %17
98 %24 = OpConstant %14 2
99 %25 = OpConstantComposite %15 %24 %24 %24 %24
100 %28 = OpTypePointer Function %6
101 %30 = OpConstant %6 0
102 %32 = OpConstant %17 0
103 %39 = OpConstant %17 10
104 %40 = OpTypeBool
105 %43 = OpConstant %17 3
106 %50 = OpConstant %17 1
107 %55 = OpConstant %14 0
108 %56 = OpTypePointer Function %14
109 %59 = OpConstant %14 1
110 %65 = OpConstant %17 2
111 %68 = OpConstant %6 1
112 %69 = OpConstant %6 2
113 %70 = OpConstant %6 3
114 %71 = OpConstant %6 4
115 %72 = OpConstant %14 3
116 %76 = OpConstant %6 6
117 %77 = OpConstant %6 7
118 %4 = OpFunction %2 None %3
119 %5 = OpLabel
120 %23 = OpVariable %22 Function
121 %26 = OpVariable %16 Function
122 OpStore %26 %25
123 %27 = OpFunctionCall %17 %20 %26
124 OpStore %23 %27
125 OpReturn
126 OpFunctionEnd
127 %12 = OpFunction %6 None %10
128 %11 = OpFunctionParameter %9
129 %13 = OpLabel
130 %29 = OpVariable %28 Function
131 %31 = OpVariable %22 Function
132 OpStore %29 %30
133 OpStore %31 %32
134 OpBranch %33
135 %33 = OpLabel
136 OpLoopMerge %35 %36 None
137 OpBranch %37
138 %37 = OpLabel
139 %38 = OpLoad %17 %31
140 %41 = OpSLessThan %40 %38 %39
141 OpBranchConditional %41 %34 %35
142 %34 = OpLabel
143 %42 = OpLoad %17 %31
144 %44 = OpExtInst %17 %1 SClamp %42 %32 %43
145 %45 = OpAccessChain %28 %11 %32 %44
146 %46 = OpLoad %6 %45
147 %47 = OpLoad %6 %29
148 %48 = OpFAdd %6 %47 %46
149 OpStore %29 %48
150 OpBranch %36
151 %36 = OpLabel
152 %49 = OpLoad %17 %31
153 %51 = OpIAdd %17 %49 %50
154 OpStore %31 %51
155 OpBranch %33
156 %35 = OpLabel
157 %52 = OpLoad %6 %29
158 OpReturnValue %52
159 OpFunctionEnd
160 %20 = OpFunction %17 None %18
161 %19 = OpFunctionParameter %16
162 %21 = OpLabel
163 %81 = OpVariable %9 Function
164 %57 = OpAccessChain %56 %19 %55
165 %58 = OpLoad %14 %57
166 %60 = OpAccessChain %56 %19 %59
167 %61 = OpLoad %14 %60
168 %62 = OpUGreaterThan %40 %58 %61
169 OpSelectionMerge %64 None
170 OpBranchConditional %62 %63 %67
171 %63 = OpLabel
172 OpReturnValue %65
173 %67 = OpLabel
174 %73 = OpAccessChain %56 %19 %72
175 %74 = OpLoad %14 %73
176 %75 = OpConvertUToF %6 %74
177 %78 = OpCompositeConstruct %7 %30 %68 %69 %70
178 %79 = OpCompositeConstruct %7 %71 %75 %76 %77
179 %80 = OpCompositeConstruct %8 %78 %79
180 OpStore %81 %80
181 %82 = OpFunctionCall %6 %12 %81
182 %83 = OpConvertFToS %17 %82
183 OpReturnValue %83
184 %64 = OpLabel
185 %85 = OpUndef %17
186 OpReturnValue %85
187 OpFunctionEnd
188 )";
189
190 const auto env = SPV_ENV_UNIVERSAL_1_3;
191 const auto consumer = nullptr;
192 spvtools::ValidatorOptions validator_options;
193
194 const auto recipient_context =
195 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
196 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
197 recipient_context.get(), validator_options, kConsoleMessageConsumer));
198
199 const auto donor_context =
200 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
201 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
202 donor_context.get(), validator_options, kConsoleMessageConsumer));
203
204 TransformationContext transformation_context(
205 MakeUnique<FactManager>(recipient_context.get()), validator_options);
206
207 PseudoRandomGenerator prng(0);
208 FuzzerContext fuzzer_context(&prng, 100);
209 protobufs::TransformationSequence transformation_sequence;
210
211 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
212 &transformation_context, &fuzzer_context,
213 &transformation_sequence, {});
214
215 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
216
217 // We just check that the result is valid. Checking to what it should be
218 // exactly equal to would be very fragile.
219 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
220 recipient_context.get(), validator_options, kConsoleMessageConsumer));
221 }
222
TEST(FuzzerPassDonateModulesTest,DonationWithUniforms)223 TEST(FuzzerPassDonateModulesTest, DonationWithUniforms) {
224 // This test checks that when donating a shader that contains uniforms,
225 // uniform variables and associated pointer types are demoted from having
226 // Uniform storage class to Private storage class.
227 std::string recipient_and_donor_shader = R"(
228 OpCapability Shader
229 %1 = OpExtInstImport "GLSL.std.450"
230 OpMemoryModel Logical GLSL450
231 OpEntryPoint Fragment %4 "main"
232 OpExecutionMode %4 OriginUpperLeft
233 OpSource ESSL 310
234 OpMemberDecorate %9 0 Offset 0
235 OpDecorate %9 Block
236 OpDecorate %11 DescriptorSet 0
237 OpDecorate %11 Binding 0
238 OpMemberDecorate %19 0 Offset 0
239 OpDecorate %19 Block
240 OpDecorate %21 DescriptorSet 0
241 OpDecorate %21 Binding 1
242 %2 = OpTypeVoid
243 %3 = OpTypeFunction %2
244 %6 = OpTypeFloat 32
245 %7 = OpTypePointer Function %6
246 %9 = OpTypeStruct %6
247 %10 = OpTypePointer Uniform %9
248 %11 = OpVariable %10 Uniform
249 %12 = OpTypeInt 32 1
250 %13 = OpConstant %12 0
251 %14 = OpTypePointer Uniform %6
252 %17 = OpTypePointer Function %12
253 %19 = OpTypeStruct %12
254 %20 = OpTypePointer Uniform %19
255 %21 = OpVariable %20 Uniform
256 %22 = OpTypePointer Uniform %12
257 %4 = OpFunction %2 None %3
258 %5 = OpLabel
259 %8 = OpVariable %7 Function
260 %18 = OpVariable %17 Function
261 %15 = OpAccessChain %14 %11 %13
262 %16 = OpLoad %6 %15
263 OpStore %8 %16
264 %23 = OpAccessChain %22 %21 %13
265 %24 = OpLoad %12 %23
266 OpStore %18 %24
267 OpReturn
268 OpFunctionEnd
269 )";
270
271 const auto env = SPV_ENV_UNIVERSAL_1_3;
272 const auto consumer = nullptr;
273 spvtools::ValidatorOptions validator_options;
274
275 const auto recipient_context = BuildModule(
276 env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
277 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
278 recipient_context.get(), validator_options, kConsoleMessageConsumer));
279
280 const auto donor_context = BuildModule(
281 env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
282 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
283 donor_context.get(), validator_options, kConsoleMessageConsumer));
284
285 TransformationContext transformation_context(
286 MakeUnique<FactManager>(recipient_context.get()), validator_options);
287
288 PseudoRandomGenerator prng(0);
289 FuzzerContext fuzzer_context(&prng, 100);
290 protobufs::TransformationSequence transformation_sequence;
291
292 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
293 &transformation_context, &fuzzer_context,
294 &transformation_sequence, {});
295
296 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
297
298 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
299 recipient_context.get(), validator_options, kConsoleMessageConsumer));
300
301 std::string after_transformation = R"(
302 OpCapability Shader
303 %1 = OpExtInstImport "GLSL.std.450"
304 OpMemoryModel Logical GLSL450
305 OpEntryPoint Fragment %4 "main"
306 OpExecutionMode %4 OriginUpperLeft
307 OpSource ESSL 310
308 OpMemberDecorate %9 0 Offset 0
309 OpDecorate %9 Block
310 OpDecorate %11 DescriptorSet 0
311 OpDecorate %11 Binding 0
312 OpMemberDecorate %19 0 Offset 0
313 OpDecorate %19 Block
314 OpDecorate %21 DescriptorSet 0
315 OpDecorate %21 Binding 1
316 %2 = OpTypeVoid
317 %3 = OpTypeFunction %2
318 %6 = OpTypeFloat 32
319 %7 = OpTypePointer Function %6
320 %9 = OpTypeStruct %6
321 %10 = OpTypePointer Uniform %9
322 %11 = OpVariable %10 Uniform
323 %12 = OpTypeInt 32 1
324 %13 = OpConstant %12 0
325 %14 = OpTypePointer Uniform %6
326 %17 = OpTypePointer Function %12
327 %19 = OpTypeStruct %12
328 %20 = OpTypePointer Uniform %19
329 %21 = OpVariable %20 Uniform
330 %22 = OpTypePointer Uniform %12
331 %100 = OpTypePointer Function %6
332 %101 = OpTypeStruct %6
333 %102 = OpTypePointer Private %101
334 %104 = OpConstant %6 0
335 %105 = OpConstantComposite %101 %104
336 %103 = OpVariable %102 Private %105
337 %106 = OpConstant %12 0
338 %107 = OpTypePointer Private %6
339 %108 = OpTypePointer Function %12
340 %109 = OpTypeStruct %12
341 %110 = OpTypePointer Private %109
342 %112 = OpConstantComposite %109 %13
343 %111 = OpVariable %110 Private %112
344 %113 = OpTypePointer Private %12
345 %4 = OpFunction %2 None %3
346 %5 = OpLabel
347 %8 = OpVariable %7 Function
348 %18 = OpVariable %17 Function
349 %15 = OpAccessChain %14 %11 %13
350 %16 = OpLoad %6 %15
351 OpStore %8 %16
352 %23 = OpAccessChain %22 %21 %13
353 %24 = OpLoad %12 %23
354 OpStore %18 %24
355 OpReturn
356 OpFunctionEnd
357 %114 = OpFunction %2 None %3
358 %115 = OpLabel
359 %116 = OpVariable %100 Function %104
360 %117 = OpVariable %108 Function %13
361 %118 = OpAccessChain %107 %103 %106
362 %119 = OpLoad %6 %118
363 OpStore %116 %119
364 %120 = OpAccessChain %113 %111 %106
365 %121 = OpLoad %12 %120
366 OpStore %117 %121
367 OpReturn
368 OpFunctionEnd
369 )";
370 ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get()));
371 }
372
TEST(FuzzerPassDonateModulesTest,DonationWithInputAndOutputVariables)373 TEST(FuzzerPassDonateModulesTest, DonationWithInputAndOutputVariables) {
374 // This test checks that when donating a shader that contains input and output
375 // variables, such variables and associated pointer types are demoted to have
376 // the Private storage class.
377 std::string recipient_and_donor_shader = R"(
378 OpCapability Shader
379 %1 = OpExtInstImport "GLSL.std.450"
380 OpMemoryModel Logical GLSL450
381 OpEntryPoint Fragment %4 "main" %9 %11
382 OpExecutionMode %4 OriginUpperLeft
383 OpSource ESSL 310
384 OpDecorate %9 Location 0
385 OpDecorate %11 Location 1
386 %2 = OpTypeVoid
387 %3 = OpTypeFunction %2
388 %6 = OpTypeFloat 32
389 %7 = OpTypeVector %6 4
390 %8 = OpTypePointer Output %7
391 %9 = OpVariable %8 Output
392 %10 = OpTypePointer Input %7
393 %11 = OpVariable %10 Input
394 %4 = OpFunction %2 None %3
395 %5 = OpLabel
396 %12 = OpLoad %7 %11
397 OpStore %9 %12
398 OpReturn
399 OpFunctionEnd
400 )";
401
402 const auto env = SPV_ENV_UNIVERSAL_1_3;
403 const auto consumer = nullptr;
404 spvtools::ValidatorOptions validator_options;
405
406 const auto recipient_context = BuildModule(
407 env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
408 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
409 recipient_context.get(), validator_options, kConsoleMessageConsumer));
410
411 const auto donor_context = BuildModule(
412 env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
413 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
414 donor_context.get(), validator_options, kConsoleMessageConsumer));
415
416 TransformationContext transformation_context(
417 MakeUnique<FactManager>(recipient_context.get()), validator_options);
418
419 PseudoRandomGenerator prng(0);
420 FuzzerContext fuzzer_context(&prng, 100);
421 protobufs::TransformationSequence transformation_sequence;
422
423 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
424 &transformation_context, &fuzzer_context,
425 &transformation_sequence, {});
426
427 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
428
429 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
430 recipient_context.get(), validator_options, kConsoleMessageConsumer));
431
432 std::string after_transformation = R"(
433 OpCapability Shader
434 %1 = OpExtInstImport "GLSL.std.450"
435 OpMemoryModel Logical GLSL450
436 OpEntryPoint Fragment %4 "main" %9 %11
437 OpExecutionMode %4 OriginUpperLeft
438 OpSource ESSL 310
439 OpDecorate %9 Location 0
440 OpDecorate %11 Location 1
441 %2 = OpTypeVoid
442 %3 = OpTypeFunction %2
443 %6 = OpTypeFloat 32
444 %7 = OpTypeVector %6 4
445 %8 = OpTypePointer Output %7
446 %9 = OpVariable %8 Output
447 %10 = OpTypePointer Input %7
448 %11 = OpVariable %10 Input
449 %100 = OpTypePointer Private %7
450 %102 = OpConstant %6 0
451 %103 = OpConstantComposite %7 %102 %102 %102 %102
452 %101 = OpVariable %100 Private %103
453 %104 = OpTypePointer Private %7
454 %105 = OpVariable %104 Private %103
455 %4 = OpFunction %2 None %3
456 %5 = OpLabel
457 %12 = OpLoad %7 %11
458 OpStore %9 %12
459 OpReturn
460 OpFunctionEnd
461 %106 = OpFunction %2 None %3
462 %107 = OpLabel
463 %108 = OpLoad %7 %105
464 OpStore %101 %108
465 OpReturn
466 OpFunctionEnd
467 )";
468 ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get()));
469 }
470
TEST(FuzzerPassDonateModulesTest,DonateFunctionTypeWithDifferentPointers)471 TEST(FuzzerPassDonateModulesTest, DonateFunctionTypeWithDifferentPointers) {
472 std::string recipient_and_donor_shader = R"(
473 OpCapability Shader
474 %1 = OpExtInstImport "GLSL.std.450"
475 OpMemoryModel Logical GLSL450
476 OpEntryPoint Fragment %4 "main"
477 OpExecutionMode %4 OriginUpperLeft
478 OpSource ESSL 310
479 %2 = OpTypeVoid
480 %3 = OpTypeFunction %2
481 %6 = OpTypeInt 32 0
482 %7 = OpTypePointer Function %6
483 %8 = OpTypeFunction %2 %7
484 %4 = OpFunction %2 None %3
485 %5 = OpLabel
486 %9 = OpVariable %7 Function
487 %10 = OpFunctionCall %2 %11 %9
488 OpReturn
489 OpFunctionEnd
490 %11 = OpFunction %2 None %8
491 %12 = OpFunctionParameter %7
492 %13 = OpLabel
493 OpReturn
494 OpFunctionEnd
495 )";
496
497 const auto env = SPV_ENV_UNIVERSAL_1_5;
498 const auto consumer = nullptr;
499 spvtools::ValidatorOptions validator_options;
500
501 const auto recipient_context = BuildModule(
502 env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
503 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
504 recipient_context.get(), validator_options, kConsoleMessageConsumer));
505
506 const auto donor_context = BuildModule(
507 env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
508 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
509 donor_context.get(), validator_options, kConsoleMessageConsumer));
510
511 TransformationContext transformation_context(
512 MakeUnique<FactManager>(recipient_context.get()), validator_options);
513
514 PseudoRandomGenerator prng(0);
515 FuzzerContext fuzzer_context(&prng, 100);
516 protobufs::TransformationSequence transformation_sequence;
517
518 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
519 &transformation_context, &fuzzer_context,
520 &transformation_sequence, {});
521
522 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
523
524 // We just check that the result is valid. Checking to what it should be
525 // exactly equal to would be very fragile.
526 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
527 recipient_context.get(), validator_options, kConsoleMessageConsumer));
528 }
529
TEST(FuzzerPassDonateModulesTest,DonateOpConstantNull)530 TEST(FuzzerPassDonateModulesTest, DonateOpConstantNull) {
531 std::string recipient_shader = R"(
532 OpCapability Shader
533 OpCapability ImageQuery
534 %1 = OpExtInstImport "GLSL.std.450"
535 OpMemoryModel Logical GLSL450
536 OpEntryPoint Fragment %4 "main"
537 OpExecutionMode %4 OriginUpperLeft
538 OpSource ESSL 320
539 OpSourceExtension "GL_EXT_samplerless_texture_functions"
540 %2 = OpTypeVoid
541 %3 = OpTypeFunction %2
542 %4 = OpFunction %2 None %3
543 %5 = OpLabel
544 OpReturn
545 OpFunctionEnd
546 )";
547
548 std::string donor_shader = R"(
549 OpCapability Shader
550 OpCapability ImageQuery
551 %1 = OpExtInstImport "GLSL.std.450"
552 OpMemoryModel Logical GLSL450
553 OpEntryPoint Fragment %4 "main"
554 OpExecutionMode %4 OriginUpperLeft
555 OpSource ESSL 320
556 %2 = OpTypeVoid
557 %3 = OpTypeFunction %2
558 %6 = OpTypeFloat 32
559 %7 = OpTypePointer Private %6
560 %8 = OpConstantNull %7
561 %4 = OpFunction %2 None %3
562 %5 = OpLabel
563 OpReturn
564 OpFunctionEnd
565 )";
566
567 const auto env = SPV_ENV_UNIVERSAL_1_3;
568 const auto consumer = nullptr;
569 spvtools::ValidatorOptions validator_options;
570
571 const auto recipient_context =
572 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
573 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
574 recipient_context.get(), validator_options, kConsoleMessageConsumer));
575
576 const auto donor_context =
577 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
578 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
579 donor_context.get(), validator_options, kConsoleMessageConsumer));
580
581 TransformationContext transformation_context(
582 MakeUnique<FactManager>(recipient_context.get()), validator_options);
583
584 PseudoRandomGenerator prng(0);
585 FuzzerContext fuzzer_context(&prng, 100);
586 protobufs::TransformationSequence transformation_sequence;
587
588 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
589 &transformation_context, &fuzzer_context,
590 &transformation_sequence, {});
591
592 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
593
594 // We just check that the result is valid. Checking to what it should be
595 // exactly equal to would be very fragile.
596 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
597 recipient_context.get(), validator_options, kConsoleMessageConsumer));
598 }
599
TEST(FuzzerPassDonateModulesTest,DonateCodeThatUsesImages)600 TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImages) {
601 std::string recipient_shader = R"(
602 OpCapability Shader
603 OpCapability ImageQuery
604 %1 = OpExtInstImport "GLSL.std.450"
605 OpMemoryModel Logical GLSL450
606 OpEntryPoint Fragment %4 "main"
607 OpExecutionMode %4 OriginUpperLeft
608 OpSource ESSL 320
609 OpSourceExtension "GL_EXT_samplerless_texture_functions"
610 %2 = OpTypeVoid
611 %3 = OpTypeFunction %2
612 %4 = OpFunction %2 None %3
613 %5 = OpLabel
614 OpReturn
615 OpFunctionEnd
616 )";
617
618 std::string donor_shader = R"(
619 OpCapability Shader
620 OpCapability ImageQuery
621 %1 = OpExtInstImport "GLSL.std.450"
622 OpMemoryModel Logical GLSL450
623 OpEntryPoint Fragment %4 "main"
624 OpExecutionMode %4 OriginUpperLeft
625 OpSource ESSL 320
626 OpSourceExtension "GL_EXT_samplerless_texture_functions"
627 OpName %4 "main"
628 OpName %10 "mySampler"
629 OpName %21 "myTexture"
630 OpName %33 "v"
631 OpDecorate %10 RelaxedPrecision
632 OpDecorate %10 DescriptorSet 0
633 OpDecorate %10 Binding 0
634 OpDecorate %11 RelaxedPrecision
635 OpDecorate %21 RelaxedPrecision
636 OpDecorate %21 DescriptorSet 0
637 OpDecorate %21 Binding 1
638 OpDecorate %22 RelaxedPrecision
639 OpDecorate %34 RelaxedPrecision
640 OpDecorate %40 RelaxedPrecision
641 OpDecorate %42 RelaxedPrecision
642 OpDecorate %43 RelaxedPrecision
643 %2 = OpTypeVoid
644 %3 = OpTypeFunction %2
645 %6 = OpTypeFloat 32
646 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
647 %8 = OpTypeSampledImage %7
648 %9 = OpTypePointer UniformConstant %8
649 %10 = OpVariable %9 UniformConstant
650 %12 = OpTypeInt 32 1
651 %13 = OpConstant %12 2
652 %15 = OpTypeVector %12 2
653 %17 = OpTypeInt 32 0
654 %18 = OpConstant %17 0
655 %20 = OpTypePointer UniformConstant %7
656 %21 = OpVariable %20 UniformConstant
657 %23 = OpConstant %12 1
658 %25 = OpConstant %17 1
659 %27 = OpTypeBool
660 %31 = OpTypeVector %6 4
661 %32 = OpTypePointer Function %31
662 %35 = OpConstantComposite %15 %23 %23
663 %36 = OpConstant %12 3
664 %37 = OpConstant %12 4
665 %38 = OpConstantComposite %15 %36 %37
666 %4 = OpFunction %2 None %3
667 %5 = OpLabel
668 %33 = OpVariable %32 Function
669 %11 = OpLoad %8 %10
670 %14 = OpImage %7 %11
671 %16 = OpImageQuerySizeLod %15 %14 %13
672 %19 = OpCompositeExtract %12 %16 0
673 %22 = OpLoad %7 %21
674 %24 = OpImageQuerySizeLod %15 %22 %23
675 %26 = OpCompositeExtract %12 %24 1
676 %28 = OpSGreaterThan %27 %19 %26
677 OpSelectionMerge %30 None
678 OpBranchConditional %28 %29 %41
679 %29 = OpLabel
680 %34 = OpLoad %8 %10
681 %39 = OpImage %7 %34
682 %40 = OpImageFetch %31 %39 %35 Lod|ConstOffset %13 %38
683 OpStore %33 %40
684 OpBranch %30
685 %41 = OpLabel
686 %42 = OpLoad %7 %21
687 %43 = OpImageFetch %31 %42 %35 Lod|ConstOffset %13 %38
688 OpStore %33 %43
689 OpBranch %30
690 %30 = OpLabel
691 OpReturn
692 OpFunctionEnd
693 )";
694
695 const auto env = SPV_ENV_UNIVERSAL_1_3;
696 const auto consumer = nullptr;
697 spvtools::ValidatorOptions validator_options;
698
699 const auto recipient_context =
700 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
701 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
702 recipient_context.get(), validator_options, kConsoleMessageConsumer));
703
704 const auto donor_context =
705 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
706 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
707 donor_context.get(), validator_options, kConsoleMessageConsumer));
708
709 TransformationContext transformation_context(
710 MakeUnique<FactManager>(recipient_context.get()), validator_options);
711
712 PseudoRandomGenerator prng(0);
713 FuzzerContext fuzzer_context(&prng, 100);
714 protobufs::TransformationSequence transformation_sequence;
715
716 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
717 &transformation_context, &fuzzer_context,
718 &transformation_sequence, {});
719
720 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
721
722 // We just check that the result is valid. Checking to what it should be
723 // exactly equal to would be very fragile.
724 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
725 recipient_context.get(), validator_options, kConsoleMessageConsumer));
726 }
727
TEST(FuzzerPassDonateModulesTest,DonateCodeThatUsesSampler)728 TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesSampler) {
729 std::string recipient_shader = R"(
730 OpCapability Shader
731 OpCapability ImageQuery
732 %1 = OpExtInstImport "GLSL.std.450"
733 OpMemoryModel Logical GLSL450
734 OpEntryPoint Fragment %4 "main"
735 OpExecutionMode %4 OriginUpperLeft
736 OpSource ESSL 320
737 OpSourceExtension "GL_EXT_samplerless_texture_functions"
738 %2 = OpTypeVoid
739 %3 = OpTypeFunction %2
740 %4 = OpFunction %2 None %3
741 %5 = OpLabel
742 OpReturn
743 OpFunctionEnd
744 )";
745
746 std::string donor_shader = R"(
747 OpCapability Shader
748 OpCapability ImageQuery
749 %1 = OpExtInstImport "GLSL.std.450"
750 OpMemoryModel Logical GLSL450
751 OpEntryPoint Fragment %4 "main"
752 OpExecutionMode %4 OriginUpperLeft
753 OpSource ESSL 320
754 OpDecorate %16 DescriptorSet 0
755 OpDecorate %16 Binding 0
756 OpDecorate %12 DescriptorSet 0
757 OpDecorate %12 Binding 64
758 %2 = OpTypeVoid
759 %3 = OpTypeFunction %2
760 %23 = OpTypeFloat 32
761 %6 = OpTypeImage %23 2D 2 0 0 1 Unknown
762 %47 = OpTypePointer UniformConstant %6
763 %12 = OpVariable %47 UniformConstant
764 %15 = OpTypeSampler
765 %55 = OpTypePointer UniformConstant %15
766 %17 = OpTypeSampledImage %6
767 %16 = OpVariable %55 UniformConstant
768 %37 = OpTypeVector %23 4
769 %109 = OpConstant %23 0
770 %66 = OpConstantComposite %37 %109 %109 %109 %109
771 %56 = OpTypeBool
772 %54 = OpConstantTrue %56
773 %4 = OpFunction %2 None %3
774 %5 = OpLabel
775 OpBranch %50
776 %50 = OpLabel
777 %51 = OpPhi %37 %66 %5 %111 %53
778 OpLoopMerge %52 %53 None
779 OpBranchConditional %54 %53 %52
780 %53 = OpLabel
781 %106 = OpLoad %6 %12
782 %107 = OpLoad %15 %16
783 %110 = OpSampledImage %17 %106 %107
784 %111 = OpImageSampleImplicitLod %37 %110 %66 Bias %109
785 OpBranch %50
786 %52 = OpLabel
787 OpReturn
788 OpFunctionEnd
789 )";
790
791 const auto env = SPV_ENV_UNIVERSAL_1_3;
792 const auto consumer = nullptr;
793 spvtools::ValidatorOptions validator_options;
794
795 const auto recipient_context =
796 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
797 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
798 recipient_context.get(), validator_options, kConsoleMessageConsumer));
799
800 const auto donor_context =
801 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
802 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
803 donor_context.get(), validator_options, kConsoleMessageConsumer));
804
805 TransformationContext transformation_context(
806 MakeUnique<FactManager>(recipient_context.get()), validator_options);
807
808 PseudoRandomGenerator prng(0);
809 FuzzerContext fuzzer_context(&prng, 100);
810 protobufs::TransformationSequence transformation_sequence;
811
812 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
813 &transformation_context, &fuzzer_context,
814 &transformation_sequence, {});
815
816 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
817
818 // We just check that the result is valid. Checking to what it should be
819 // exactly equal to would be very fragile.
820 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
821 recipient_context.get(), validator_options, kConsoleMessageConsumer));
822 }
823
TEST(FuzzerPassDonateModulesTest,DonateCodeThatUsesImageStructField)824 TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImageStructField) {
825 std::string recipient_shader = R"(
826 OpCapability Shader
827 OpCapability ImageQuery
828 %1 = OpExtInstImport "GLSL.std.450"
829 OpMemoryModel Logical GLSL450
830 OpEntryPoint Fragment %4 "main"
831 OpExecutionMode %4 OriginUpperLeft
832 OpSource ESSL 320
833 OpSourceExtension "GL_EXT_samplerless_texture_functions"
834 %2 = OpTypeVoid
835 %3 = OpTypeFunction %2
836 %4 = OpFunction %2 None %3
837 %5 = OpLabel
838 OpReturn
839 OpFunctionEnd
840 )";
841
842 std::string donor_shader = R"(
843 OpCapability Shader
844 OpCapability ImageQuery
845 %1 = OpExtInstImport "GLSL.std.450"
846 OpMemoryModel Logical GLSL450
847 OpEntryPoint Fragment %4 "main"
848 OpExecutionMode %4 OriginUpperLeft
849 OpSource ESSL 320
850 OpSourceExtension "GL_EXT_samplerless_texture_functions"
851 OpName %4 "main"
852 OpName %10 "mySampler"
853 OpName %21 "myTexture"
854 OpName %33 "v"
855 OpDecorate %10 RelaxedPrecision
856 OpDecorate %10 DescriptorSet 0
857 OpDecorate %10 Binding 0
858 OpDecorate %11 RelaxedPrecision
859 OpDecorate %21 RelaxedPrecision
860 OpDecorate %21 DescriptorSet 0
861 OpDecorate %21 Binding 1
862 OpDecorate %22 RelaxedPrecision
863 OpDecorate %34 RelaxedPrecision
864 OpDecorate %40 RelaxedPrecision
865 OpDecorate %42 RelaxedPrecision
866 OpDecorate %43 RelaxedPrecision
867 %2 = OpTypeVoid
868 %3 = OpTypeFunction %2
869 %6 = OpTypeFloat 32
870 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
871 %8 = OpTypeSampledImage %7
872 %9 = OpTypePointer UniformConstant %8
873 %10 = OpVariable %9 UniformConstant
874 %12 = OpTypeInt 32 1
875 %13 = OpConstant %12 2
876 %15 = OpTypeVector %12 2
877 %17 = OpTypeInt 32 0
878 %18 = OpConstant %17 0
879 %20 = OpTypePointer UniformConstant %7
880 %21 = OpVariable %20 UniformConstant
881 %23 = OpConstant %12 1
882 %25 = OpConstant %17 1
883 %27 = OpTypeBool
884 %31 = OpTypeVector %6 4
885 %32 = OpTypePointer Function %31
886 %35 = OpConstantComposite %15 %23 %23
887 %36 = OpConstant %12 3
888 %37 = OpConstant %12 4
889 %38 = OpConstantComposite %15 %36 %37
890 %201 = OpTypeStruct %7 %7
891 %4 = OpFunction %2 None %3
892 %5 = OpLabel
893 %33 = OpVariable %32 Function
894 %11 = OpLoad %8 %10
895 %14 = OpImage %7 %11
896 %22 = OpLoad %7 %21
897 %200 = OpCompositeConstruct %201 %14 %22
898 %202 = OpCompositeExtract %7 %200 0
899 %203 = OpCompositeExtract %7 %200 1
900 %24 = OpImageQuerySizeLod %15 %203 %23
901 %16 = OpImageQuerySizeLod %15 %202 %13
902 %26 = OpCompositeExtract %12 %24 1
903 %19 = OpCompositeExtract %12 %16 0
904 %28 = OpSGreaterThan %27 %19 %26
905 OpSelectionMerge %30 None
906 OpBranchConditional %28 %29 %41
907 %29 = OpLabel
908 %34 = OpLoad %8 %10
909 %39 = OpImage %7 %34
910 %40 = OpImageFetch %31 %39 %35 Lod|ConstOffset %13 %38
911 OpStore %33 %40
912 OpBranch %30
913 %41 = OpLabel
914 %42 = OpLoad %7 %21
915 %43 = OpImageFetch %31 %42 %35 Lod|ConstOffset %13 %38
916 OpStore %33 %43
917 OpBranch %30
918 %30 = OpLabel
919 OpReturn
920 OpFunctionEnd
921 )";
922
923 const auto env = SPV_ENV_UNIVERSAL_1_3;
924 const auto consumer = nullptr;
925 spvtools::ValidatorOptions validator_options;
926
927 const auto recipient_context =
928 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
929 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
930 recipient_context.get(), validator_options, kConsoleMessageConsumer));
931
932 const auto donor_context =
933 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
934 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
935 donor_context.get(), validator_options, kConsoleMessageConsumer));
936
937 TransformationContext transformation_context(
938 MakeUnique<FactManager>(recipient_context.get()), validator_options);
939
940 PseudoRandomGenerator prng(0);
941 FuzzerContext fuzzer_context(&prng, 100);
942 protobufs::TransformationSequence transformation_sequence;
943
944 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
945 &transformation_context, &fuzzer_context,
946 &transformation_sequence, {});
947
948 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
949
950 // We just check that the result is valid. Checking to what it should be
951 // exactly equal to would be very fragile.
952 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
953 recipient_context.get(), validator_options, kConsoleMessageConsumer));
954 }
955
TEST(FuzzerPassDonateModulesTest,DonateCodeThatUsesImageFunctionParameter)956 TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImageFunctionParameter) {
957 std::string recipient_shader = R"(
958 OpCapability Shader
959 OpCapability ImageQuery
960 %1 = OpExtInstImport "GLSL.std.450"
961 OpMemoryModel Logical GLSL450
962 OpEntryPoint Fragment %4 "main"
963 OpExecutionMode %4 OriginUpperLeft
964 OpSource ESSL 320
965 OpSourceExtension "GL_EXT_samplerless_texture_functions"
966 %2 = OpTypeVoid
967 %3 = OpTypeFunction %2
968 %4 = OpFunction %2 None %3
969 %5 = OpLabel
970 OpReturn
971 OpFunctionEnd
972 )";
973
974 std::string donor_shader = R"(
975 OpCapability Shader
976 OpCapability ImageQuery
977 %1 = OpExtInstImport "GLSL.std.450"
978 OpMemoryModel Logical GLSL450
979 OpEntryPoint Fragment %4 "main"
980 OpExecutionMode %4 OriginUpperLeft
981 OpSource ESSL 320
982 OpSourceExtension "GL_EXT_samplerless_texture_functions"
983 OpName %4 "main"
984 OpName %10 "mySampler"
985 OpName %21 "myTexture"
986 OpName %33 "v"
987 OpDecorate %10 RelaxedPrecision
988 OpDecorate %10 DescriptorSet 0
989 OpDecorate %10 Binding 0
990 OpDecorate %11 RelaxedPrecision
991 OpDecorate %21 RelaxedPrecision
992 OpDecorate %21 DescriptorSet 0
993 OpDecorate %21 Binding 1
994 OpDecorate %22 RelaxedPrecision
995 OpDecorate %34 RelaxedPrecision
996 OpDecorate %40 RelaxedPrecision
997 OpDecorate %42 RelaxedPrecision
998 OpDecorate %43 RelaxedPrecision
999 %2 = OpTypeVoid
1000 %3 = OpTypeFunction %2
1001 %6 = OpTypeFloat 32
1002 %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
1003 %8 = OpTypeSampledImage %7
1004 %9 = OpTypePointer UniformConstant %8
1005 %10 = OpVariable %9 UniformConstant
1006 %12 = OpTypeInt 32 1
1007 %13 = OpConstant %12 2
1008 %15 = OpTypeVector %12 2
1009 %17 = OpTypeInt 32 0
1010 %18 = OpConstant %17 0
1011 %20 = OpTypePointer UniformConstant %7
1012 %21 = OpVariable %20 UniformConstant
1013 %23 = OpConstant %12 1
1014 %25 = OpConstant %17 1
1015 %27 = OpTypeBool
1016 %31 = OpTypeVector %6 4
1017 %32 = OpTypePointer Function %31
1018 %35 = OpConstantComposite %15 %23 %23
1019 %36 = OpConstant %12 3
1020 %37 = OpConstant %12 4
1021 %38 = OpConstantComposite %15 %36 %37
1022 %201 = OpTypeFunction %15 %7 %12
1023 %4 = OpFunction %2 None %3
1024 %5 = OpLabel
1025 %33 = OpVariable %32 Function
1026 %11 = OpLoad %8 %10
1027 %14 = OpImage %7 %11
1028 %16 = OpFunctionCall %15 %200 %14 %13
1029 %19 = OpCompositeExtract %12 %16 0
1030 %22 = OpLoad %7 %21
1031 %24 = OpImageQuerySizeLod %15 %22 %23
1032 %26 = OpCompositeExtract %12 %24 1
1033 %28 = OpSGreaterThan %27 %19 %26
1034 OpSelectionMerge %30 None
1035 OpBranchConditional %28 %29 %41
1036 %29 = OpLabel
1037 %34 = OpLoad %8 %10
1038 %39 = OpImage %7 %34
1039 %40 = OpImageFetch %31 %39 %35 Lod|ConstOffset %13 %38
1040 OpStore %33 %40
1041 OpBranch %30
1042 %41 = OpLabel
1043 %42 = OpLoad %7 %21
1044 %43 = OpImageFetch %31 %42 %35 Lod|ConstOffset %13 %38
1045 OpStore %33 %43
1046 OpBranch %30
1047 %30 = OpLabel
1048 OpReturn
1049 OpFunctionEnd
1050 %200 = OpFunction %15 None %201
1051 %202 = OpFunctionParameter %7
1052 %203 = OpFunctionParameter %12
1053 %204 = OpLabel
1054 %205 = OpImageQuerySizeLod %15 %202 %203
1055 OpReturnValue %205
1056 OpFunctionEnd
1057 )";
1058
1059 const auto env = SPV_ENV_UNIVERSAL_1_3;
1060 const auto consumer = nullptr;
1061 spvtools::ValidatorOptions validator_options;
1062
1063 const auto recipient_context =
1064 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1065 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1066 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1067
1068 const auto donor_context =
1069 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1070 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1071 donor_context.get(), validator_options, kConsoleMessageConsumer));
1072
1073 TransformationContext transformation_context(
1074 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1075
1076 PseudoRandomGenerator prng(0);
1077 FuzzerContext fuzzer_context(&prng, 100);
1078 protobufs::TransformationSequence transformation_sequence;
1079
1080 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1081 &transformation_context, &fuzzer_context,
1082 &transformation_sequence, {});
1083
1084 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
1085
1086 // We just check that the result is valid. Checking to what it should be
1087 // exactly equal to would be very fragile.
1088 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1089 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1090 }
1091
TEST(FuzzerPassDonateModulesTest,DonateShaderWithImageStorageClass)1092 TEST(FuzzerPassDonateModulesTest, DonateShaderWithImageStorageClass) {
1093 std::string recipient_shader = R"(
1094 OpCapability Shader
1095 OpCapability ImageQuery
1096 %1 = OpExtInstImport "GLSL.std.450"
1097 OpMemoryModel Logical GLSL450
1098 OpEntryPoint Fragment %4 "main"
1099 OpExecutionMode %4 OriginUpperLeft
1100 OpSource ESSL 320
1101 OpSourceExtension "GL_EXT_samplerless_texture_functions"
1102 %2 = OpTypeVoid
1103 %3 = OpTypeFunction %2
1104 %4 = OpFunction %2 None %3
1105 %5 = OpLabel
1106 OpReturn
1107 OpFunctionEnd
1108 )";
1109
1110 std::string donor_shader = R"(
1111 OpCapability Shader
1112 OpCapability SampledBuffer
1113 OpCapability ImageBuffer
1114 %1 = OpExtInstImport "GLSL.std.450"
1115 OpMemoryModel Logical GLSL450
1116 OpEntryPoint Fragment %2 "MainPSPacked"
1117 OpExecutionMode %2 OriginUpperLeft
1118 OpDecorate %18 DescriptorSet 0
1119 OpDecorate %18 Binding 128
1120 %49 = OpTypeInt 32 0
1121 %50 = OpTypeFloat 32
1122 %58 = OpConstant %50 1
1123 %66 = OpConstant %49 0
1124 %87 = OpTypeVector %50 2
1125 %88 = OpConstantComposite %87 %58 %58
1126 %17 = OpTypeImage %49 2D 2 0 0 2 R32ui
1127 %118 = OpTypePointer UniformConstant %17
1128 %123 = OpTypeVector %49 2
1129 %132 = OpTypeVoid
1130 %133 = OpTypeFunction %132
1131 %142 = OpTypePointer Image %49
1132 %18 = OpVariable %118 UniformConstant
1133 %2 = OpFunction %132 None %133
1134 %153 = OpLabel
1135 %495 = OpConvertFToU %123 %88
1136 %501 = OpImageTexelPointer %142 %18 %495 %66
1137 OpReturn
1138 OpFunctionEnd
1139 )";
1140
1141 const auto env = SPV_ENV_UNIVERSAL_1_3;
1142 const auto consumer = nullptr;
1143 spvtools::ValidatorOptions validator_options;
1144
1145 const auto recipient_context =
1146 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1147 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1148 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1149
1150 const auto donor_context =
1151 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1152 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1153 donor_context.get(), validator_options, kConsoleMessageConsumer));
1154
1155 TransformationContext transformation_context(
1156 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1157
1158 PseudoRandomGenerator prng(0);
1159 FuzzerContext fuzzer_context(&prng, 100);
1160 protobufs::TransformationSequence transformation_sequence;
1161
1162 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1163 &transformation_context, &fuzzer_context,
1164 &transformation_sequence, {});
1165
1166 fuzzer_pass.DonateSingleModule(donor_context.get(), true);
1167
1168 // We just check that the result is valid. Checking to what it should be
1169 // exactly equal to would be very fragile.
1170 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1171 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1172 }
1173
TEST(FuzzerPassDonateModulesTest,DonateComputeShaderWithRuntimeArray)1174 TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithRuntimeArray) {
1175 std::string recipient_shader = R"(
1176 OpCapability Shader
1177 %1 = OpExtInstImport "GLSL.std.450"
1178 OpMemoryModel Logical GLSL450
1179 OpEntryPoint GLCompute %4 "main"
1180 OpExecutionMode %4 LocalSize 1 1 1
1181 OpSource ESSL 310
1182 %2 = OpTypeVoid
1183 %3 = OpTypeFunction %2
1184 %4 = OpFunction %2 None %3
1185 %5 = OpLabel
1186 OpReturn
1187 OpFunctionEnd
1188 )";
1189
1190 std::string donor_shader = R"(
1191 OpCapability Shader
1192 %1 = OpExtInstImport "GLSL.std.450"
1193 OpMemoryModel Logical GLSL450
1194 OpEntryPoint GLCompute %4 "main"
1195 OpExecutionMode %4 LocalSize 1 1 1
1196 OpSource ESSL 310
1197 OpDecorate %9 ArrayStride 4
1198 OpMemberDecorate %10 0 Offset 0
1199 OpDecorate %10 BufferBlock
1200 OpDecorate %12 DescriptorSet 0
1201 OpDecorate %12 Binding 0
1202 %2 = OpTypeVoid
1203 %3 = OpTypeFunction %2
1204 %6 = OpTypeInt 32 1
1205 %7 = OpTypePointer Function %6
1206 %9 = OpTypeRuntimeArray %6
1207 %10 = OpTypeStruct %9
1208 %11 = OpTypePointer Uniform %10
1209 %12 = OpVariable %11 Uniform
1210 %13 = OpTypeInt 32 0
1211 %16 = OpConstant %6 0
1212 %18 = OpConstant %6 1
1213 %20 = OpTypePointer Uniform %6
1214 %4 = OpFunction %2 None %3
1215 %5 = OpLabel
1216 %8 = OpVariable %7 Function
1217 %14 = OpArrayLength %13 %12 0
1218 %15 = OpBitcast %6 %14
1219 OpStore %8 %15
1220 %17 = OpLoad %6 %8
1221 %19 = OpISub %6 %17 %18
1222 %21 = OpAccessChain %20 %12 %16 %19
1223 OpStore %21 %16
1224 OpReturn
1225 OpFunctionEnd
1226 )";
1227
1228 const auto env = SPV_ENV_UNIVERSAL_1_3;
1229 const auto consumer = nullptr;
1230 spvtools::ValidatorOptions validator_options;
1231
1232 const auto recipient_context =
1233 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1234 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1235 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1236
1237 const auto donor_context =
1238 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1239 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1240 donor_context.get(), validator_options, kConsoleMessageConsumer));
1241
1242 TransformationContext transformation_context(
1243 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1244
1245 PseudoRandomGenerator prng(0);
1246 FuzzerContext fuzzer_context(&prng, 100);
1247 protobufs::TransformationSequence transformation_sequence;
1248
1249 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1250 &transformation_context, &fuzzer_context,
1251 &transformation_sequence, {});
1252
1253 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
1254
1255 // We just check that the result is valid. Checking to what it should be
1256 // exactly equal to would be very fragile.
1257 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1258 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1259 }
1260
TEST(FuzzerPassDonateModulesTest,DonateComputeShaderWithRuntimeArrayLivesafe)1261 TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithRuntimeArrayLivesafe) {
1262 std::string recipient_shader = R"(
1263 OpCapability Shader
1264 %1 = OpExtInstImport "GLSL.std.450"
1265 OpMemoryModel Logical GLSL450
1266 OpEntryPoint GLCompute %4 "main"
1267 OpExecutionMode %4 LocalSize 1 1 1
1268 OpSource ESSL 310
1269 %2 = OpTypeVoid
1270 %3 = OpTypeFunction %2
1271 %4 = OpFunction %2 None %3
1272 %5 = OpLabel
1273 OpReturn
1274 OpFunctionEnd
1275 )";
1276
1277 std::string donor_shader = R"(
1278 OpCapability Shader
1279 %1 = OpExtInstImport "GLSL.std.450"
1280 OpMemoryModel Logical GLSL450
1281 OpEntryPoint GLCompute %4 "main"
1282 OpExecutionMode %4 LocalSize 1 1 1
1283 OpSource ESSL 310
1284 OpDecorate %16 ArrayStride 4
1285 OpMemberDecorate %17 0 Offset 0
1286 OpDecorate %17 BufferBlock
1287 OpDecorate %19 DescriptorSet 0
1288 OpDecorate %19 Binding 0
1289 %2 = OpTypeVoid
1290 %3 = OpTypeFunction %2
1291 %6 = OpTypeInt 32 1
1292 %7 = OpTypePointer Function %6
1293 %9 = OpConstant %6 0
1294 %16 = OpTypeRuntimeArray %6
1295 %17 = OpTypeStruct %16
1296 %18 = OpTypePointer Uniform %17
1297 %19 = OpVariable %18 Uniform
1298 %20 = OpTypeInt 32 0
1299 %23 = OpTypeBool
1300 %26 = OpConstant %6 32
1301 %27 = OpTypePointer Uniform %6
1302 %30 = OpConstant %6 1
1303 %4 = OpFunction %2 None %3
1304 %5 = OpLabel
1305 %8 = OpVariable %7 Function
1306 OpStore %8 %9
1307 OpBranch %10
1308 %10 = OpLabel
1309 OpLoopMerge %12 %13 None
1310 OpBranch %14
1311 %14 = OpLabel
1312 %15 = OpLoad %6 %8
1313 %21 = OpArrayLength %20 %19 0
1314 %22 = OpBitcast %6 %21
1315 %24 = OpSLessThan %23 %15 %22
1316 OpBranchConditional %24 %11 %12
1317 %11 = OpLabel
1318 %25 = OpLoad %6 %8
1319 %28 = OpAccessChain %27 %19 %9 %25
1320 OpStore %28 %26
1321 OpBranch %13
1322 %13 = OpLabel
1323 %29 = OpLoad %6 %8
1324 %31 = OpIAdd %6 %29 %30
1325 OpStore %8 %31
1326 OpBranch %10
1327 %12 = OpLabel
1328 OpReturn
1329 OpFunctionEnd
1330 )";
1331
1332 const auto env = SPV_ENV_UNIVERSAL_1_3;
1333 const auto consumer = nullptr;
1334 spvtools::ValidatorOptions validator_options;
1335
1336 const auto recipient_context =
1337 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1338 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1339 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1340
1341 const auto donor_context =
1342 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1343 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1344 donor_context.get(), validator_options, kConsoleMessageConsumer));
1345
1346 TransformationContext transformation_context(
1347 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1348
1349 PseudoRandomGenerator prng(0);
1350 FuzzerContext fuzzer_context(&prng, 100);
1351 protobufs::TransformationSequence transformation_sequence;
1352
1353 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1354 &transformation_context, &fuzzer_context,
1355 &transformation_sequence, {});
1356
1357 fuzzer_pass.DonateSingleModule(donor_context.get(), true);
1358
1359 // We just check that the result is valid. Checking to what it should be
1360 // exactly equal to would be very fragile.
1361 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1362 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1363 }
1364
TEST(FuzzerPassDonateModulesTest,DonateComputeShaderWithWorkgroupVariables)1365 TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithWorkgroupVariables) {
1366 std::string recipient_shader = R"(
1367 OpCapability Shader
1368 %1 = OpExtInstImport "GLSL.std.450"
1369 OpMemoryModel Logical GLSL450
1370 OpEntryPoint GLCompute %4 "main"
1371 OpExecutionMode %4 LocalSize 1 1 1
1372 OpSource ESSL 310
1373 %2 = OpTypeVoid
1374 %3 = OpTypeFunction %2
1375 %4 = OpFunction %2 None %3
1376 %5 = OpLabel
1377 OpReturn
1378 OpFunctionEnd
1379 )";
1380
1381 std::string donor_shader = R"(
1382 OpCapability Shader
1383 %1 = OpExtInstImport "GLSL.std.450"
1384 OpMemoryModel Logical GLSL450
1385 OpEntryPoint GLCompute %4 "main"
1386 OpExecutionMode %4 LocalSize 1 1 1
1387 OpSource ESSL 310
1388 %2 = OpTypeVoid
1389 %3 = OpTypeFunction %2
1390 %6 = OpTypeInt 32 1
1391 %7 = OpTypePointer Workgroup %6
1392 %8 = OpVariable %7 Workgroup
1393 %9 = OpConstant %6 2
1394 %10 = OpVariable %7 Workgroup
1395 %4 = OpFunction %2 None %3
1396 %5 = OpLabel
1397 OpStore %8 %9
1398 %11 = OpLoad %6 %8
1399 OpStore %10 %11
1400 OpReturn
1401 OpFunctionEnd
1402 )";
1403
1404 const auto env = SPV_ENV_UNIVERSAL_1_3;
1405 const auto consumer = nullptr;
1406 spvtools::ValidatorOptions validator_options;
1407
1408 const auto recipient_context =
1409 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1410 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1411 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1412
1413 const auto donor_context =
1414 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1415 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1416 donor_context.get(), validator_options, kConsoleMessageConsumer));
1417
1418 TransformationContext transformation_context(
1419 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1420
1421 PseudoRandomGenerator prng(0);
1422 FuzzerContext fuzzer_context(&prng, 100);
1423 protobufs::TransformationSequence transformation_sequence;
1424
1425 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1426 &transformation_context, &fuzzer_context,
1427 &transformation_sequence, {});
1428
1429 fuzzer_pass.DonateSingleModule(donor_context.get(), true);
1430
1431 // We just check that the result is valid. Checking to what it should be
1432 // exactly equal to would be very fragile.
1433 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1434 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1435 }
1436
TEST(FuzzerPassDonateModulesTest,DonateComputeShaderWithAtomics)1437 TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithAtomics) {
1438 std::string recipient_shader = R"(
1439 OpCapability Shader
1440 %1 = OpExtInstImport "GLSL.std.450"
1441 OpMemoryModel Logical GLSL450
1442 OpEntryPoint GLCompute %4 "main"
1443 OpExecutionMode %4 LocalSize 1 1 1
1444 OpSource ESSL 310
1445 %2 = OpTypeVoid
1446 %3 = OpTypeFunction %2
1447 %4 = OpFunction %2 None %3
1448 %5 = OpLabel
1449 OpReturn
1450 OpFunctionEnd
1451 )";
1452
1453 std::string donor_shader = R"(
1454 OpCapability Shader
1455 %1 = OpExtInstImport "GLSL.std.450"
1456 OpMemoryModel Logical GLSL450
1457 OpEntryPoint GLCompute %4 "main"
1458 OpExecutionMode %4 LocalSize 1 1 1
1459 OpSource ESSL 310
1460 OpMemberDecorate %9 0 Offset 0
1461 OpDecorate %9 BufferBlock
1462 OpDecorate %11 DescriptorSet 0
1463 OpDecorate %11 Binding 0
1464 %2 = OpTypeVoid
1465 %3 = OpTypeFunction %2
1466 %6 = OpTypeInt 32 0
1467 %7 = OpTypePointer Function %6
1468 %9 = OpTypeStruct %6
1469 %10 = OpTypePointer Uniform %9
1470 %11 = OpVariable %10 Uniform
1471 %12 = OpTypeInt 32 1
1472 %13 = OpConstant %12 0
1473 %14 = OpTypePointer Uniform %6
1474 %16 = OpConstant %6 1
1475 %17 = OpConstant %6 0
1476 %4 = OpFunction %2 None %3
1477 %5 = OpLabel
1478 %8 = OpVariable %7 Function
1479 %15 = OpAccessChain %14 %11 %13
1480 %18 = OpAtomicIAdd %6 %15 %16 %17 %16
1481 OpStore %8 %18
1482 %19 = OpAccessChain %14 %11 %13
1483 %20 = OpLoad %6 %8
1484 %21 = OpAtomicUMin %6 %19 %16 %17 %20
1485 OpStore %8 %21
1486 %22 = OpAccessChain %14 %11 %13
1487 %23 = OpLoad %6 %8
1488 %24 = OpAtomicUMax %6 %22 %16 %17 %23
1489 OpStore %8 %24
1490 %25 = OpAccessChain %14 %11 %13
1491 %26 = OpLoad %6 %8
1492 %27 = OpAtomicAnd %6 %25 %16 %17 %26
1493 OpStore %8 %27
1494 %28 = OpAccessChain %14 %11 %13
1495 %29 = OpLoad %6 %8
1496 %30 = OpAtomicOr %6 %28 %16 %17 %29
1497 OpStore %8 %30
1498 %31 = OpAccessChain %14 %11 %13
1499 %32 = OpLoad %6 %8
1500 %33 = OpAtomicXor %6 %31 %16 %17 %32
1501 OpStore %8 %33
1502 %34 = OpAccessChain %14 %11 %13
1503 %35 = OpLoad %6 %8
1504 %36 = OpAtomicExchange %6 %34 %16 %17 %35
1505 OpStore %8 %36
1506 %37 = OpAccessChain %14 %11 %13
1507 %38 = OpLoad %6 %8
1508 %39 = OpAtomicCompareExchange %6 %37 %16 %17 %17 %16 %38
1509 OpStore %8 %39
1510 OpReturn
1511 OpFunctionEnd
1512 )";
1513
1514 const auto env = SPV_ENV_UNIVERSAL_1_3;
1515 const auto consumer = nullptr;
1516 spvtools::ValidatorOptions validator_options;
1517
1518 const auto recipient_context =
1519 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1520 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1521 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1522
1523 const auto donor_context =
1524 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1525 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1526 donor_context.get(), validator_options, kConsoleMessageConsumer));
1527
1528 TransformationContext transformation_context(
1529 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1530
1531 PseudoRandomGenerator prng(0);
1532 FuzzerContext fuzzer_context(&prng, 100);
1533 protobufs::TransformationSequence transformation_sequence;
1534
1535 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1536 &transformation_context, &fuzzer_context,
1537 &transformation_sequence, {});
1538
1539 fuzzer_pass.DonateSingleModule(donor_context.get(), true);
1540
1541 // We just check that the result is valid. Checking to what it should be
1542 // exactly equal to would be very fragile.
1543 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1544 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1545 }
1546
TEST(FuzzerPassDonateModulesTest,Miscellaneous1)1547 TEST(FuzzerPassDonateModulesTest, Miscellaneous1) {
1548 std::string recipient_shader = R"(
1549 OpCapability Shader
1550 %1 = OpExtInstImport "GLSL.std.450"
1551 OpMemoryModel Logical GLSL450
1552 OpEntryPoint Fragment %4 "main"
1553 OpExecutionMode %4 OriginUpperLeft
1554 OpSource ESSL 310
1555 %2 = OpTypeVoid
1556 %3 = OpTypeFunction %2
1557 %4 = OpFunction %2 None %3
1558 %5 = OpLabel
1559 OpReturn
1560 OpFunctionEnd
1561 )";
1562
1563 std::string donor_shader = R"(
1564 OpCapability Shader
1565 %1 = OpExtInstImport "GLSL.std.450"
1566 OpMemoryModel Logical GLSL450
1567 OpEntryPoint Fragment %4 "main"
1568 OpExecutionMode %4 OriginUpperLeft
1569 OpSource ESSL 310
1570 OpName %4 "main"
1571 OpName %6 "foo("
1572 OpName %10 "x"
1573 OpName %12 "i"
1574 OpName %33 "i"
1575 OpName %42 "j"
1576 OpDecorate %10 RelaxedPrecision
1577 OpDecorate %12 RelaxedPrecision
1578 OpDecorate %19 RelaxedPrecision
1579 OpDecorate %23 RelaxedPrecision
1580 OpDecorate %24 RelaxedPrecision
1581 OpDecorate %25 RelaxedPrecision
1582 OpDecorate %26 RelaxedPrecision
1583 OpDecorate %27 RelaxedPrecision
1584 OpDecorate %28 RelaxedPrecision
1585 OpDecorate %30 RelaxedPrecision
1586 OpDecorate %33 RelaxedPrecision
1587 OpDecorate %39 RelaxedPrecision
1588 OpDecorate %42 RelaxedPrecision
1589 OpDecorate %49 RelaxedPrecision
1590 OpDecorate %52 RelaxedPrecision
1591 OpDecorate %53 RelaxedPrecision
1592 OpDecorate %58 RelaxedPrecision
1593 OpDecorate %59 RelaxedPrecision
1594 OpDecorate %60 RelaxedPrecision
1595 OpDecorate %63 RelaxedPrecision
1596 OpDecorate %64 RelaxedPrecision
1597 %2 = OpTypeVoid
1598 %3 = OpTypeFunction %2
1599 %8 = OpTypeInt 32 1
1600 %9 = OpTypePointer Function %8
1601 %11 = OpConstant %8 2
1602 %13 = OpConstant %8 0
1603 %20 = OpConstant %8 100
1604 %21 = OpTypeBool
1605 %29 = OpConstant %8 1
1606 %40 = OpConstant %8 10
1607 %43 = OpConstant %8 20
1608 %61 = OpConstant %8 4
1609 %4 = OpFunction %2 None %3
1610 %5 = OpLabel
1611 %33 = OpVariable %9 Function
1612 %42 = OpVariable %9 Function
1613 %32 = OpFunctionCall %2 %6
1614 OpStore %33 %13
1615 OpBranch %34
1616 %34 = OpLabel
1617 OpLoopMerge %36 %37 None
1618 OpBranch %38
1619 %38 = OpLabel
1620 %39 = OpLoad %8 %33
1621 %41 = OpSLessThan %21 %39 %40
1622 OpBranchConditional %41 %35 %36
1623 %35 = OpLabel
1624 OpStore %42 %43
1625 OpBranch %44
1626 %44 = OpLabel
1627 OpLoopMerge %46 %47 None
1628 OpBranch %48
1629 %48 = OpLabel
1630 %49 = OpLoad %8 %42
1631 %50 = OpSGreaterThan %21 %49 %13
1632 OpBranchConditional %50 %45 %46
1633 %45 = OpLabel
1634 %51 = OpFunctionCall %2 %6
1635 %52 = OpLoad %8 %42
1636 %53 = OpISub %8 %52 %29
1637 OpStore %42 %53
1638 OpBranch %47
1639 %47 = OpLabel
1640 OpBranch %44
1641 %46 = OpLabel
1642 OpBranch %54
1643 %54 = OpLabel
1644 OpLoopMerge %56 %57 None
1645 OpBranch %55
1646 %55 = OpLabel
1647 %58 = OpLoad %8 %33
1648 %59 = OpIAdd %8 %58 %29
1649 OpStore %33 %59
1650 OpBranch %57
1651 %57 = OpLabel
1652 %60 = OpLoad %8 %33
1653 %62 = OpSLessThan %21 %60 %61
1654 OpBranchConditional %62 %54 %56
1655 %56 = OpLabel
1656 OpBranch %37
1657 %37 = OpLabel
1658 %63 = OpLoad %8 %33
1659 %64 = OpIAdd %8 %63 %29
1660 OpStore %33 %64
1661 OpBranch %34
1662 %36 = OpLabel
1663 OpReturn
1664 OpFunctionEnd
1665 %6 = OpFunction %2 None %3
1666 %7 = OpLabel
1667 %10 = OpVariable %9 Function
1668 %12 = OpVariable %9 Function
1669 OpStore %10 %11
1670 OpStore %12 %13
1671 OpBranch %14
1672 %14 = OpLabel
1673 OpLoopMerge %16 %17 None
1674 OpBranch %18
1675 %18 = OpLabel
1676 %19 = OpLoad %8 %12
1677 %22 = OpSLessThan %21 %19 %20
1678 OpBranchConditional %22 %15 %16
1679 %15 = OpLabel
1680 %23 = OpLoad %8 %12
1681 %24 = OpLoad %8 %10
1682 %25 = OpIAdd %8 %24 %23
1683 OpStore %10 %25
1684 %26 = OpLoad %8 %10
1685 %27 = OpIMul %8 %26 %11
1686 OpStore %10 %27
1687 OpBranch %17
1688 %17 = OpLabel
1689 %28 = OpLoad %8 %12
1690 %30 = OpIAdd %8 %28 %29
1691 OpStore %12 %30
1692 OpBranch %14
1693 %16 = OpLabel
1694 OpReturn
1695 OpFunctionEnd
1696 )";
1697
1698 const auto env = SPV_ENV_UNIVERSAL_1_5;
1699 const auto consumer = nullptr;
1700 spvtools::ValidatorOptions validator_options;
1701
1702 const auto recipient_context =
1703 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1704 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1705 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1706
1707 const auto donor_context =
1708 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1709 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1710 donor_context.get(), validator_options, kConsoleMessageConsumer));
1711
1712 TransformationContext transformation_context(
1713 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1714
1715 PseudoRandomGenerator rng(0);
1716 FuzzerContext fuzzer_context(&rng, 100);
1717 protobufs::TransformationSequence transformation_sequence;
1718
1719 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1720 &transformation_context, &fuzzer_context,
1721 &transformation_sequence, {});
1722
1723 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
1724
1725 // We just check that the result is valid. Checking to what it should be
1726 // exactly equal to would be very fragile.
1727 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1728 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1729 }
1730
TEST(FuzzerPassDonateModulesTest,OpSpecConstantInstructions)1731 TEST(FuzzerPassDonateModulesTest, OpSpecConstantInstructions) {
1732 std::string donor_shader = R"(
1733 OpCapability Shader
1734 %1 = OpExtInstImport "GLSL.std.450"
1735 OpMemoryModel Logical GLSL450
1736 OpEntryPoint Fragment %4 "main"
1737 OpExecutionMode %4 OriginUpperLeft
1738 OpSource ESSL 310
1739 %2 = OpTypeVoid
1740 %3 = OpTypeFunction %2
1741 %6 = OpTypeBool
1742 %7 = OpTypeInt 32 1
1743 %8 = OpTypeStruct %6 %6 %7
1744 %9 = OpSpecConstantTrue %6
1745 %10 = OpSpecConstantFalse %6
1746 %11 = OpSpecConstant %7 2
1747 %12 = OpSpecConstantComposite %8 %9 %10 %11
1748 %13 = OpSpecConstantOp %6 LogicalEqual %9 %10
1749 %4 = OpFunction %2 None %3
1750 %5 = OpLabel
1751 OpReturn
1752 OpFunctionEnd
1753 )";
1754
1755 std::string recipient_shader = R"(
1756 OpCapability Shader
1757 %1 = OpExtInstImport "GLSL.std.450"
1758 OpMemoryModel Logical GLSL450
1759 OpEntryPoint Fragment %4 "main"
1760 OpExecutionMode %4 OriginUpperLeft
1761 OpSource ESSL 310
1762 %2 = OpTypeVoid
1763 %3 = OpTypeFunction %2
1764 %4 = OpFunction %2 None %3
1765 %5 = OpLabel
1766 OpReturn
1767 OpFunctionEnd
1768 )";
1769
1770 const auto env = SPV_ENV_UNIVERSAL_1_3;
1771 const auto consumer = nullptr;
1772 spvtools::ValidatorOptions validator_options;
1773
1774 const auto recipient_context =
1775 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1776 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1777 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1778
1779 const auto donor_context =
1780 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1781 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1782 donor_context.get(), validator_options, kConsoleMessageConsumer));
1783
1784 TransformationContext transformation_context(
1785 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1786
1787 PseudoRandomGenerator prng(0);
1788 FuzzerContext fuzzer_context(&prng, 100);
1789 protobufs::TransformationSequence transformation_sequence;
1790
1791 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1792 &transformation_context, &fuzzer_context,
1793 &transformation_sequence, {});
1794
1795 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
1796
1797 // Check that the module is valid first.
1798 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1799 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1800
1801 std::string expected_shader = R"(
1802 OpCapability Shader
1803 %1 = OpExtInstImport "GLSL.std.450"
1804 OpMemoryModel Logical GLSL450
1805 OpEntryPoint Fragment %4 "main"
1806 OpExecutionMode %4 OriginUpperLeft
1807 OpSource ESSL 310
1808 %2 = OpTypeVoid
1809 %3 = OpTypeFunction %2
1810 %100 = OpTypeBool
1811 %101 = OpTypeInt 32 1
1812 %102 = OpTypeStruct %100 %100 %101
1813 %103 = OpConstantTrue %100
1814 %104 = OpConstantFalse %100
1815 %105 = OpConstant %101 2
1816 %106 = OpConstantComposite %102 %103 %104 %105
1817 %107 = OpSpecConstantOp %100 LogicalEqual %103 %104
1818 %4 = OpFunction %2 None %3
1819 %5 = OpLabel
1820 OpReturn
1821 OpFunctionEnd
1822 %108 = OpFunction %2 None %3
1823 %109 = OpLabel
1824 OpReturn
1825 OpFunctionEnd
1826 )";
1827
1828 // Now check that the transformation has produced the expected result.
1829 ASSERT_TRUE(IsEqual(env, expected_shader, recipient_context.get()));
1830 }
1831
TEST(FuzzerPassDonateModulesTest,DonationSupportsOpTypeRuntimeArray)1832 TEST(FuzzerPassDonateModulesTest, DonationSupportsOpTypeRuntimeArray) {
1833 std::string donor_shader = R"(
1834 OpCapability Shader
1835 OpExtension "SPV_KHR_storage_buffer_storage_class"
1836 OpMemoryModel Logical GLSL450
1837 OpEntryPoint GLCompute %29 "kernel_1"
1838 OpEntryPoint GLCompute %37 "kernel_2"
1839 OpSource OpenCL_C 120
1840 OpDecorate %2 ArrayStride 4
1841 OpMemberDecorate %3 0 Offset 0
1842 OpDecorate %3 Block
1843 OpMemberDecorate %5 0 Offset 0
1844 OpMemberDecorate %6 0 Offset 0
1845 OpDecorate %6 Block
1846 OpDecorate %21 BuiltIn WorkgroupSize
1847 OpDecorate %23 DescriptorSet 0
1848 OpDecorate %23 Binding 0
1849 OpDecorate %25 SpecId 3
1850 OpDecorate %18 SpecId 0
1851 OpDecorate %19 SpecId 1
1852 OpDecorate %20 SpecId 2
1853 %1 = OpTypeInt 32 0
1854 %2 = OpTypeRuntimeArray %1
1855 %3 = OpTypeStruct %2
1856 %4 = OpTypePointer StorageBuffer %3
1857 %5 = OpTypeStruct %1
1858 %6 = OpTypeStruct %5
1859 %7 = OpTypePointer PushConstant %6
1860 %8 = OpTypeFloat 32
1861 %9 = OpTypeVoid
1862 %10 = OpTypeFunction %9
1863 %11 = OpTypePointer Workgroup %1
1864 %12 = OpTypePointer PushConstant %5
1865 %13 = OpTypePointer StorageBuffer %1
1866 %14 = OpTypeFunction %1 %1
1867 %15 = OpTypeVector %1 3
1868 %16 = OpTypePointer Private %15
1869 %17 = OpConstant %1 0
1870 %18 = OpSpecConstant %1 1
1871 %19 = OpSpecConstant %1 1
1872 %20 = OpSpecConstant %1 1
1873 %21 = OpSpecConstantComposite %15 %18 %19 %20
1874 %25 = OpSpecConstant %1 1
1875 %26 = OpTypeArray %1 %25
1876 %27 = OpTypePointer Workgroup %26
1877 %22 = OpVariable %16 Private %21
1878 %23 = OpVariable %4 StorageBuffer
1879 %24 = OpVariable %7 PushConstant
1880 %28 = OpVariable %27 Workgroup
1881 %29 = OpFunction %9 None %10
1882 %30 = OpLabel
1883 %31 = OpAccessChain %11 %28 %17
1884 %32 = OpAccessChain %12 %24 %17
1885 %33 = OpLoad %5 %32
1886 %34 = OpCompositeExtract %1 %33 0
1887 %35 = OpFunctionCall %1 %45 %34
1888 %36 = OpAccessChain %13 %23 %17 %34
1889 OpStore %36 %35
1890 OpReturn
1891 OpFunctionEnd
1892 %37 = OpFunction %9 None %10
1893 %38 = OpLabel
1894 %39 = OpAccessChain %11 %28 %17
1895 %40 = OpAccessChain %12 %24 %17
1896 %41 = OpLoad %5 %40
1897 %42 = OpCompositeExtract %1 %41 0
1898 %43 = OpFunctionCall %1 %45 %42
1899 %44 = OpAccessChain %13 %23 %17 %42
1900 OpStore %44 %43
1901 OpReturn
1902 OpFunctionEnd
1903 %45 = OpFunction %1 Pure %14
1904 %46 = OpFunctionParameter %1
1905 %47 = OpLabel
1906 %48 = OpAccessChain %11 %28 %46
1907 %49 = OpLoad %1 %48
1908 OpReturnValue %49
1909 OpFunctionEnd
1910 )";
1911
1912 std::string recipient_shader = R"(
1913 OpCapability Shader
1914 %1 = OpExtInstImport "GLSL.std.450"
1915 OpMemoryModel Logical GLSL450
1916 OpEntryPoint Fragment %4 "main"
1917 OpExecutionMode %4 OriginUpperLeft
1918 OpSource ESSL 310
1919 %2 = OpTypeVoid
1920 %3 = OpTypeFunction %2
1921 %4 = OpFunction %2 None %3
1922 %5 = OpLabel
1923 OpReturn
1924 OpFunctionEnd
1925 )";
1926
1927 const auto env = SPV_ENV_UNIVERSAL_1_0;
1928 const auto consumer = nullptr;
1929 spvtools::ValidatorOptions validator_options;
1930
1931 const auto recipient_context =
1932 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
1933 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1934 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1935
1936 const auto donor_context =
1937 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
1938 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1939 donor_context.get(), validator_options, kConsoleMessageConsumer));
1940
1941 TransformationContext transformation_context(
1942 MakeUnique<FactManager>(recipient_context.get()), validator_options);
1943
1944 PseudoRandomGenerator rng(0);
1945 FuzzerContext fuzzer_context(&rng, 100);
1946 protobufs::TransformationSequence transformation_sequence;
1947
1948 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
1949 &transformation_context, &fuzzer_context,
1950 &transformation_sequence, {});
1951
1952 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
1953
1954 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1955 recipient_context.get(), validator_options, kConsoleMessageConsumer));
1956 }
1957
TEST(FuzzerPassDonateModulesTest,HandlesCapabilities)1958 TEST(FuzzerPassDonateModulesTest, HandlesCapabilities) {
1959 std::string donor_shader = R"(
1960 OpCapability VariablePointersStorageBuffer
1961 %1 = OpExtInstImport "GLSL.std.450"
1962 OpMemoryModel Logical GLSL450
1963 OpEntryPoint Fragment %4 "main"
1964 OpExecutionMode %4 OriginUpperLeft
1965 OpSource ESSL 310
1966 %2 = OpTypeVoid
1967 %3 = OpTypeFunction %2
1968 %6 = OpTypeFloat 32
1969 %11 = OpConstant %6 23
1970 %7 = OpTypePointer Function %6
1971 %4 = OpFunction %2 None %3
1972
1973 %5 = OpLabel
1974 %8 = OpVariable %7 Function
1975 OpBranch %9
1976
1977 %9 = OpLabel
1978 %10 = OpPhi %7 %8 %5
1979 OpStore %10 %11
1980 OpReturn
1981
1982 OpFunctionEnd
1983 )";
1984
1985 std::string recipient_shader = R"(
1986 OpCapability Shader
1987 %1 = OpExtInstImport "GLSL.std.450"
1988 OpMemoryModel Logical GLSL450
1989 OpEntryPoint Fragment %4 "main"
1990 OpExecutionMode %4 OriginUpperLeft
1991 OpSource ESSL 310
1992 %2 = OpTypeVoid
1993 %3 = OpTypeFunction %2
1994 %4 = OpFunction %2 None %3
1995 %5 = OpLabel
1996 OpReturn
1997 OpFunctionEnd
1998 )";
1999
2000 const auto env = SPV_ENV_UNIVERSAL_1_3;
2001 const auto consumer = nullptr;
2002 spvtools::ValidatorOptions validator_options;
2003
2004 const auto recipient_context =
2005 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
2006 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
2007 recipient_context.get(), validator_options, kConsoleMessageConsumer));
2008
2009 const auto donor_context =
2010 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
2011 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
2012 donor_context.get(), validator_options, kConsoleMessageConsumer));
2013
2014 TransformationContext transformation_context(
2015 MakeUnique<FactManager>(recipient_context.get()), validator_options);
2016
2017 PseudoRandomGenerator rng(0);
2018 FuzzerContext fuzzer_context(&rng, 100);
2019 protobufs::TransformationSequence transformation_sequence;
2020
2021 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
2022 &transformation_context, &fuzzer_context,
2023 &transformation_sequence, {});
2024
2025 ASSERT_TRUE(donor_context->get_feature_mgr()->HasCapability(
2026 SpvCapabilityVariablePointersStorageBuffer));
2027 ASSERT_FALSE(recipient_context->get_feature_mgr()->HasCapability(
2028 SpvCapabilityVariablePointersStorageBuffer));
2029
2030 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
2031
2032 // Check that recipient module hasn't changed.
2033 ASSERT_TRUE(IsEqual(env, recipient_shader, recipient_context.get()));
2034
2035 // Add the missing capability.
2036 //
2037 // We are adding VariablePointers to test the case when donor and recipient
2038 // have different OpCapability instructions but the same capabilities. In our
2039 // example, VariablePointers implicitly declares
2040 // VariablePointersStorageBuffer. Thus, two modules must be compatible.
2041 recipient_context->AddCapability(SpvCapabilityVariablePointers);
2042
2043 ASSERT_TRUE(donor_context->get_feature_mgr()->HasCapability(
2044 SpvCapabilityVariablePointersStorageBuffer));
2045 ASSERT_TRUE(recipient_context->get_feature_mgr()->HasCapability(
2046 SpvCapabilityVariablePointersStorageBuffer));
2047
2048 fuzzer_pass.DonateSingleModule(donor_context.get(), false);
2049
2050 // Check that donation was successful.
2051 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
2052 recipient_context.get(), validator_options, kConsoleMessageConsumer));
2053
2054 std::string after_transformation = R"(
2055 OpCapability Shader
2056 OpCapability VariablePointers
2057 %1 = OpExtInstImport "GLSL.std.450"
2058 OpMemoryModel Logical GLSL450
2059 OpEntryPoint Fragment %4 "main"
2060 OpExecutionMode %4 OriginUpperLeft
2061 OpSource ESSL 310
2062 %2 = OpTypeVoid
2063 %3 = OpTypeFunction %2
2064 %100 = OpTypeFloat 32
2065 %101 = OpConstant %100 23
2066 %102 = OpTypePointer Function %100
2067 %105 = OpConstant %100 0
2068 %4 = OpFunction %2 None %3
2069 %5 = OpLabel
2070 OpReturn
2071 OpFunctionEnd
2072 %103 = OpFunction %2 None %3
2073 %104 = OpLabel
2074 %106 = OpVariable %102 Function %105
2075 OpBranch %107
2076 %107 = OpLabel
2077 %108 = OpPhi %102 %106 %104
2078 OpStore %108 %101
2079 OpReturn
2080 OpFunctionEnd
2081 )";
2082
2083 ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get()));
2084 }
2085
TEST(FuzzerPassDonateModulesTest,HandlesOpPhisInMergeBlock)2086 TEST(FuzzerPassDonateModulesTest, HandlesOpPhisInMergeBlock) {
2087 std::string donor_shader = R"(
2088 ; OpPhis don't support pointers without this capability
2089 ; and we need pointers to test some of the functionality
2090 OpCapability VariablePointers
2091 OpCapability Shader
2092 %1 = OpExtInstImport "GLSL.std.450"
2093 OpMemoryModel Logical GLSL450
2094 OpEntryPoint Fragment %4 "main"
2095 OpExecutionMode %4 OriginUpperLeft
2096 OpSource ESSL 310
2097 %2 = OpTypeVoid
2098 %3 = OpTypeFunction %2
2099 %14 = OpTypeBool
2100 %15 = OpConstantTrue %14
2101 %42 = OpTypePointer Function %14
2102
2103 ; back-edge block is unreachable in the CFG
2104 %4 = OpFunction %2 None %3
2105 %5 = OpLabel
2106 OpBranch %6
2107 %6 = OpLabel
2108 OpLoopMerge %8 %7 None
2109 OpBranch %8
2110 %7 = OpLabel
2111 OpBranch %6
2112 %8 = OpLabel
2113 OpReturn
2114 OpFunctionEnd
2115
2116 ; back-edge block already has an edge to the merge block
2117 %9 = OpFunction %2 None %3
2118 %10 = OpLabel
2119 OpBranch %11
2120 %11 = OpLabel
2121 OpLoopMerge %13 %12 None
2122 OpBranch %12
2123 %12 = OpLabel
2124 OpBranchConditional %15 %11 %13
2125 %13 = OpLabel
2126 OpReturn
2127 OpFunctionEnd
2128
2129 ; merge block has no OpPhis
2130 %16 = OpFunction %2 None %3
2131 %17 = OpLabel
2132 OpBranch %18
2133 %18 = OpLabel
2134 OpLoopMerge %20 %19 None
2135 OpBranchConditional %15 %19 %20
2136 %19 = OpLabel
2137 OpBranch %18
2138 %20 = OpLabel
2139 OpReturn
2140 OpFunctionEnd
2141
2142 ; merge block has OpPhis and some of their operands are available at
2143 ; the back-edge block
2144 %21 = OpFunction %2 None %3
2145 %22 = OpLabel
2146 OpBranch %23
2147 %23 = OpLabel
2148 %24 = OpCopyObject %14 %15
2149 OpLoopMerge %28 %27 None
2150 OpBranchConditional %15 %25 %28
2151 %25 = OpLabel
2152 %26 = OpCopyObject %14 %15
2153 OpBranchConditional %15 %28 %27
2154 %27 = OpLabel
2155 OpBranch %23
2156 %28 = OpLabel
2157 %29 = OpPhi %14 %24 %23 %26 %25
2158 OpReturn
2159 OpFunctionEnd
2160
2161 ; none of the OpPhis' operands dominate the back-edge block but some of
2162 ; them have basic type
2163 %30 = OpFunction %2 None %3
2164 %31 = OpLabel
2165 OpBranch %32
2166 %32 = OpLabel
2167 OpLoopMerge %40 %39 None
2168 OpBranch %33
2169 %33 = OpLabel
2170 OpSelectionMerge %38 None
2171 OpBranchConditional %15 %34 %36
2172 %34 = OpLabel
2173 %35 = OpCopyObject %14 %15
2174 OpBranchConditional %35 %38 %40
2175 %36 = OpLabel
2176 %37 = OpCopyObject %14 %15
2177 OpBranchConditional %37 %38 %40
2178 %38 = OpLabel
2179 OpBranch %39
2180 %39 = OpLabel
2181 OpBranch %32
2182 %40 = OpLabel
2183 %41 = OpPhi %14 %35 %34 %37 %36
2184 OpReturn
2185 OpFunctionEnd
2186
2187 ; none of the OpPhis' operands dominate the back-edge block and none of
2188 ; them have basic type
2189 %43 = OpFunction %2 None %3
2190 %44 = OpLabel
2191 %45 = OpVariable %42 Function
2192 OpBranch %46
2193 %46 = OpLabel
2194 OpLoopMerge %54 %53 None
2195 OpBranch %47
2196 %47 = OpLabel
2197 OpSelectionMerge %52 None
2198 OpBranchConditional %15 %48 %50
2199 %48 = OpLabel
2200 %49 = OpCopyObject %42 %45
2201 OpBranchConditional %15 %52 %54
2202 %50 = OpLabel
2203 %51 = OpCopyObject %42 %45
2204 OpBranchConditional %15 %52 %54
2205 %52 = OpLabel
2206 OpBranch %53
2207 %53 = OpLabel
2208 OpBranch %46
2209 %54 = OpLabel
2210 %55 = OpPhi %42 %49 %48 %51 %50
2211 OpReturn
2212 OpFunctionEnd
2213 )";
2214
2215 std::string recipient_shader = R"(
2216 ; OpPhis don't support pointers without this capability
2217 ; and we need pointers to test some of the functionality
2218 OpCapability VariablePointers
2219 OpCapability Shader
2220 %1 = OpExtInstImport "GLSL.std.450"
2221 OpMemoryModel Logical GLSL450
2222 OpEntryPoint Fragment %4 "main"
2223 OpExecutionMode %4 OriginUpperLeft
2224 OpSource ESSL 310
2225 %2 = OpTypeVoid
2226 %3 = OpTypeFunction %2
2227 %4 = OpFunction %2 None %3
2228 %5 = OpLabel
2229 OpReturn
2230 OpFunctionEnd
2231 )";
2232
2233 const auto env = SPV_ENV_UNIVERSAL_1_3;
2234 const auto consumer = nullptr;
2235 spvtools::ValidatorOptions validator_options;
2236
2237 const auto recipient_context =
2238 BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
2239 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
2240 recipient_context.get(), validator_options, kConsoleMessageConsumer));
2241
2242 const auto donor_context =
2243 BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
2244 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
2245 donor_context.get(), validator_options, kConsoleMessageConsumer));
2246
2247 TransformationContext transformation_context(
2248 MakeUnique<FactManager>(recipient_context.get()), validator_options);
2249
2250 PseudoRandomGenerator prng(0);
2251 FuzzerContext fuzzer_context(&prng, 100);
2252 protobufs::TransformationSequence transformation_sequence;
2253
2254 FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
2255 &transformation_context, &fuzzer_context,
2256 &transformation_sequence, {});
2257
2258 fuzzer_pass.DonateSingleModule(donor_context.get(), true);
2259
2260 // We just check that the result is valid. Checking to what it should be
2261 // exactly equal to would be very fragile.
2262 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
2263 recipient_context.get(), validator_options, kConsoleMessageConsumer));
2264 }
2265
2266 } // namespace
2267 } // namespace fuzz
2268 } // namespace spvtools
2269