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