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_store.h"
16 #include "source/fuzz/instruction_descriptor.h"
17 #include "test/fuzz/fuzz_test_util.h"
18
19 namespace spvtools {
20 namespace fuzz {
21 namespace {
22
TEST(TransformationStoreTest,BasicTest)23 TEST(TransformationStoreTest, BasicTest) {
24 std::string shader = R"(
25 OpCapability Shader
26 %1 = OpExtInstImport "GLSL.std.450"
27 OpMemoryModel Logical GLSL450
28 OpEntryPoint Fragment %4 "main" %92 %52 %53
29 OpExecutionMode %4 OriginUpperLeft
30 OpSource ESSL 310
31 OpDecorate %92 BuiltIn FragCoord
32 %2 = OpTypeVoid
33 %3 = OpTypeFunction %2
34 %6 = OpTypeInt 32 1
35 %7 = OpTypeFloat 32
36 %8 = OpTypeStruct %6 %7
37 %9 = OpTypePointer Function %8
38 %10 = OpTypeFunction %6 %9
39 %14 = OpConstant %6 0
40 %15 = OpTypePointer Function %6
41 %51 = OpTypePointer Private %6
42 %21 = OpConstant %6 2
43 %23 = OpConstant %6 1
44 %24 = OpConstant %7 1
45 %25 = OpTypePointer Function %7
46 %50 = OpTypePointer Private %7
47 %34 = OpTypeBool
48 %35 = OpConstantFalse %34
49 %60 = OpConstantNull %50
50 %61 = OpUndef %51
51 %52 = OpVariable %50 Private
52 %53 = OpVariable %51 Private
53 %80 = OpConstantComposite %8 %21 %24
54 %90 = OpTypeVector %7 4
55 %91 = OpTypePointer Input %90
56 %92 = OpVariable %91 Input
57 %93 = OpConstantComposite %90 %24 %24 %24 %24
58 %4 = OpFunction %2 None %3
59 %5 = OpLabel
60 %20 = OpVariable %9 Function
61 %27 = OpVariable %9 Function ; irrelevant
62 %22 = OpAccessChain %15 %20 %14
63 %44 = OpCopyObject %9 %20
64 %26 = OpAccessChain %25 %20 %23
65 %29 = OpFunctionCall %6 %12 %27
66 %30 = OpAccessChain %15 %20 %14
67 %45 = OpCopyObject %15 %30
68 %81 = OpCopyObject %9 %27 ; irrelevant
69 %33 = OpAccessChain %15 %20 %14
70 OpSelectionMerge %37 None
71 OpBranchConditional %35 %36 %37
72 %36 = OpLabel
73 %38 = OpAccessChain %15 %20 %14
74 %40 = OpAccessChain %15 %20 %14
75 %43 = OpAccessChain %15 %20 %14
76 %82 = OpCopyObject %9 %27 ; irrelevant
77 OpBranch %37
78 %37 = OpLabel
79 OpReturn
80 OpFunctionEnd
81 %12 = OpFunction %6 None %10
82 %11 = OpFunctionParameter %9 ; irrelevant
83 %13 = OpLabel
84 %46 = OpCopyObject %9 %11 ; irrelevant
85 %16 = OpAccessChain %15 %11 %14 ; irrelevant
86 %95 = OpCopyObject %8 %80
87 OpReturnValue %21
88 OpFunctionEnd
89 )";
90
91 const auto env = SPV_ENV_UNIVERSAL_1_4;
92 const auto consumer = nullptr;
93 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
94 ASSERT_TRUE(IsValid(env, context.get()));
95
96 FactManager fact_manager;
97 spvtools::ValidatorOptions validator_options;
98 TransformationContext transformation_context(&fact_manager,
99 validator_options);
100
101 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
102 27);
103 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
104 11);
105 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
106 46);
107 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
108 16);
109 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
110 52);
111 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
112 81);
113 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
114 82);
115
116 transformation_context.GetFactManager()->AddFactBlockIsDead(36);
117
118 // Variables with pointee types:
119 // 52 - ptr_to(7)
120 // 53 - ptr_to(6)
121 // 20 - ptr_to(8)
122 // 27 - ptr_to(8) - irrelevant
123 // 92 - ptr_to(90) - read only
124
125 // Access chains with pointee type:
126 // 22 - ptr_to(6)
127 // 26 - ptr_to(6)
128 // 30 - ptr_to(6)
129 // 33 - ptr_to(6)
130 // 38 - ptr_to(6)
131 // 40 - ptr_to(6)
132 // 43 - ptr_to(6)
133 // 16 - ptr_to(6) - irrelevant
134
135 // Copied object with pointee type:
136 // 44 - ptr_to(8)
137 // 45 - ptr_to(6)
138 // 46 - ptr_to(8) - irrelevant
139 // 81 - ptr_to(8) - irrelevant
140 // 82 - ptr_to(8) - irrelevant
141
142 // Function parameters with pointee type:
143 // 11 - ptr_to(8) - irrelevant
144
145 // Pointers that cannot be used:
146 // 60 - null
147 // 61 - undefined
148
149 // Bad: attempt to store to 11 from outside its function
150 ASSERT_FALSE(TransformationStore(
151 11, 80, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
152 .IsApplicable(context.get(), transformation_context));
153
154 // Bad: pointer is not available
155 ASSERT_FALSE(TransformationStore(
156 81, 80, MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
157 .IsApplicable(context.get(), transformation_context));
158
159 // Bad: attempt to insert before OpVariable
160 ASSERT_FALSE(TransformationStore(
161 52, 24, MakeInstructionDescriptor(27, SpvOpVariable, 0))
162 .IsApplicable(context.get(), transformation_context));
163
164 // Bad: pointer id does not exist
165 ASSERT_FALSE(TransformationStore(
166 1000, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
167 .IsApplicable(context.get(), transformation_context));
168
169 // Bad: pointer id exists but does not have a type
170 ASSERT_FALSE(TransformationStore(
171 5, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
172 .IsApplicable(context.get(), transformation_context));
173
174 // Bad: pointer id exists and has a type, but is not a pointer
175 ASSERT_FALSE(TransformationStore(
176 24, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
177 .IsApplicable(context.get(), transformation_context));
178
179 // Bad: attempt to store to a null pointer
180 ASSERT_FALSE(TransformationStore(
181 60, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
182 .IsApplicable(context.get(), transformation_context));
183
184 // Bad: attempt to store to an undefined pointer
185 ASSERT_FALSE(TransformationStore(
186 61, 21, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
187 .IsApplicable(context.get(), transformation_context));
188
189 // Bad: %82 is not available at the program point
190 ASSERT_FALSE(
191 TransformationStore(82, 80, MakeInstructionDescriptor(37, SpvOpReturn, 0))
192 .IsApplicable(context.get(), transformation_context));
193
194 // Bad: value id does not exist
195 ASSERT_FALSE(TransformationStore(
196 27, 1000, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
197 .IsApplicable(context.get(), transformation_context));
198
199 // Bad: value id exists but does not have a type
200 ASSERT_FALSE(TransformationStore(
201 27, 15, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
202 .IsApplicable(context.get(), transformation_context));
203
204 // Bad: value id exists but has the wrong type
205 ASSERT_FALSE(TransformationStore(
206 27, 14, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
207 .IsApplicable(context.get(), transformation_context));
208
209 // Bad: attempt to store to read-only variable
210 ASSERT_FALSE(TransformationStore(
211 92, 93, MakeInstructionDescriptor(40, SpvOpAccessChain, 0))
212 .IsApplicable(context.get(), transformation_context));
213
214 // Bad: value is not available
215 ASSERT_FALSE(TransformationStore(
216 27, 95, MakeInstructionDescriptor(40, SpvOpAccessChain, 0))
217 .IsApplicable(context.get(), transformation_context));
218
219 // Bad: variable being stored to does not have an irrelevant pointee value,
220 // and the store is not in a dead block.
221 ASSERT_FALSE(TransformationStore(
222 20, 95, MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
223 .IsApplicable(context.get(), transformation_context));
224
225 // The described instruction does not exist.
226 ASSERT_FALSE(TransformationStore(
227 27, 80, MakeInstructionDescriptor(1000, SpvOpAccessChain, 0))
228 .IsApplicable(context.get(), transformation_context));
229
230 {
231 // Store to irrelevant variable from dead block.
232 TransformationStore transformation(
233 27, 80, MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
234 ASSERT_TRUE(
235 transformation.IsApplicable(context.get(), transformation_context));
236 transformation.Apply(context.get(), &transformation_context);
237 ASSERT_TRUE(IsValid(env, context.get()));
238 }
239
240 {
241 // Store to irrelevant variable from live block.
242 TransformationStore transformation(
243 11, 95, MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
244 ASSERT_TRUE(
245 transformation.IsApplicable(context.get(), transformation_context));
246 transformation.Apply(context.get(), &transformation_context);
247 ASSERT_TRUE(IsValid(env, context.get()));
248 }
249
250 {
251 // Store to irrelevant variable from live block.
252 TransformationStore transformation(
253 46, 80, MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
254 ASSERT_TRUE(
255 transformation.IsApplicable(context.get(), transformation_context));
256 transformation.Apply(context.get(), &transformation_context);
257 ASSERT_TRUE(IsValid(env, context.get()));
258 }
259
260 {
261 // Store to irrelevant variable from live block.
262 TransformationStore transformation(
263 16, 21, MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
264 ASSERT_TRUE(
265 transformation.IsApplicable(context.get(), transformation_context));
266 transformation.Apply(context.get(), &transformation_context);
267 ASSERT_TRUE(IsValid(env, context.get()));
268 }
269
270 {
271 // Store to non-irrelevant variable from dead block.
272 TransformationStore transformation(
273 53, 21, MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
274 ASSERT_TRUE(
275 transformation.IsApplicable(context.get(), transformation_context));
276 transformation.Apply(context.get(), &transformation_context);
277 ASSERT_TRUE(IsValid(env, context.get()));
278 }
279
280 std::string after_transformation = R"(
281 OpCapability Shader
282 %1 = OpExtInstImport "GLSL.std.450"
283 OpMemoryModel Logical GLSL450
284 OpEntryPoint Fragment %4 "main" %92 %52 %53
285 OpExecutionMode %4 OriginUpperLeft
286 OpSource ESSL 310
287 OpDecorate %92 BuiltIn FragCoord
288 %2 = OpTypeVoid
289 %3 = OpTypeFunction %2
290 %6 = OpTypeInt 32 1
291 %7 = OpTypeFloat 32
292 %8 = OpTypeStruct %6 %7
293 %9 = OpTypePointer Function %8
294 %10 = OpTypeFunction %6 %9
295 %14 = OpConstant %6 0
296 %15 = OpTypePointer Function %6
297 %51 = OpTypePointer Private %6
298 %21 = OpConstant %6 2
299 %23 = OpConstant %6 1
300 %24 = OpConstant %7 1
301 %25 = OpTypePointer Function %7
302 %50 = OpTypePointer Private %7
303 %34 = OpTypeBool
304 %35 = OpConstantFalse %34
305 %60 = OpConstantNull %50
306 %61 = OpUndef %51
307 %52 = OpVariable %50 Private
308 %53 = OpVariable %51 Private
309 %80 = OpConstantComposite %8 %21 %24
310 %90 = OpTypeVector %7 4
311 %91 = OpTypePointer Input %90
312 %92 = OpVariable %91 Input
313 %93 = OpConstantComposite %90 %24 %24 %24 %24
314 %4 = OpFunction %2 None %3
315 %5 = OpLabel
316 %20 = OpVariable %9 Function
317 %27 = OpVariable %9 Function ; irrelevant
318 %22 = OpAccessChain %15 %20 %14
319 %44 = OpCopyObject %9 %20
320 %26 = OpAccessChain %25 %20 %23
321 %29 = OpFunctionCall %6 %12 %27
322 %30 = OpAccessChain %15 %20 %14
323 %45 = OpCopyObject %15 %30
324 %81 = OpCopyObject %9 %27 ; irrelevant
325 %33 = OpAccessChain %15 %20 %14
326 OpSelectionMerge %37 None
327 OpBranchConditional %35 %36 %37
328 %36 = OpLabel
329 OpStore %27 %80
330 OpStore %53 %21
331 %38 = OpAccessChain %15 %20 %14
332 %40 = OpAccessChain %15 %20 %14
333 %43 = OpAccessChain %15 %20 %14
334 %82 = OpCopyObject %9 %27 ; irrelevant
335 OpBranch %37
336 %37 = OpLabel
337 OpReturn
338 OpFunctionEnd
339 %12 = OpFunction %6 None %10
340 %11 = OpFunctionParameter %9 ; irrelevant
341 %13 = OpLabel
342 %46 = OpCopyObject %9 %11 ; irrelevant
343 %16 = OpAccessChain %15 %11 %14 ; irrelevant
344 %95 = OpCopyObject %8 %80
345 OpStore %11 %95
346 OpStore %46 %80
347 OpStore %16 %21
348 OpReturnValue %21
349 OpFunctionEnd
350 )";
351 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
352 }
353
354 } // namespace
355 } // namespace fuzz
356 } // namespace spvtools
357