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