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
23namespace spvtools {
24namespace fuzz {
25namespace {
26
27TEST(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
223TEST(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
373TEST(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
471TEST(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
530TEST(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
602TEST(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
730TEST(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
826TEST(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
958TEST(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
1094TEST(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
1176TEST(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
1263TEST(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
1367TEST(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
1439TEST(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
1549TEST(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
1733TEST(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
1834TEST(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
1960TEST(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
2088TEST(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