• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "source/fuzz/transformation_add_global_variable.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "test/fuzz/fuzz_test_util.h"
20 
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24 
TEST(TransformationAddGlobalVariableTest,BasicTest)25 TEST(TransformationAddGlobalVariableTest, BasicTest) {
26   std::string shader = R"(
27                OpCapability Shader
28           %1 = OpExtInstImport "GLSL.std.450"
29                OpMemoryModel Logical GLSL450
30                OpEntryPoint Fragment %4 "main"
31                OpExecutionMode %4 OriginUpperLeft
32                OpSource ESSL 310
33           %2 = OpTypeVoid
34           %3 = OpTypeFunction %2
35           %6 = OpTypeFloat 32
36          %40 = OpConstant %6 0
37           %7 = OpTypeInt 32 1
38           %8 = OpTypeVector %6 2
39          %41 = OpConstantComposite %8 %40 %40
40           %9 = OpTypePointer Function %6
41          %10 = OpTypePointer Private %6
42          %20 = OpTypePointer Uniform %6
43          %11 = OpTypePointer Function %7
44          %12 = OpTypePointer Private %7
45          %13 = OpTypePointer Private %8
46          %14 = OpVariable %10 Private
47          %15 = OpVariable %20 Uniform
48          %16 = OpConstant %7 1
49          %17 = OpTypePointer Private %10
50          %18 = OpTypeBool
51          %19 = OpTypePointer Private %18
52          %21 = OpConstantTrue %18
53          %22 = OpConstantFalse %18
54           %4 = OpFunction %2 None %3
55           %5 = OpLabel
56                OpReturn
57                OpFunctionEnd
58   )";
59 
60   const auto env = SPV_ENV_UNIVERSAL_1_3;
61   const auto consumer = nullptr;
62   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
63   spvtools::ValidatorOptions validator_options;
64   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
65                                                kConsoleMessageConsumer));
66   TransformationContext transformation_context(
67       MakeUnique<FactManager>(context.get()), validator_options);
68   // Id already in use
69   ASSERT_FALSE(
70       TransformationAddGlobalVariable(4, 10, SpvStorageClassPrivate, 0, true)
71           .IsApplicable(context.get(), transformation_context));
72   // %1 is not a type
73   ASSERT_FALSE(
74       TransformationAddGlobalVariable(100, 1, SpvStorageClassPrivate, 0, false)
75           .IsApplicable(context.get(), transformation_context));
76 
77   // %7 is not a pointer type
78   ASSERT_FALSE(
79       TransformationAddGlobalVariable(100, 7, SpvStorageClassPrivate, 0, true)
80           .IsApplicable(context.get(), transformation_context));
81 
82   // %9 does not have Private storage class
83   ASSERT_FALSE(
84       TransformationAddGlobalVariable(100, 9, SpvStorageClassPrivate, 0, false)
85           .IsApplicable(context.get(), transformation_context));
86 
87   // %15 does not have Private storage class
88   ASSERT_FALSE(
89       TransformationAddGlobalVariable(100, 15, SpvStorageClassPrivate, 0, true)
90           .IsApplicable(context.get(), transformation_context));
91 
92   // %10 is a pointer to float, while %16 is an int constant
93   ASSERT_FALSE(TransformationAddGlobalVariable(100, 10, SpvStorageClassPrivate,
94                                                16, false)
95                    .IsApplicable(context.get(), transformation_context));
96 
97   // %10 is a Private pointer to float, while %15 is a variable with type
98   // Uniform float pointer
99   ASSERT_FALSE(
100       TransformationAddGlobalVariable(100, 10, SpvStorageClassPrivate, 15, true)
101           .IsApplicable(context.get(), transformation_context));
102 
103   // %12 is a Private pointer to int, while %10 is a variable with type
104   // Private float pointer
105   ASSERT_FALSE(TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate,
106                                                10, false)
107                    .IsApplicable(context.get(), transformation_context));
108 
109   // %10 is pointer-to-float, and %14 has type pointer-to-float; that's not OK
110   // since the initializer's type should be the *pointee* type.
111   ASSERT_FALSE(
112       TransformationAddGlobalVariable(104, 10, SpvStorageClassPrivate, 14, true)
113           .IsApplicable(context.get(), transformation_context));
114 
115   // This would work in principle, but logical addressing does not allow
116   // a pointer to a pointer.
117   ASSERT_FALSE(TransformationAddGlobalVariable(104, 17, SpvStorageClassPrivate,
118                                                14, false)
119                    .IsApplicable(context.get(), transformation_context));
120 
121   {
122     // %100 = OpVariable %12 Private
123     ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(100));
124     TransformationAddGlobalVariable transformation(
125         100, 12, SpvStorageClassPrivate, 16, true);
126     ASSERT_TRUE(
127         transformation.IsApplicable(context.get(), transformation_context));
128     ApplyAndCheckFreshIds(transformation, context.get(),
129                           &transformation_context);
130     ASSERT_EQ(SpvOpVariable, context->get_def_use_mgr()->GetDef(100)->opcode());
131     ASSERT_EQ(
132         SpvStorageClassPrivate,
133         static_cast<SpvStorageClass>(
134             context->get_def_use_mgr()->GetDef(100)->GetSingleWordInOperand(
135                 0)));
136   }
137 
138   TransformationAddGlobalVariable transformations[] = {
139       // %101 = OpVariable %10 Private
140       TransformationAddGlobalVariable(101, 10, SpvStorageClassPrivate, 40,
141                                       false),
142 
143       // %102 = OpVariable %13 Private
144       TransformationAddGlobalVariable(102, 13, SpvStorageClassPrivate, 41,
145                                       true),
146 
147       // %103 = OpVariable %12 Private %16
148       TransformationAddGlobalVariable(103, 12, SpvStorageClassPrivate, 16,
149                                       false),
150 
151       // %104 = OpVariable %19 Private %21
152       TransformationAddGlobalVariable(104, 19, SpvStorageClassPrivate, 21,
153                                       true),
154 
155       // %105 = OpVariable %19 Private %22
156       TransformationAddGlobalVariable(105, 19, SpvStorageClassPrivate, 22,
157                                       false)};
158 
159   for (auto& transformation : transformations) {
160     ASSERT_TRUE(
161         transformation.IsApplicable(context.get(), transformation_context));
162     ApplyAndCheckFreshIds(transformation, context.get(),
163                           &transformation_context);
164   }
165   ASSERT_TRUE(
166       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
167   ASSERT_TRUE(
168       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
169   ASSERT_TRUE(
170       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(104));
171   ASSERT_FALSE(
172       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
173   ASSERT_FALSE(
174       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(103));
175   ASSERT_FALSE(
176       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(105));
177 
178   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
179                                                kConsoleMessageConsumer));
180 
181   std::string after_transformation = R"(
182                OpCapability Shader
183           %1 = OpExtInstImport "GLSL.std.450"
184                OpMemoryModel Logical GLSL450
185                OpEntryPoint Fragment %4 "main"
186                OpExecutionMode %4 OriginUpperLeft
187                OpSource ESSL 310
188           %2 = OpTypeVoid
189           %3 = OpTypeFunction %2
190           %6 = OpTypeFloat 32
191          %40 = OpConstant %6 0
192           %7 = OpTypeInt 32 1
193           %8 = OpTypeVector %6 2
194          %41 = OpConstantComposite %8 %40 %40
195           %9 = OpTypePointer Function %6
196          %10 = OpTypePointer Private %6
197          %20 = OpTypePointer Uniform %6
198          %11 = OpTypePointer Function %7
199          %12 = OpTypePointer Private %7
200          %13 = OpTypePointer Private %8
201          %14 = OpVariable %10 Private
202          %15 = OpVariable %20 Uniform
203          %16 = OpConstant %7 1
204          %17 = OpTypePointer Private %10
205          %18 = OpTypeBool
206          %19 = OpTypePointer Private %18
207          %21 = OpConstantTrue %18
208          %22 = OpConstantFalse %18
209         %100 = OpVariable %12 Private %16
210         %101 = OpVariable %10 Private %40
211         %102 = OpVariable %13 Private %41
212         %103 = OpVariable %12 Private %16
213         %104 = OpVariable %19 Private %21
214         %105 = OpVariable %19 Private %22
215           %4 = OpFunction %2 None %3
216           %5 = OpLabel
217                OpReturn
218                OpFunctionEnd
219   )";
220   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
221 }
222 
TEST(TransformationAddGlobalVariableTest,TestEntryPointInterfaceEnlargement)223 TEST(TransformationAddGlobalVariableTest, TestEntryPointInterfaceEnlargement) {
224   // This checks that when global variables are added to a SPIR-V 1.4+ module,
225   // they are also added to entry points of that module.
226   std::string shader = R"(
227                OpCapability Shader
228           %1 = OpExtInstImport "GLSL.std.450"
229                OpMemoryModel Logical GLSL450
230                OpEntryPoint Fragment %4 "m1"
231                OpEntryPoint Vertex %5 "m2"
232                OpExecutionMode %4 OriginUpperLeft
233                OpSource ESSL 310
234           %2 = OpTypeVoid
235           %3 = OpTypeFunction %2
236           %6 = OpTypeFloat 32
237           %7 = OpTypeInt 32 1
238           %8 = OpTypeVector %6 2
239           %9 = OpTypePointer Function %6
240          %10 = OpTypePointer Private %6
241          %11 = OpTypePointer Function %7
242          %12 = OpTypePointer Private %7
243          %13 = OpTypePointer Private %8
244          %14 = OpVariable %10 Private
245          %16 = OpConstant %7 1
246          %17 = OpTypePointer Private %10
247          %18 = OpTypeBool
248          %19 = OpTypePointer Private %18
249          %21 = OpConstantTrue %18
250           %4 = OpFunction %2 None %3
251          %30 = OpLabel
252                OpReturn
253                OpFunctionEnd
254           %5 = OpFunction %2 None %3
255          %31 = OpLabel
256                OpReturn
257                OpFunctionEnd
258   )";
259 
260   for (auto env : {SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
261                    SPV_ENV_VULKAN_1_1_SPIRV_1_4, SPV_ENV_VULKAN_1_2}) {
262     const auto consumer = nullptr;
263     const auto context =
264         BuildModule(env, consumer, shader, kFuzzAssembleOption);
265     spvtools::ValidatorOptions validator_options;
266     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
267         context.get(), validator_options, kConsoleMessageConsumer));
268     TransformationContext transformation_context(
269         MakeUnique<FactManager>(context.get()), validator_options);
270     TransformationAddGlobalVariable transformations[] = {
271         // %100 = OpVariable %12 Private
272         TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
273                                         true),
274 
275         // %101 = OpVariable %12 Private %16
276         TransformationAddGlobalVariable(101, 12, SpvStorageClassPrivate, 16,
277                                         false),
278 
279         // %102 = OpVariable %19 Private %21
280         TransformationAddGlobalVariable(102, 19, SpvStorageClassPrivate, 21,
281                                         true)};
282 
283     for (auto& transformation : transformations) {
284       ASSERT_TRUE(
285           transformation.IsApplicable(context.get(), transformation_context));
286       ApplyAndCheckFreshIds(transformation, context.get(),
287                             &transformation_context);
288     }
289     ASSERT_TRUE(
290         transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
291     ASSERT_TRUE(
292         transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
293     ASSERT_FALSE(
294         transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
295     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
296         context.get(), validator_options, kConsoleMessageConsumer));
297 
298     std::string after_transformation_enlarged_interface = R"(
299                  OpCapability Shader
300             %1 = OpExtInstImport "GLSL.std.450"
301                  OpMemoryModel Logical GLSL450
302                  OpEntryPoint Fragment %4 "m1" %100 %101 %102
303                  OpEntryPoint Vertex %5 "m2" %100 %101 %102
304                  OpExecutionMode %4 OriginUpperLeft
305                  OpSource ESSL 310
306             %2 = OpTypeVoid
307             %3 = OpTypeFunction %2
308             %6 = OpTypeFloat 32
309             %7 = OpTypeInt 32 1
310             %8 = OpTypeVector %6 2
311             %9 = OpTypePointer Function %6
312            %10 = OpTypePointer Private %6
313            %11 = OpTypePointer Function %7
314            %12 = OpTypePointer Private %7
315            %13 = OpTypePointer Private %8
316            %14 = OpVariable %10 Private
317            %16 = OpConstant %7 1
318            %17 = OpTypePointer Private %10
319            %18 = OpTypeBool
320            %19 = OpTypePointer Private %18
321            %21 = OpConstantTrue %18
322           %100 = OpVariable %12 Private %16
323           %101 = OpVariable %12 Private %16
324           %102 = OpVariable %19 Private %21
325             %4 = OpFunction %2 None %3
326            %30 = OpLabel
327                  OpReturn
328                  OpFunctionEnd
329             %5 = OpFunction %2 None %3
330            %31 = OpLabel
331                  OpReturn
332                  OpFunctionEnd
333     )";
334 
335     ASSERT_TRUE(
336         IsEqual(env, after_transformation_enlarged_interface, context.get()));
337   }
338 }
339 
TEST(TransformationAddGlobalVariableTest,TestEntryPointInterfaceNoEnlargement)340 TEST(TransformationAddGlobalVariableTest,
341      TestEntryPointInterfaceNoEnlargement) {
342   // This checks that when global variables are added to a SPIR-V 1.3- module,
343   // they are not added to entry points of that module.
344   std::string shader = R"(
345                OpCapability Shader
346           %1 = OpExtInstImport "GLSL.std.450"
347                OpMemoryModel Logical GLSL450
348                OpEntryPoint Fragment %4 "m1"
349                OpEntryPoint Vertex %5 "m2"
350                OpExecutionMode %4 OriginUpperLeft
351                OpSource ESSL 310
352           %2 = OpTypeVoid
353           %3 = OpTypeFunction %2
354           %6 = OpTypeFloat 32
355           %7 = OpTypeInt 32 1
356           %8 = OpTypeVector %6 2
357           %9 = OpTypePointer Function %6
358          %10 = OpTypePointer Private %6
359          %11 = OpTypePointer Function %7
360          %12 = OpTypePointer Private %7
361          %13 = OpTypePointer Private %8
362          %14 = OpVariable %10 Private
363          %16 = OpConstant %7 1
364          %17 = OpTypePointer Private %10
365          %18 = OpTypeBool
366          %19 = OpTypePointer Private %18
367          %21 = OpConstantTrue %18
368           %4 = OpFunction %2 None %3
369          %30 = OpLabel
370                OpReturn
371                OpFunctionEnd
372           %5 = OpFunction %2 None %3
373          %31 = OpLabel
374                OpReturn
375                OpFunctionEnd
376   )";
377 
378   for (auto env :
379        {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
380         SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
381     const auto consumer = nullptr;
382     const auto context =
383         BuildModule(env, consumer, shader, kFuzzAssembleOption);
384     spvtools::ValidatorOptions validator_options;
385     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
386         context.get(), validator_options, kConsoleMessageConsumer));
387     TransformationContext transformation_context(
388         MakeUnique<FactManager>(context.get()), validator_options);
389     TransformationAddGlobalVariable transformations[] = {
390         // %100 = OpVariable %12 Private
391         TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
392                                         true),
393 
394         // %101 = OpVariable %12 Private %16
395         TransformationAddGlobalVariable(101, 12, SpvStorageClassPrivate, 16,
396                                         false),
397 
398         // %102 = OpVariable %19 Private %21
399         TransformationAddGlobalVariable(102, 19, SpvStorageClassPrivate, 21,
400                                         true)};
401 
402     for (auto& transformation : transformations) {
403       ASSERT_TRUE(
404           transformation.IsApplicable(context.get(), transformation_context));
405       ApplyAndCheckFreshIds(transformation, context.get(),
406                             &transformation_context);
407     }
408     ASSERT_TRUE(
409         transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
410     ASSERT_TRUE(
411         transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
412     ASSERT_FALSE(
413         transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
414     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
415         context.get(), validator_options, kConsoleMessageConsumer));
416 
417     std::string after_transformation_fixed_interface = R"(
418                  OpCapability Shader
419             %1 = OpExtInstImport "GLSL.std.450"
420                  OpMemoryModel Logical GLSL450
421                  OpEntryPoint Fragment %4 "m1"
422                  OpEntryPoint Vertex %5 "m2"
423                  OpExecutionMode %4 OriginUpperLeft
424                  OpSource ESSL 310
425             %2 = OpTypeVoid
426             %3 = OpTypeFunction %2
427             %6 = OpTypeFloat 32
428             %7 = OpTypeInt 32 1
429             %8 = OpTypeVector %6 2
430             %9 = OpTypePointer Function %6
431            %10 = OpTypePointer Private %6
432            %11 = OpTypePointer Function %7
433            %12 = OpTypePointer Private %7
434            %13 = OpTypePointer Private %8
435            %14 = OpVariable %10 Private
436            %16 = OpConstant %7 1
437            %17 = OpTypePointer Private %10
438            %18 = OpTypeBool
439            %19 = OpTypePointer Private %18
440            %21 = OpConstantTrue %18
441           %100 = OpVariable %12 Private %16
442           %101 = OpVariable %12 Private %16
443           %102 = OpVariable %19 Private %21
444             %4 = OpFunction %2 None %3
445            %30 = OpLabel
446                  OpReturn
447                  OpFunctionEnd
448             %5 = OpFunction %2 None %3
449            %31 = OpLabel
450                  OpReturn
451                  OpFunctionEnd
452     )";
453 
454     ASSERT_TRUE(
455         IsEqual(env, after_transformation_fixed_interface, context.get()));
456   }
457 }
458 
TEST(TransformationAddGlobalVariableTest,TestAddingWorkgroupGlobals)459 TEST(TransformationAddGlobalVariableTest, TestAddingWorkgroupGlobals) {
460   // This checks that workgroup globals can be added to a compute shader.
461   std::string shader = R"(
462                OpCapability Shader
463           %1 = OpExtInstImport "GLSL.std.450"
464                OpMemoryModel Logical GLSL450
465                OpEntryPoint GLCompute %4 "main"
466                OpExecutionMode %4 LocalSize 1 1 1
467                OpSource ESSL 310
468           %2 = OpTypeVoid
469           %3 = OpTypeFunction %2
470           %6 = OpTypeInt 32 1
471           %7 = OpTypePointer Workgroup %6
472          %50 = OpConstant %6 2
473           %4 = OpFunction %2 None %3
474           %5 = OpLabel
475                OpReturn
476                OpFunctionEnd
477   )";
478 
479   const auto env = SPV_ENV_UNIVERSAL_1_4;
480   const auto consumer = nullptr;
481   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
482   spvtools::ValidatorOptions validator_options;
483   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
484                                                kConsoleMessageConsumer));
485   TransformationContext transformation_context(
486       MakeUnique<FactManager>(context.get()), validator_options);
487 #ifndef NDEBUG
488   ASSERT_DEATH(
489       TransformationAddGlobalVariable(8, 7, SpvStorageClassWorkgroup, 50, true)
490           .IsApplicable(context.get(), transformation_context),
491       "By construction this transformation should not have an.*initializer "
492       "when Workgroup storage class is used");
493 #endif
494 
495   TransformationAddGlobalVariable transformations[] = {
496       // %8 = OpVariable %7 Workgroup
497       TransformationAddGlobalVariable(8, 7, SpvStorageClassWorkgroup, 0, true),
498 
499       // %10 = OpVariable %7 Workgroup
500       TransformationAddGlobalVariable(10, 7, SpvStorageClassWorkgroup, 0,
501                                       false)};
502 
503   for (auto& transformation : transformations) {
504     ASSERT_TRUE(
505         transformation.IsApplicable(context.get(), transformation_context));
506     ApplyAndCheckFreshIds(transformation, context.get(),
507                           &transformation_context);
508   }
509   ASSERT_TRUE(
510       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(8));
511   ASSERT_FALSE(
512       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(10));
513   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
514                                                kConsoleMessageConsumer));
515 
516   std::string after_transformation = R"(
517                OpCapability Shader
518           %1 = OpExtInstImport "GLSL.std.450"
519                OpMemoryModel Logical GLSL450
520                OpEntryPoint GLCompute %4 "main" %8 %10
521                OpExecutionMode %4 LocalSize 1 1 1
522                OpSource ESSL 310
523           %2 = OpTypeVoid
524           %3 = OpTypeFunction %2
525           %6 = OpTypeInt 32 1
526           %7 = OpTypePointer Workgroup %6
527          %50 = OpConstant %6 2
528           %8 = OpVariable %7 Workgroup
529          %10 = OpVariable %7 Workgroup
530           %4 = OpFunction %2 None %3
531           %5 = OpLabel
532                OpReturn
533                OpFunctionEnd
534   )";
535   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
536 }
537 
538 }  // namespace
539 }  // namespace fuzz
540 }  // namespace spvtools
541