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