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_constant_scalar.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(TransformationAddConstantScalarTest, IsApplicable)25 TEST(TransformationAddConstantScalarTest, IsApplicable) {
26   std::string reference_shader = R"(
27                OpCapability Shader
28                OpCapability Int64
29                OpCapability Float64
30           %1 = OpExtInstImport "GLSL.std.450"
31                OpMemoryModel Logical GLSL450
32                OpEntryPoint Vertex %17 "main"
33 
34 ; Types
35 
36   ; 32-bit types
37           %2 = OpTypeInt 32 0
38           %3 = OpTypeInt 32 1
39           %4 = OpTypeFloat 32
40 
41   ; 64-bit types
42           %5 = OpTypeInt 64 0
43           %6 = OpTypeInt 64 1
44           %7 = OpTypeFloat 64
45 
46           %8 = OpTypePointer Private %2
47           %9 = OpTypeVoid
48          %10 = OpTypeFunction %9
49 
50 ; Constants
51 
52   ; 32-bit constants
53          %11 = OpConstant %2 1
54          %12 = OpConstant %3 2
55          %13 = OpConstant %4 3
56 
57   ; 64-bit constants
58          %14 = OpConstant %5 1
59          %15 = OpConstant %6 2
60          %16 = OpConstant %7 3
61 
62 ; main function
63          %17 = OpFunction %9 None %10
64          %18 = OpLabel
65                OpReturn
66                OpFunctionEnd
67   )";
68 
69   const auto env = SPV_ENV_UNIVERSAL_1_3;
70   const auto consumer = nullptr;
71   const auto context =
72       BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
73   spvtools::ValidatorOptions validator_options;
74   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
75                                                kConsoleMessageConsumer));
76   TransformationContext transformation_context(
77       MakeUnique<FactManager>(context.get()), validator_options);
78   // Tests |fresh_id| being non-fresh.
79   auto transformation = TransformationAddConstantScalar(18, 2, {0}, false);
80   ASSERT_FALSE(
81       transformation.IsApplicable(context.get(), transformation_context));
82 
83   // Tests undefined |type_id|.
84   transformation = TransformationAddConstantScalar(19, 20, {0}, false);
85   ASSERT_FALSE(
86       transformation.IsApplicable(context.get(), transformation_context));
87 
88   // Tests |type_id| not representing a type instruction.
89   transformation = TransformationAddConstantScalar(19, 11, {0}, false);
90   ASSERT_FALSE(
91       transformation.IsApplicable(context.get(), transformation_context));
92 
93   // Tests |type_id| representing an OpTypePointer instruction.
94   transformation = TransformationAddConstantScalar(19, 8, {0}, false);
95   ASSERT_FALSE(
96       transformation.IsApplicable(context.get(), transformation_context));
97 
98   // Tests |type_id| representing an OpTypeVoid instruction.
99   transformation = TransformationAddConstantScalar(19, 9, {0}, false);
100   ASSERT_FALSE(
101       transformation.IsApplicable(context.get(), transformation_context));
102 
103   // Tests |words| having no words.
104   transformation = TransformationAddConstantScalar(19, 2, {}, false);
105   ASSERT_FALSE(
106       transformation.IsApplicable(context.get(), transformation_context));
107 
108   // Tests |words| having 2 words for a 32-bit type.
109   transformation = TransformationAddConstantScalar(19, 2, {0, 1}, false);
110   ASSERT_FALSE(
111       transformation.IsApplicable(context.get(), transformation_context));
112 
113   // Tests |words| having 3 words for a 64-bit type.
114   transformation = TransformationAddConstantScalar(19, 5, {0, 1, 2}, false);
115   ASSERT_FALSE(
116       transformation.IsApplicable(context.get(), transformation_context));
117 
118   // Tests |words| having 2 words for a 32-bit float type.
119   transformation = TransformationAddConstantScalar(19, 4, {0, 1}, false);
120   ASSERT_FALSE(
121       transformation.IsApplicable(context.get(), transformation_context));
122 }
123 
TEST(TransformationAddConstantScalarTest, Apply)124 TEST(TransformationAddConstantScalarTest, Apply) {
125   std::string reference_shader = R"(
126                OpCapability Shader
127                OpCapability Int64
128                OpCapability Float64
129           %1 = OpExtInstImport "GLSL.std.450"
130                OpMemoryModel Logical GLSL450
131                OpEntryPoint Vertex %17 "main"
132 
133 ; Types
134 
135   ; 32-bit types
136           %2 = OpTypeInt 32 0
137           %3 = OpTypeInt 32 1
138           %4 = OpTypeFloat 32
139 
140   ; 64-bit types
141           %5 = OpTypeInt 64 0
142           %6 = OpTypeInt 64 1
143           %7 = OpTypeFloat 64
144 
145           %8 = OpTypePointer Private %2
146           %9 = OpTypeVoid
147          %10 = OpTypeFunction %9
148 
149 ; Constants
150 
151   ; 32-bit constants
152          %11 = OpConstant %2 1
153          %12 = OpConstant %3 2
154          %13 = OpConstant %4 3
155 
156   ; 64-bit constants
157          %14 = OpConstant %5 1
158          %15 = OpConstant %6 2
159          %16 = OpConstant %7 3
160 
161 ; main function
162          %17 = OpFunction %9 None %10
163          %18 = OpLabel
164                OpReturn
165                OpFunctionEnd
166   )";
167 
168   const auto env = SPV_ENV_UNIVERSAL_1_3;
169   const auto consumer = nullptr;
170   const auto context =
171       BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
172   spvtools::ValidatorOptions validator_options;
173   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
174                                                kConsoleMessageConsumer));
175   TransformationContext transformation_context(
176       MakeUnique<FactManager>(context.get()), validator_options);
177   // Adds 32-bit unsigned integer (1 logical operand with 1 word).
178   auto transformation = TransformationAddConstantScalar(19, 2, {4}, false);
179   ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(19));
180   ASSERT_EQ(nullptr, context->get_constant_mgr()->FindDeclaredConstant(19));
181   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
182   ASSERT_EQ(spv::Op::OpConstant,
183             context->get_def_use_mgr()->GetDef(19)->opcode());
184   ASSERT_EQ(4, context->get_constant_mgr()->FindDeclaredConstant(19)->GetU32());
185   auto* constant_instruction = context->get_def_use_mgr()->GetDef(19);
186   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
187   EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
188   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
189                                                kConsoleMessageConsumer));
190 
191   // Adds 32-bit signed integer (1 logical operand with 1 word).
192   transformation = TransformationAddConstantScalar(20, 3, {5}, false);
193   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
194   constant_instruction = context->get_def_use_mgr()->GetDef(20);
195   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
196   EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
197   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
198                                                kConsoleMessageConsumer));
199 
200   // Adds 32-bit float (1 logical operand with 1 word).
201   transformation = TransformationAddConstantScalar(
202       21, 4, {0b01000000110000000000000000000000}, false);
203   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
204   constant_instruction = context->get_def_use_mgr()->GetDef(21);
205   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
206   EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
207   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
208                                                kConsoleMessageConsumer));
209 
210   // Adds 64-bit unsigned integer (1 logical operand with 2 words).
211   transformation = TransformationAddConstantScalar(22, 5, {7, 0}, false);
212   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
213   constant_instruction = context->get_def_use_mgr()->GetDef(22);
214   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
215   EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
216   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
217                                                kConsoleMessageConsumer));
218 
219   // Adds 64-bit signed integer (1 logical operand with 2 words).
220   transformation = TransformationAddConstantScalar(23, 6, {8, 0}, false);
221   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
222   constant_instruction = context->get_def_use_mgr()->GetDef(23);
223   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
224   EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
225   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
226                                                kConsoleMessageConsumer));
227 
228   // Adds 64-bit float (1 logical operand with 2 words).
229   transformation = TransformationAddConstantScalar(
230       24, 7, {0, 0b01000000001000100000000000000000}, false);
231   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
232   constant_instruction = context->get_def_use_mgr()->GetDef(24);
233   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
234   EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
235   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
236                                                kConsoleMessageConsumer));
237 
238   // Adds irrelevant 32-bit unsigned integer (1 logical operand with 1 word).
239   transformation = TransformationAddConstantScalar(25, 2, {10}, true);
240   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
241   constant_instruction = context->get_def_use_mgr()->GetDef(25);
242   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
243   EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
244   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
245                                                kConsoleMessageConsumer));
246 
247   // Adds irrelevant 32-bit signed integer (1 logical operand with 1 word).
248   transformation = TransformationAddConstantScalar(26, 3, {11}, true);
249   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
250   constant_instruction = context->get_def_use_mgr()->GetDef(26);
251   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
252   EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
253   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
254                                                kConsoleMessageConsumer));
255 
256   // Adds irrelevant 32-bit float (1 logical operand with 1 word).
257   transformation = TransformationAddConstantScalar(
258       27, 4, {0b01000001010000000000000000000000}, true);
259   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
260   constant_instruction = context->get_def_use_mgr()->GetDef(27);
261   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
262   EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
263   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
264                                                kConsoleMessageConsumer));
265 
266   // Adds irrelevant 64-bit unsigned integer (1 logical operand with 2 words).
267   transformation = TransformationAddConstantScalar(28, 5, {13, 0}, true);
268   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
269   constant_instruction = context->get_def_use_mgr()->GetDef(28);
270   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
271   EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
272   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
273                                                kConsoleMessageConsumer));
274 
275   // Adds irrelevant 64-bit signed integer (1 logical operand with 2 words).
276   transformation = TransformationAddConstantScalar(29, 6, {14, 0}, true);
277   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
278   constant_instruction = context->get_def_use_mgr()->GetDef(29);
279   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
280   EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
281   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
282                                                kConsoleMessageConsumer));
283 
284   // Adds irrelevant 64-bit float (1 logical operand with 2 words).
285   transformation = TransformationAddConstantScalar(
286       30, 7, {0, 0b01000000001011100000000000000000}, true);
287   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
288   constant_instruction = context->get_def_use_mgr()->GetDef(30);
289   EXPECT_EQ(constant_instruction->NumInOperands(), 1);
290   EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
291   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
292                                                kConsoleMessageConsumer));
293 
294   for (uint32_t result_id = 19; result_id <= 24; ++result_id) {
295     ASSERT_FALSE(
296         transformation_context.GetFactManager()->IdIsIrrelevant(result_id));
297   }
298 
299   for (uint32_t result_id = 25; result_id <= 30; ++result_id) {
300     ASSERT_TRUE(
301         transformation_context.GetFactManager()->IdIsIrrelevant(result_id));
302   }
303 
304   std::string variant_shader = R"(
305                OpCapability Shader
306                OpCapability Int64
307                OpCapability Float64
308           %1 = OpExtInstImport "GLSL.std.450"
309                OpMemoryModel Logical GLSL450
310                OpEntryPoint Vertex %17 "main"
311 
312 ; Types
313 
314   ; 32-bit types
315           %2 = OpTypeInt 32 0
316           %3 = OpTypeInt 32 1
317           %4 = OpTypeFloat 32
318 
319   ; 64-bit types
320           %5 = OpTypeInt 64 0
321           %6 = OpTypeInt 64 1
322           %7 = OpTypeFloat 64
323 
324           %8 = OpTypePointer Private %2
325           %9 = OpTypeVoid
326          %10 = OpTypeFunction %9
327 
328 ; Constants
329 
330   ; 32-bit constants
331          %11 = OpConstant %2 1
332          %12 = OpConstant %3 2
333          %13 = OpConstant %4 3
334 
335   ; 64-bit constants
336          %14 = OpConstant %5 1
337          %15 = OpConstant %6 2
338          %16 = OpConstant %7 3
339 
340   ; added constants
341          %19 = OpConstant %2 4
342          %20 = OpConstant %3 5
343          %21 = OpConstant %4 6
344          %22 = OpConstant %5 7
345          %23 = OpConstant %6 8
346          %24 = OpConstant %7 9
347          %25 = OpConstant %2 10
348          %26 = OpConstant %3 11
349          %27 = OpConstant %4 12
350          %28 = OpConstant %5 13
351          %29 = OpConstant %6 14
352          %30 = OpConstant %7 15
353 
354 ; main function
355          %17 = OpFunction %9 None %10
356          %18 = OpLabel
357                OpReturn
358                OpFunctionEnd
359   )";
360 
361   ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
362 }
363 
364 }  // namespace
365 }  // namespace fuzz
366 }  // namespace spvtools
367