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