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