1 // Copyright (c) 2020 André Perez Maselco
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_toggle_access_chain_instruction.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25
TEST(TransformationToggleAccessChainInstructionTest,IsApplicableTest)26 TEST(TransformationToggleAccessChainInstructionTest, IsApplicableTest) {
27 std::string shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main"
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 OpName %4 "main"
35 %2 = OpTypeVoid
36 %3 = OpTypeFunction %2
37 %6 = OpTypeInt 32 1
38 %7 = OpTypeInt 32 0
39 %8 = OpConstant %7 2
40 %9 = OpTypeArray %6 %8
41 %10 = OpTypePointer Function %9
42 %12 = OpConstant %6 1
43 %13 = OpConstant %6 2
44 %14 = OpConstantComposite %9 %12 %13
45 %15 = OpTypePointer Function %6
46 %17 = OpConstant %6 0
47 %29 = OpTypeFloat 32
48 %30 = OpTypeArray %29 %8
49 %31 = OpTypePointer Function %30
50 %33 = OpConstant %29 1
51 %34 = OpConstant %29 2
52 %35 = OpConstantComposite %30 %33 %34
53 %36 = OpTypePointer Function %29
54 %49 = OpTypeVector %29 3
55 %50 = OpTypeArray %49 %8
56 %51 = OpTypePointer Function %50
57 %53 = OpConstant %29 3
58 %54 = OpConstantComposite %49 %33 %34 %53
59 %55 = OpConstant %29 4
60 %56 = OpConstant %29 5
61 %57 = OpConstant %29 6
62 %58 = OpConstantComposite %49 %55 %56 %57
63 %59 = OpConstantComposite %50 %54 %58
64 %61 = OpTypePointer Function %49
65 %4 = OpFunction %2 None %3
66 %5 = OpLabel
67 %11 = OpVariable %10 Function
68 %16 = OpVariable %15 Function
69 %23 = OpVariable %15 Function
70 %32 = OpVariable %31 Function
71 %37 = OpVariable %36 Function
72 %43 = OpVariable %36 Function
73 %52 = OpVariable %51 Function
74 %60 = OpVariable %36 Function
75 OpStore %11 %14
76 %18 = OpAccessChain %15 %11 %17
77 %19 = OpLoad %6 %18
78 %20 = OpInBoundsAccessChain %15 %11 %12
79 %21 = OpLoad %6 %20
80 %22 = OpIAdd %6 %19 %21
81 OpStore %16 %22
82 %24 = OpAccessChain %15 %11 %17
83 %25 = OpLoad %6 %24
84 %26 = OpInBoundsAccessChain %15 %11 %12
85 %27 = OpLoad %6 %26
86 %28 = OpIMul %6 %25 %27
87 OpStore %23 %28
88 OpStore %32 %35
89 %38 = OpAccessChain %36 %32 %17
90 %39 = OpLoad %29 %38
91 %40 = OpAccessChain %36 %32 %12
92 %41 = OpLoad %29 %40
93 %42 = OpFAdd %29 %39 %41
94 OpStore %37 %42
95 %44 = OpAccessChain %36 %32 %17
96 %45 = OpLoad %29 %44
97 %46 = OpAccessChain %36 %32 %12
98 %47 = OpLoad %29 %46
99 %48 = OpFMul %29 %45 %47
100 OpStore %43 %48
101 OpStore %52 %59
102 %62 = OpAccessChain %61 %52 %17
103 %63 = OpLoad %49 %62
104 %64 = OpAccessChain %61 %52 %12
105 %65 = OpLoad %49 %64
106 %66 = OpDot %29 %63 %65
107 OpStore %60 %66
108 OpReturn
109 OpFunctionEnd
110 )";
111
112 const auto env = SPV_ENV_UNIVERSAL_1_5;
113 const auto consumer = nullptr;
114 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
115 spvtools::ValidatorOptions validator_options;
116 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
117 kConsoleMessageConsumer));
118 TransformationContext transformation_context(
119 MakeUnique<FactManager>(context.get()), validator_options);
120 // Tests existing access chain instructions
121 auto instructionDescriptor =
122 MakeInstructionDescriptor(18, SpvOpAccessChain, 0);
123 auto transformation =
124 TransformationToggleAccessChainInstruction(instructionDescriptor);
125 ASSERT_TRUE(
126 transformation.IsApplicable(context.get(), transformation_context));
127
128 instructionDescriptor =
129 MakeInstructionDescriptor(20, SpvOpInBoundsAccessChain, 0);
130 transformation =
131 TransformationToggleAccessChainInstruction(instructionDescriptor);
132 ASSERT_TRUE(
133 transformation.IsApplicable(context.get(), transformation_context));
134
135 instructionDescriptor = MakeInstructionDescriptor(24, SpvOpAccessChain, 0);
136 transformation =
137 TransformationToggleAccessChainInstruction(instructionDescriptor);
138 ASSERT_TRUE(
139 transformation.IsApplicable(context.get(), transformation_context));
140
141 instructionDescriptor =
142 MakeInstructionDescriptor(26, SpvOpInBoundsAccessChain, 0);
143 transformation =
144 TransformationToggleAccessChainInstruction(instructionDescriptor);
145 ASSERT_TRUE(
146 transformation.IsApplicable(context.get(), transformation_context));
147
148 // Tests existing non-access chain instructions
149 instructionDescriptor = MakeInstructionDescriptor(1, SpvOpExtInstImport, 0);
150 transformation =
151 TransformationToggleAccessChainInstruction(instructionDescriptor);
152 ASSERT_FALSE(
153 transformation.IsApplicable(context.get(), transformation_context));
154
155 instructionDescriptor = MakeInstructionDescriptor(5, SpvOpLabel, 0);
156 transformation =
157 TransformationToggleAccessChainInstruction(instructionDescriptor);
158 ASSERT_FALSE(
159 transformation.IsApplicable(context.get(), transformation_context));
160
161 instructionDescriptor =
162 MakeInstructionDescriptor(14, SpvOpConstantComposite, 0);
163 transformation =
164 TransformationToggleAccessChainInstruction(instructionDescriptor);
165 ASSERT_FALSE(
166 transformation.IsApplicable(context.get(), transformation_context));
167
168 // Tests the base instruction id not existing
169 instructionDescriptor = MakeInstructionDescriptor(67, SpvOpAccessChain, 0);
170 transformation =
171 TransformationToggleAccessChainInstruction(instructionDescriptor);
172 ASSERT_FALSE(
173 transformation.IsApplicable(context.get(), transformation_context));
174
175 instructionDescriptor = MakeInstructionDescriptor(68, SpvOpAccessChain, 0);
176 transformation =
177 TransformationToggleAccessChainInstruction(instructionDescriptor);
178 ASSERT_FALSE(
179 transformation.IsApplicable(context.get(), transformation_context));
180
181 instructionDescriptor =
182 MakeInstructionDescriptor(69, SpvOpInBoundsAccessChain, 0);
183 transformation =
184 TransformationToggleAccessChainInstruction(instructionDescriptor);
185 ASSERT_FALSE(
186 transformation.IsApplicable(context.get(), transformation_context));
187
188 // Tests there being no instruction with the desired opcode after the base
189 // instruction id
190 instructionDescriptor = MakeInstructionDescriptor(65, SpvOpAccessChain, 0);
191 transformation =
192 TransformationToggleAccessChainInstruction(instructionDescriptor);
193 ASSERT_FALSE(
194 transformation.IsApplicable(context.get(), transformation_context));
195
196 instructionDescriptor =
197 MakeInstructionDescriptor(66, SpvOpInBoundsAccessChain, 0);
198 transformation =
199 TransformationToggleAccessChainInstruction(instructionDescriptor);
200 ASSERT_FALSE(
201 transformation.IsApplicable(context.get(), transformation_context));
202
203 // Tests there being an instruction with the desired opcode after the base
204 // instruction id, but the skip count associated with the instruction
205 // descriptor being so high.
206 instructionDescriptor = MakeInstructionDescriptor(11, SpvOpAccessChain, 100);
207 transformation =
208 TransformationToggleAccessChainInstruction(instructionDescriptor);
209 ASSERT_FALSE(
210 transformation.IsApplicable(context.get(), transformation_context));
211
212 instructionDescriptor =
213 MakeInstructionDescriptor(16, SpvOpInBoundsAccessChain, 100);
214 transformation =
215 TransformationToggleAccessChainInstruction(instructionDescriptor);
216 ASSERT_FALSE(
217 transformation.IsApplicable(context.get(), transformation_context));
218 }
219
TEST(TransformationToggleAccessChainInstructionTest,ApplyTest)220 TEST(TransformationToggleAccessChainInstructionTest, ApplyTest) {
221 std::string shader = R"(
222 OpCapability Shader
223 %1 = OpExtInstImport "GLSL.std.450"
224 OpMemoryModel Logical GLSL450
225 OpEntryPoint Fragment %4 "main"
226 OpExecutionMode %4 OriginUpperLeft
227 OpSource ESSL 310
228 OpName %4 "main"
229 %2 = OpTypeVoid
230 %3 = OpTypeFunction %2
231 %6 = OpTypeInt 32 1
232 %7 = OpTypeInt 32 0
233 %8 = OpConstant %7 2
234 %9 = OpTypeArray %6 %8
235 %10 = OpTypePointer Function %9
236 %12 = OpConstant %6 1
237 %13 = OpConstant %6 2
238 %14 = OpConstantComposite %9 %12 %13
239 %15 = OpTypePointer Function %6
240 %17 = OpConstant %6 0
241 %29 = OpTypeFloat 32
242 %30 = OpTypeArray %29 %8
243 %31 = OpTypePointer Function %30
244 %33 = OpConstant %29 1
245 %34 = OpConstant %29 2
246 %35 = OpConstantComposite %30 %33 %34
247 %36 = OpTypePointer Function %29
248 %49 = OpTypeVector %29 3
249 %50 = OpTypeArray %49 %8
250 %51 = OpTypePointer Function %50
251 %53 = OpConstant %29 3
252 %54 = OpConstantComposite %49 %33 %34 %53
253 %55 = OpConstant %29 4
254 %56 = OpConstant %29 5
255 %57 = OpConstant %29 6
256 %58 = OpConstantComposite %49 %55 %56 %57
257 %59 = OpConstantComposite %50 %54 %58
258 %61 = OpTypePointer Function %49
259 %4 = OpFunction %2 None %3
260 %5 = OpLabel
261 %11 = OpVariable %10 Function
262 %16 = OpVariable %15 Function
263 %23 = OpVariable %15 Function
264 %32 = OpVariable %31 Function
265 %37 = OpVariable %36 Function
266 %43 = OpVariable %36 Function
267 %52 = OpVariable %51 Function
268 %60 = OpVariable %36 Function
269 OpStore %11 %14
270 %18 = OpAccessChain %15 %11 %17
271 %19 = OpLoad %6 %18
272 %20 = OpInBoundsAccessChain %15 %11 %12
273 %21 = OpLoad %6 %20
274 %22 = OpIAdd %6 %19 %21
275 OpStore %16 %22
276 %24 = OpAccessChain %15 %11 %17
277 %25 = OpLoad %6 %24
278 %26 = OpInBoundsAccessChain %15 %11 %12
279 %27 = OpLoad %6 %26
280 %28 = OpIMul %6 %25 %27
281 OpStore %23 %28
282 OpStore %32 %35
283 %38 = OpAccessChain %36 %32 %17
284 %39 = OpLoad %29 %38
285 %40 = OpAccessChain %36 %32 %12
286 %41 = OpLoad %29 %40
287 %42 = OpFAdd %29 %39 %41
288 OpStore %37 %42
289 %44 = OpAccessChain %36 %32 %17
290 %45 = OpLoad %29 %44
291 %46 = OpAccessChain %36 %32 %12
292 %47 = OpLoad %29 %46
293 %48 = OpFMul %29 %45 %47
294 OpStore %43 %48
295 OpStore %52 %59
296 %62 = OpAccessChain %61 %52 %17
297 %63 = OpLoad %49 %62
298 %64 = OpAccessChain %61 %52 %12
299 %65 = OpLoad %49 %64
300 %66 = OpDot %29 %63 %65
301 OpStore %60 %66
302 OpReturn
303 OpFunctionEnd
304 )";
305
306 const auto env = SPV_ENV_UNIVERSAL_1_5;
307 const auto consumer = nullptr;
308 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
309 spvtools::ValidatorOptions validator_options;
310 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
311 kConsoleMessageConsumer));
312 TransformationContext transformation_context(
313 MakeUnique<FactManager>(context.get()), validator_options);
314 auto instructionDescriptor =
315 MakeInstructionDescriptor(18, SpvOpAccessChain, 0);
316 auto transformation =
317 TransformationToggleAccessChainInstruction(instructionDescriptor);
318 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
319
320 instructionDescriptor =
321 MakeInstructionDescriptor(20, SpvOpInBoundsAccessChain, 0);
322 transformation =
323 TransformationToggleAccessChainInstruction(instructionDescriptor);
324 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
325
326 instructionDescriptor = MakeInstructionDescriptor(24, SpvOpAccessChain, 0);
327 transformation =
328 TransformationToggleAccessChainInstruction(instructionDescriptor);
329 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
330
331 instructionDescriptor =
332 MakeInstructionDescriptor(26, SpvOpInBoundsAccessChain, 0);
333 transformation =
334 TransformationToggleAccessChainInstruction(instructionDescriptor);
335 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
336
337 instructionDescriptor = MakeInstructionDescriptor(38, SpvOpAccessChain, 0);
338 transformation =
339 TransformationToggleAccessChainInstruction(instructionDescriptor);
340 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
341
342 std::string variantShader = R"(
343 OpCapability Shader
344 %1 = OpExtInstImport "GLSL.std.450"
345 OpMemoryModel Logical GLSL450
346 OpEntryPoint Fragment %4 "main"
347 OpExecutionMode %4 OriginUpperLeft
348 OpSource ESSL 310
349 OpName %4 "main"
350 %2 = OpTypeVoid
351 %3 = OpTypeFunction %2
352 %6 = OpTypeInt 32 1
353 %7 = OpTypeInt 32 0
354 %8 = OpConstant %7 2
355 %9 = OpTypeArray %6 %8
356 %10 = OpTypePointer Function %9
357 %12 = OpConstant %6 1
358 %13 = OpConstant %6 2
359 %14 = OpConstantComposite %9 %12 %13
360 %15 = OpTypePointer Function %6
361 %17 = OpConstant %6 0
362 %29 = OpTypeFloat 32
363 %30 = OpTypeArray %29 %8
364 %31 = OpTypePointer Function %30
365 %33 = OpConstant %29 1
366 %34 = OpConstant %29 2
367 %35 = OpConstantComposite %30 %33 %34
368 %36 = OpTypePointer Function %29
369 %49 = OpTypeVector %29 3
370 %50 = OpTypeArray %49 %8
371 %51 = OpTypePointer Function %50
372 %53 = OpConstant %29 3
373 %54 = OpConstantComposite %49 %33 %34 %53
374 %55 = OpConstant %29 4
375 %56 = OpConstant %29 5
376 %57 = OpConstant %29 6
377 %58 = OpConstantComposite %49 %55 %56 %57
378 %59 = OpConstantComposite %50 %54 %58
379 %61 = OpTypePointer Function %49
380 %4 = OpFunction %2 None %3
381 %5 = OpLabel
382 %11 = OpVariable %10 Function
383 %16 = OpVariable %15 Function
384 %23 = OpVariable %15 Function
385 %32 = OpVariable %31 Function
386 %37 = OpVariable %36 Function
387 %43 = OpVariable %36 Function
388 %52 = OpVariable %51 Function
389 %60 = OpVariable %36 Function
390 OpStore %11 %14
391 %18 = OpInBoundsAccessChain %15 %11 %17
392 %19 = OpLoad %6 %18
393 %20 = OpAccessChain %15 %11 %12
394 %21 = OpLoad %6 %20
395 %22 = OpIAdd %6 %19 %21
396 OpStore %16 %22
397 %24 = OpInBoundsAccessChain %15 %11 %17
398 %25 = OpLoad %6 %24
399 %26 = OpAccessChain %15 %11 %12
400 %27 = OpLoad %6 %26
401 %28 = OpIMul %6 %25 %27
402 OpStore %23 %28
403 OpStore %32 %35
404 %38 = OpInBoundsAccessChain %36 %32 %17
405 %39 = OpLoad %29 %38
406 %40 = OpAccessChain %36 %32 %12
407 %41 = OpLoad %29 %40
408 %42 = OpFAdd %29 %39 %41
409 OpStore %37 %42
410 %44 = OpAccessChain %36 %32 %17
411 %45 = OpLoad %29 %44
412 %46 = OpAccessChain %36 %32 %12
413 %47 = OpLoad %29 %46
414 %48 = OpFMul %29 %45 %47
415 OpStore %43 %48
416 OpStore %52 %59
417 %62 = OpAccessChain %61 %52 %17
418 %63 = OpLoad %49 %62
419 %64 = OpAccessChain %61 %52 %12
420 %65 = OpLoad %49 %64
421 %66 = OpDot %29 %63 %65
422 OpStore %60 %66
423 OpReturn
424 OpFunctionEnd
425 )";
426
427 ASSERT_TRUE(IsEqual(env, variantShader, context.get()));
428 }
429
430 } // namespace
431 } // namespace fuzz
432 } // namespace spvtools
433