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
TEST(TransformationAddConstantScalarTest,Apply)119 TEST(TransformationAddConstantScalarTest, Apply) {
120 std::string reference_shader = R"(
121 OpCapability Shader
122 OpCapability Int64
123 OpCapability Float64
124 %1 = OpExtInstImport "GLSL.std.450"
125 OpMemoryModel Logical GLSL450
126 OpEntryPoint Vertex %17 "main"
127
128 ; Types
129
130 ; 32-bit types
131 %2 = OpTypeInt 32 0
132 %3 = OpTypeInt 32 1
133 %4 = OpTypeFloat 32
134
135 ; 64-bit types
136 %5 = OpTypeInt 64 0
137 %6 = OpTypeInt 64 1
138 %7 = OpTypeFloat 64
139
140 %8 = OpTypePointer Private %2
141 %9 = OpTypeVoid
142 %10 = OpTypeFunction %9
143
144 ; Constants
145
146 ; 32-bit constants
147 %11 = OpConstant %2 1
148 %12 = OpConstant %3 2
149 %13 = OpConstant %4 3
150
151 ; 64-bit constants
152 %14 = OpConstant %5 1
153 %15 = OpConstant %6 2
154 %16 = OpConstant %7 3
155
156 ; main function
157 %17 = OpFunction %9 None %10
158 %18 = OpLabel
159 OpReturn
160 OpFunctionEnd
161 )";
162
163 const auto env = SPV_ENV_UNIVERSAL_1_3;
164 const auto consumer = nullptr;
165 const auto context =
166 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
167 spvtools::ValidatorOptions validator_options;
168 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
169 kConsoleMessageConsumer));
170 TransformationContext transformation_context(
171 MakeUnique<FactManager>(context.get()), validator_options);
172 // Adds 32-bit unsigned integer (1 logical operand with 1 word).
173 auto transformation = TransformationAddConstantScalar(19, 2, {4}, false);
174 ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(19));
175 ASSERT_EQ(nullptr, context->get_constant_mgr()->FindDeclaredConstant(19));
176 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
177 ASSERT_EQ(SpvOpConstant, context->get_def_use_mgr()->GetDef(19)->opcode());
178 ASSERT_EQ(4, context->get_constant_mgr()->FindDeclaredConstant(19)->GetU32());
179 auto* constant_instruction = context->get_def_use_mgr()->GetDef(19);
180 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
181 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
182 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
183 kConsoleMessageConsumer));
184
185 // Adds 32-bit signed integer (1 logical operand with 1 word).
186 transformation = TransformationAddConstantScalar(20, 3, {5}, false);
187 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
188 constant_instruction = context->get_def_use_mgr()->GetDef(20);
189 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
190 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
191 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
192 kConsoleMessageConsumer));
193
194 // Adds 32-bit float (1 logical operand with 1 word).
195 transformation = TransformationAddConstantScalar(
196 21, 4, {0b01000000110000000000000000000000}, false);
197 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
198 constant_instruction = context->get_def_use_mgr()->GetDef(21);
199 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
200 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
201 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
202 kConsoleMessageConsumer));
203
204 // Adds 64-bit unsigned integer (1 logical operand with 2 words).
205 transformation = TransformationAddConstantScalar(22, 5, {7, 0}, false);
206 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
207 constant_instruction = context->get_def_use_mgr()->GetDef(22);
208 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
209 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
210 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
211 kConsoleMessageConsumer));
212
213 // Adds 64-bit signed integer (1 logical operand with 2 words).
214 transformation = TransformationAddConstantScalar(23, 6, {8, 0}, false);
215 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
216 constant_instruction = context->get_def_use_mgr()->GetDef(23);
217 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
218 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
219 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
220 kConsoleMessageConsumer));
221
222 // Adds 64-bit float (1 logical operand with 2 words).
223 transformation = TransformationAddConstantScalar(
224 24, 7, {0, 0b01000000001000100000000000000000}, false);
225 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
226 constant_instruction = context->get_def_use_mgr()->GetDef(24);
227 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
228 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
229 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
230 kConsoleMessageConsumer));
231
232 // Adds irrelevant 32-bit unsigned integer (1 logical operand with 1 word).
233 transformation = TransformationAddConstantScalar(25, 2, {10}, true);
234 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
235 constant_instruction = context->get_def_use_mgr()->GetDef(25);
236 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
237 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
238 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
239 kConsoleMessageConsumer));
240
241 // Adds irrelevant 32-bit signed integer (1 logical operand with 1 word).
242 transformation = TransformationAddConstantScalar(26, 3, {11}, true);
243 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
244 constant_instruction = context->get_def_use_mgr()->GetDef(26);
245 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
246 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
247 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
248 kConsoleMessageConsumer));
249
250 // Adds irrelevant 32-bit float (1 logical operand with 1 word).
251 transformation = TransformationAddConstantScalar(
252 27, 4, {0b01000001010000000000000000000000}, true);
253 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
254 constant_instruction = context->get_def_use_mgr()->GetDef(27);
255 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
256 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
257 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
258 kConsoleMessageConsumer));
259
260 // Adds irrelevant 64-bit unsigned integer (1 logical operand with 2 words).
261 transformation = TransformationAddConstantScalar(28, 5, {13, 0}, true);
262 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
263 constant_instruction = context->get_def_use_mgr()->GetDef(28);
264 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
265 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
266 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
267 kConsoleMessageConsumer));
268
269 // Adds irrelevant 64-bit signed integer (1 logical operand with 2 words).
270 transformation = TransformationAddConstantScalar(29, 6, {14, 0}, true);
271 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
272 constant_instruction = context->get_def_use_mgr()->GetDef(29);
273 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
274 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
275 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
276 kConsoleMessageConsumer));
277
278 // Adds irrelevant 64-bit float (1 logical operand with 2 words).
279 transformation = TransformationAddConstantScalar(
280 30, 7, {0, 0b01000000001011100000000000000000}, true);
281 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
282 constant_instruction = context->get_def_use_mgr()->GetDef(30);
283 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
284 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
285 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
286 kConsoleMessageConsumer));
287
288 for (uint32_t result_id = 19; result_id <= 24; ++result_id) {
289 ASSERT_FALSE(
290 transformation_context.GetFactManager()->IdIsIrrelevant(result_id));
291 }
292
293 for (uint32_t result_id = 25; result_id <= 30; ++result_id) {
294 ASSERT_TRUE(
295 transformation_context.GetFactManager()->IdIsIrrelevant(result_id));
296 }
297
298 std::string variant_shader = R"(
299 OpCapability Shader
300 OpCapability Int64
301 OpCapability Float64
302 %1 = OpExtInstImport "GLSL.std.450"
303 OpMemoryModel Logical GLSL450
304 OpEntryPoint Vertex %17 "main"
305
306 ; Types
307
308 ; 32-bit types
309 %2 = OpTypeInt 32 0
310 %3 = OpTypeInt 32 1
311 %4 = OpTypeFloat 32
312
313 ; 64-bit types
314 %5 = OpTypeInt 64 0
315 %6 = OpTypeInt 64 1
316 %7 = OpTypeFloat 64
317
318 %8 = OpTypePointer Private %2
319 %9 = OpTypeVoid
320 %10 = OpTypeFunction %9
321
322 ; Constants
323
324 ; 32-bit constants
325 %11 = OpConstant %2 1
326 %12 = OpConstant %3 2
327 %13 = OpConstant %4 3
328
329 ; 64-bit constants
330 %14 = OpConstant %5 1
331 %15 = OpConstant %6 2
332 %16 = OpConstant %7 3
333
334 ; added constants
335 %19 = OpConstant %2 4
336 %20 = OpConstant %3 5
337 %21 = OpConstant %4 6
338 %22 = OpConstant %5 7
339 %23 = OpConstant %6 8
340 %24 = OpConstant %7 9
341 %25 = OpConstant %2 10
342 %26 = OpConstant %3 11
343 %27 = OpConstant %4 12
344 %28 = OpConstant %5 13
345 %29 = OpConstant %6 14
346 %30 = OpConstant %7 15
347
348 ; main function
349 %17 = OpFunction %9 None %10
350 %18 = OpLabel
351 OpReturn
352 OpFunctionEnd
353 )";
354
355 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
356 }
357
358 } // namespace
359 } // namespace fuzz
360 } // namespace spvtools
361