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(SpvOpConstant, context->get_def_use_mgr()->GetDef(19)->opcode());
183 ASSERT_EQ(4, context->get_constant_mgr()->FindDeclaredConstant(19)->GetU32());
184 auto* constant_instruction = context->get_def_use_mgr()->GetDef(19);
185 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
186 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
187 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
188 kConsoleMessageConsumer));
189
190 // Adds 32-bit signed integer (1 logical operand with 1 word).
191 transformation = TransformationAddConstantScalar(20, 3, {5}, false);
192 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
193 constant_instruction = context->get_def_use_mgr()->GetDef(20);
194 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
195 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
196 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
197 kConsoleMessageConsumer));
198
199 // Adds 32-bit float (1 logical operand with 1 word).
200 transformation = TransformationAddConstantScalar(
201 21, 4, {0b01000000110000000000000000000000}, false);
202 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
203 constant_instruction = context->get_def_use_mgr()->GetDef(21);
204 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
205 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
206 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
207 kConsoleMessageConsumer));
208
209 // Adds 64-bit unsigned integer (1 logical operand with 2 words).
210 transformation = TransformationAddConstantScalar(22, 5, {7, 0}, false);
211 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
212 constant_instruction = context->get_def_use_mgr()->GetDef(22);
213 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
214 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
215 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
216 kConsoleMessageConsumer));
217
218 // Adds 64-bit signed integer (1 logical operand with 2 words).
219 transformation = TransformationAddConstantScalar(23, 6, {8, 0}, false);
220 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
221 constant_instruction = context->get_def_use_mgr()->GetDef(23);
222 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
223 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
224 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
225 kConsoleMessageConsumer));
226
227 // Adds 64-bit float (1 logical operand with 2 words).
228 transformation = TransformationAddConstantScalar(
229 24, 7, {0, 0b01000000001000100000000000000000}, false);
230 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
231 constant_instruction = context->get_def_use_mgr()->GetDef(24);
232 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
233 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
234 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
235 kConsoleMessageConsumer));
236
237 // Adds irrelevant 32-bit unsigned integer (1 logical operand with 1 word).
238 transformation = TransformationAddConstantScalar(25, 2, {10}, true);
239 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
240 constant_instruction = context->get_def_use_mgr()->GetDef(25);
241 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
242 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
243 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
244 kConsoleMessageConsumer));
245
246 // Adds irrelevant 32-bit signed integer (1 logical operand with 1 word).
247 transformation = TransformationAddConstantScalar(26, 3, {11}, true);
248 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
249 constant_instruction = context->get_def_use_mgr()->GetDef(26);
250 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
251 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
252 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
253 kConsoleMessageConsumer));
254
255 // Adds irrelevant 32-bit float (1 logical operand with 1 word).
256 transformation = TransformationAddConstantScalar(
257 27, 4, {0b01000001010000000000000000000000}, true);
258 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
259 constant_instruction = context->get_def_use_mgr()->GetDef(27);
260 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
261 EXPECT_EQ(constant_instruction->NumInOperandWords(), 1);
262 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
263 kConsoleMessageConsumer));
264
265 // Adds irrelevant 64-bit unsigned integer (1 logical operand with 2 words).
266 transformation = TransformationAddConstantScalar(28, 5, {13, 0}, true);
267 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
268 constant_instruction = context->get_def_use_mgr()->GetDef(28);
269 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
270 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
271 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
272 kConsoleMessageConsumer));
273
274 // Adds irrelevant 64-bit signed integer (1 logical operand with 2 words).
275 transformation = TransformationAddConstantScalar(29, 6, {14, 0}, true);
276 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
277 constant_instruction = context->get_def_use_mgr()->GetDef(29);
278 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
279 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
280 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
281 kConsoleMessageConsumer));
282
283 // Adds irrelevant 64-bit float (1 logical operand with 2 words).
284 transformation = TransformationAddConstantScalar(
285 30, 7, {0, 0b01000000001011100000000000000000}, true);
286 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
287 constant_instruction = context->get_def_use_mgr()->GetDef(30);
288 EXPECT_EQ(constant_instruction->NumInOperands(), 1);
289 EXPECT_EQ(constant_instruction->NumInOperandWords(), 2);
290 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
291 kConsoleMessageConsumer));
292
293 for (uint32_t result_id = 19; result_id <= 24; ++result_id) {
294 ASSERT_FALSE(
295 transformation_context.GetFactManager()->IdIsIrrelevant(result_id));
296 }
297
298 for (uint32_t result_id = 25; result_id <= 30; ++result_id) {
299 ASSERT_TRUE(
300 transformation_context.GetFactManager()->IdIsIrrelevant(result_id));
301 }
302
303 std::string variant_shader = R"(
304 OpCapability Shader
305 OpCapability Int64
306 OpCapability Float64
307 %1 = OpExtInstImport "GLSL.std.450"
308 OpMemoryModel Logical GLSL450
309 OpEntryPoint Vertex %17 "main"
310
311 ; Types
312
313 ; 32-bit types
314 %2 = OpTypeInt 32 0
315 %3 = OpTypeInt 32 1
316 %4 = OpTypeFloat 32
317
318 ; 64-bit types
319 %5 = OpTypeInt 64 0
320 %6 = OpTypeInt 64 1
321 %7 = OpTypeFloat 64
322
323 %8 = OpTypePointer Private %2
324 %9 = OpTypeVoid
325 %10 = OpTypeFunction %9
326
327 ; Constants
328
329 ; 32-bit constants
330 %11 = OpConstant %2 1
331 %12 = OpConstant %3 2
332 %13 = OpConstant %4 3
333
334 ; 64-bit constants
335 %14 = OpConstant %5 1
336 %15 = OpConstant %6 2
337 %16 = OpConstant %7 3
338
339 ; added constants
340 %19 = OpConstant %2 4
341 %20 = OpConstant %3 5
342 %21 = OpConstant %4 6
343 %22 = OpConstant %5 7
344 %23 = OpConstant %6 8
345 %24 = OpConstant %7 9
346 %25 = OpConstant %2 10
347 %26 = OpConstant %3 11
348 %27 = OpConstant %4 12
349 %28 = OpConstant %5 13
350 %29 = OpConstant %6 14
351 %30 = OpConstant %7 15
352
353 ; main function
354 %17 = OpFunction %9 None %10
355 %18 = OpLabel
356 OpReturn
357 OpFunctionEnd
358 )";
359
360 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
361 }
362
363 } // namespace
364 } // namespace fuzz
365 } // namespace spvtools
366