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