• 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 #include "test/fuzz/fuzz_test_util.h"
17 
18 namespace spvtools {
19 namespace fuzz {
20 namespace {
21 
TEST(TransformationAddGlobalVariableTest,BasicTest)22 TEST(TransformationAddGlobalVariableTest, BasicTest) {
23   std::string shader = R"(
24                OpCapability Shader
25           %1 = OpExtInstImport "GLSL.std.450"
26                OpMemoryModel Logical GLSL450
27                OpEntryPoint Fragment %4 "main"
28                OpExecutionMode %4 OriginUpperLeft
29                OpSource ESSL 310
30           %2 = OpTypeVoid
31           %3 = OpTypeFunction %2
32           %6 = OpTypeFloat 32
33          %40 = OpConstant %6 0
34           %7 = OpTypeInt 32 1
35           %8 = OpTypeVector %6 2
36          %41 = OpConstantComposite %8 %40 %40
37           %9 = OpTypePointer Function %6
38          %10 = OpTypePointer Private %6
39          %20 = OpTypePointer Uniform %6
40          %11 = OpTypePointer Function %7
41          %12 = OpTypePointer Private %7
42          %13 = OpTypePointer Private %8
43          %14 = OpVariable %10 Private
44          %15 = OpVariable %20 Uniform
45          %16 = OpConstant %7 1
46          %17 = OpTypePointer Private %10
47          %18 = OpTypeBool
48          %19 = OpTypePointer Private %18
49          %21 = OpConstantTrue %18
50          %22 = OpConstantFalse %18
51           %4 = OpFunction %2 None %3
52           %5 = OpLabel
53                OpReturn
54                OpFunctionEnd
55   )";
56 
57   const auto env = SPV_ENV_UNIVERSAL_1_3;
58   const auto consumer = nullptr;
59   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
60   ASSERT_TRUE(IsValid(env, context.get()));
61 
62   FactManager fact_manager;
63   spvtools::ValidatorOptions validator_options;
64   TransformationContext transformation_context(&fact_manager,
65                                                validator_options);
66 
67   // Id already in use
68   ASSERT_FALSE(
69       TransformationAddGlobalVariable(4, 10, SpvStorageClassPrivate, 0, true)
70           .IsApplicable(context.get(), transformation_context));
71   // %1 is not a type
72   ASSERT_FALSE(
73       TransformationAddGlobalVariable(100, 1, SpvStorageClassPrivate, 0, false)
74           .IsApplicable(context.get(), transformation_context));
75 
76   // %7 is not a pointer type
77   ASSERT_FALSE(
78       TransformationAddGlobalVariable(100, 7, SpvStorageClassPrivate, 0, true)
79           .IsApplicable(context.get(), transformation_context));
80 
81   // %9 does not have Private storage class
82   ASSERT_FALSE(
83       TransformationAddGlobalVariable(100, 9, SpvStorageClassPrivate, 0, false)
84           .IsApplicable(context.get(), transformation_context));
85 
86   // %15 does not have Private storage class
87   ASSERT_FALSE(
88       TransformationAddGlobalVariable(100, 15, SpvStorageClassPrivate, 0, true)
89           .IsApplicable(context.get(), transformation_context));
90 
91   // %10 is a pointer to float, while %16 is an int constant
92   ASSERT_FALSE(TransformationAddGlobalVariable(100, 10, SpvStorageClassPrivate,
93                                                16, false)
94                    .IsApplicable(context.get(), transformation_context));
95 
96   // %10 is a Private pointer to float, while %15 is a variable with type
97   // Uniform float pointer
98   ASSERT_FALSE(
99       TransformationAddGlobalVariable(100, 10, SpvStorageClassPrivate, 15, true)
100           .IsApplicable(context.get(), transformation_context));
101 
102   // %12 is a Private pointer to int, while %10 is a variable with type
103   // Private float pointer
104   ASSERT_FALSE(TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate,
105                                                10, false)
106                    .IsApplicable(context.get(), transformation_context));
107 
108   // %10 is pointer-to-float, and %14 has type pointer-to-float; that's not OK
109   // since the initializer's type should be the *pointee* type.
110   ASSERT_FALSE(
111       TransformationAddGlobalVariable(104, 10, SpvStorageClassPrivate, 14, true)
112           .IsApplicable(context.get(), transformation_context));
113 
114   // This would work in principle, but logical addressing does not allow
115   // a pointer to a pointer.
116   ASSERT_FALSE(TransformationAddGlobalVariable(104, 17, SpvStorageClassPrivate,
117                                                14, false)
118                    .IsApplicable(context.get(), transformation_context));
119 
120   TransformationAddGlobalVariable transformations[] = {
121       // %100 = OpVariable %12 Private
122       TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
123                                       true),
124 
125       // %101 = OpVariable %10 Private
126       TransformationAddGlobalVariable(101, 10, SpvStorageClassPrivate, 40,
127                                       false),
128 
129       // %102 = OpVariable %13 Private
130       TransformationAddGlobalVariable(102, 13, SpvStorageClassPrivate, 41,
131                                       true),
132 
133       // %103 = OpVariable %12 Private %16
134       TransformationAddGlobalVariable(103, 12, SpvStorageClassPrivate, 16,
135                                       false),
136 
137       // %104 = OpVariable %19 Private %21
138       TransformationAddGlobalVariable(104, 19, SpvStorageClassPrivate, 21,
139                                       true),
140 
141       // %105 = OpVariable %19 Private %22
142       TransformationAddGlobalVariable(105, 19, SpvStorageClassPrivate, 22,
143                                       false)};
144 
145   for (auto& transformation : transformations) {
146     ASSERT_TRUE(
147         transformation.IsApplicable(context.get(), transformation_context));
148     transformation.Apply(context.get(), &transformation_context);
149   }
150   ASSERT_TRUE(
151       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
152   ASSERT_TRUE(
153       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
154   ASSERT_TRUE(
155       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(104));
156   ASSERT_FALSE(
157       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
158   ASSERT_FALSE(
159       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(103));
160   ASSERT_FALSE(
161       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(105));
162 
163   ASSERT_TRUE(IsValid(env, context.get()));
164 
165   std::string after_transformation = R"(
166                OpCapability Shader
167           %1 = OpExtInstImport "GLSL.std.450"
168                OpMemoryModel Logical GLSL450
169                OpEntryPoint Fragment %4 "main"
170                OpExecutionMode %4 OriginUpperLeft
171                OpSource ESSL 310
172           %2 = OpTypeVoid
173           %3 = OpTypeFunction %2
174           %6 = OpTypeFloat 32
175          %40 = OpConstant %6 0
176           %7 = OpTypeInt 32 1
177           %8 = OpTypeVector %6 2
178          %41 = OpConstantComposite %8 %40 %40
179           %9 = OpTypePointer Function %6
180          %10 = OpTypePointer Private %6
181          %20 = OpTypePointer Uniform %6
182          %11 = OpTypePointer Function %7
183          %12 = OpTypePointer Private %7
184          %13 = OpTypePointer Private %8
185          %14 = OpVariable %10 Private
186          %15 = OpVariable %20 Uniform
187          %16 = OpConstant %7 1
188          %17 = OpTypePointer Private %10
189          %18 = OpTypeBool
190          %19 = OpTypePointer Private %18
191          %21 = OpConstantTrue %18
192          %22 = OpConstantFalse %18
193         %100 = OpVariable %12 Private %16
194         %101 = OpVariable %10 Private %40
195         %102 = OpVariable %13 Private %41
196         %103 = OpVariable %12 Private %16
197         %104 = OpVariable %19 Private %21
198         %105 = OpVariable %19 Private %22
199           %4 = OpFunction %2 None %3
200           %5 = OpLabel
201                OpReturn
202                OpFunctionEnd
203   )";
204   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
205 }
206 
TEST(TransformationAddGlobalVariableTest,TestEntryPointInterfaceEnlargement)207 TEST(TransformationAddGlobalVariableTest, TestEntryPointInterfaceEnlargement) {
208   // This checks that when global variables are added to a SPIR-V 1.4+ module,
209   // they are also added to entry points of that module.
210   std::string shader = R"(
211                OpCapability Shader
212           %1 = OpExtInstImport "GLSL.std.450"
213                OpMemoryModel Logical GLSL450
214                OpEntryPoint Fragment %4 "m1"
215                OpEntryPoint Vertex %5 "m2"
216                OpExecutionMode %4 OriginUpperLeft
217                OpSource ESSL 310
218           %2 = OpTypeVoid
219           %3 = OpTypeFunction %2
220           %6 = OpTypeFloat 32
221           %7 = OpTypeInt 32 1
222           %8 = OpTypeVector %6 2
223           %9 = OpTypePointer Function %6
224          %10 = OpTypePointer Private %6
225          %20 = OpTypePointer Uniform %6
226          %11 = OpTypePointer Function %7
227          %12 = OpTypePointer Private %7
228          %13 = OpTypePointer Private %8
229          %14 = OpVariable %10 Private
230          %15 = OpVariable %20 Uniform
231          %16 = OpConstant %7 1
232          %17 = OpTypePointer Private %10
233          %18 = OpTypeBool
234          %19 = OpTypePointer Private %18
235          %21 = OpConstantTrue %18
236           %4 = OpFunction %2 None %3
237          %30 = OpLabel
238                OpReturn
239                OpFunctionEnd
240           %5 = OpFunction %2 None %3
241          %31 = OpLabel
242                OpReturn
243                OpFunctionEnd
244   )";
245 
246   const auto env = SPV_ENV_UNIVERSAL_1_4;
247   const auto consumer = nullptr;
248   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
249   ASSERT_TRUE(IsValid(env, context.get()));
250 
251   FactManager fact_manager;
252   spvtools::ValidatorOptions validator_options;
253   TransformationContext transformation_context(&fact_manager,
254                                                validator_options);
255 
256   TransformationAddGlobalVariable transformations[] = {
257       // %100 = OpVariable %12 Private
258       TransformationAddGlobalVariable(100, 12, SpvStorageClassPrivate, 16,
259                                       true),
260 
261       // %101 = OpVariable %12 Private %16
262       TransformationAddGlobalVariable(101, 12, SpvStorageClassPrivate, 16,
263                                       false),
264 
265       // %102 = OpVariable %19 Private %21
266       TransformationAddGlobalVariable(102, 19, SpvStorageClassPrivate, 21,
267                                       true)};
268 
269   for (auto& transformation : transformations) {
270     ASSERT_TRUE(
271         transformation.IsApplicable(context.get(), transformation_context));
272     transformation.Apply(context.get(), &transformation_context);
273   }
274   ASSERT_TRUE(
275       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
276   ASSERT_TRUE(
277       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(102));
278   ASSERT_FALSE(
279       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
280   ASSERT_TRUE(IsValid(env, context.get()));
281 
282   std::string after_transformation = R"(
283                OpCapability Shader
284           %1 = OpExtInstImport "GLSL.std.450"
285                OpMemoryModel Logical GLSL450
286                OpEntryPoint Fragment %4 "m1" %100 %101 %102
287                OpEntryPoint Vertex %5 "m2" %100 %101 %102
288                OpExecutionMode %4 OriginUpperLeft
289                OpSource ESSL 310
290           %2 = OpTypeVoid
291           %3 = OpTypeFunction %2
292           %6 = OpTypeFloat 32
293           %7 = OpTypeInt 32 1
294           %8 = OpTypeVector %6 2
295           %9 = OpTypePointer Function %6
296          %10 = OpTypePointer Private %6
297          %20 = OpTypePointer Uniform %6
298          %11 = OpTypePointer Function %7
299          %12 = OpTypePointer Private %7
300          %13 = OpTypePointer Private %8
301          %14 = OpVariable %10 Private
302          %15 = OpVariable %20 Uniform
303          %16 = OpConstant %7 1
304          %17 = OpTypePointer Private %10
305          %18 = OpTypeBool
306          %19 = OpTypePointer Private %18
307          %21 = OpConstantTrue %18
308         %100 = OpVariable %12 Private %16
309         %101 = OpVariable %12 Private %16
310         %102 = OpVariable %19 Private %21
311           %4 = OpFunction %2 None %3
312          %30 = OpLabel
313                OpReturn
314                OpFunctionEnd
315           %5 = OpFunction %2 None %3
316          %31 = OpLabel
317                OpReturn
318                OpFunctionEnd
319   )";
320   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
321 }
322 
TEST(TransformationAddGlobalVariableTest,TestAddingWorkgroupGlobals)323 TEST(TransformationAddGlobalVariableTest, TestAddingWorkgroupGlobals) {
324   // This checks that workgroup globals can be added to a compute shader.
325   std::string shader = R"(
326                OpCapability Shader
327           %1 = OpExtInstImport "GLSL.std.450"
328                OpMemoryModel Logical GLSL450
329                OpEntryPoint GLCompute %4 "main"
330                OpExecutionMode %4 LocalSize 1 1 1
331                OpSource ESSL 310
332           %2 = OpTypeVoid
333           %3 = OpTypeFunction %2
334           %6 = OpTypeInt 32 1
335           %7 = OpTypePointer Workgroup %6
336          %50 = OpConstant %6 2
337           %4 = OpFunction %2 None %3
338           %5 = OpLabel
339                OpReturn
340                OpFunctionEnd
341   )";
342 
343   const auto env = SPV_ENV_UNIVERSAL_1_4;
344   const auto consumer = nullptr;
345   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
346   ASSERT_TRUE(IsValid(env, context.get()));
347 
348   FactManager fact_manager;
349   spvtools::ValidatorOptions validator_options;
350   TransformationContext transformation_context(&fact_manager,
351                                                validator_options);
352 
353 #ifndef NDEBUG
354   ASSERT_DEATH(
355       TransformationAddGlobalVariable(8, 7, SpvStorageClassWorkgroup, 50, true)
356           .IsApplicable(context.get(), transformation_context),
357       "By construction this transformation should not have an.*initializer "
358       "when Workgroup storage class is used");
359 #endif
360 
361   TransformationAddGlobalVariable transformations[] = {
362       // %8 = OpVariable %7 Workgroup
363       TransformationAddGlobalVariable(8, 7, SpvStorageClassWorkgroup, 0, true),
364 
365       // %10 = OpVariable %7 Workgroup
366       TransformationAddGlobalVariable(10, 7, SpvStorageClassWorkgroup, 0,
367                                       false)};
368 
369   for (auto& transformation : transformations) {
370     ASSERT_TRUE(
371         transformation.IsApplicable(context.get(), transformation_context));
372     transformation.Apply(context.get(), &transformation_context);
373   }
374   ASSERT_TRUE(
375       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(8));
376   ASSERT_FALSE(
377       transformation_context.GetFactManager()->PointeeValueIsIrrelevant(10));
378   ASSERT_TRUE(IsValid(env, context.get()));
379 
380   std::string after_transformation = R"(
381                OpCapability Shader
382           %1 = OpExtInstImport "GLSL.std.450"
383                OpMemoryModel Logical GLSL450
384                OpEntryPoint GLCompute %4 "main" %8 %10
385                OpExecutionMode %4 LocalSize 1 1 1
386                OpSource ESSL 310
387           %2 = OpTypeVoid
388           %3 = OpTypeFunction %2
389           %6 = OpTypeInt 32 1
390           %7 = OpTypePointer Workgroup %6
391          %50 = OpConstant %6 2
392           %8 = OpVariable %7 Workgroup
393          %10 = OpVariable %7 Workgroup
394           %4 = OpFunction %2 None %3
395           %5 = OpLabel
396                OpReturn
397                OpFunctionEnd
398   )";
399   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
400 }
401 
402 }  // namespace
403 }  // namespace fuzz
404 }  // namespace spvtools
405