• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 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_replace_irrelevant_id.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/id_use_descriptor.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "test/fuzz/fuzz_test_util.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26 const std::string shader = R"(
27                OpCapability Shader
28           %1 = OpExtInstImport "GLSL.std.450"
29                OpMemoryModel Logical GLSL450
30                OpEntryPoint Fragment %2 "main"
31                OpExecutionMode %2 OriginUpperLeft
32                OpSource ESSL 310
33                OpName %2 "main"
34                OpName %3 "a"
35                OpName %4 "b"
36           %5 = OpTypeVoid
37           %6 = OpTypeFunction %5
38           %7 = OpTypeBool
39           %8 = OpConstantTrue %7
40           %9 = OpTypeInt 32 1
41          %10 = OpTypePointer Function %9
42          %11 = OpConstant %9 2
43          %12 = OpTypeStruct %9
44          %13 = OpTypeInt 32 0
45          %14 = OpConstant %13 3
46          %15 = OpTypeArray %12 %14
47          %16 = OpTypePointer Function %15
48          %17 = OpConstant %9 0
49           %2 = OpFunction %5 None %6
50          %18 = OpLabel
51           %3 = OpVariable %10 Function
52           %4 = OpVariable %10 Function
53          %19 = OpVariable %16 Function
54                OpStore %3 %11
55          %20 = OpLoad %9 %3
56          %21 = OpAccessChain %10 %19 %20 %17
57          %22 = OpLoad %9 %21
58                OpStore %4 %22
59          %23 = OpLoad %9 %4
60          %24 = OpIAdd %9 %20 %23
61          %25 = OpISub %9 %23 %20
62                OpReturn
63                OpFunctionEnd
64 )";
65 
SetUpIrrelevantIdFacts(FactManager * fact_manager)66 void SetUpIrrelevantIdFacts(FactManager* fact_manager) {
67   fact_manager->AddFactIdIsIrrelevant(17);
68   fact_manager->AddFactIdIsIrrelevant(23);
69   fact_manager->AddFactIdIsIrrelevant(24);
70   fact_manager->AddFactIdIsIrrelevant(25);
71 }
72 
TEST(TransformationReplaceIrrelevantIdTest,Inapplicable)73 TEST(TransformationReplaceIrrelevantIdTest, Inapplicable) {
74   const auto env = SPV_ENV_UNIVERSAL_1_5;
75   const auto consumer = nullptr;
76   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
77   spvtools::ValidatorOptions validator_options;
78   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
79                                                kConsoleMessageConsumer));
80   TransformationContext transformation_context(
81       MakeUnique<FactManager>(context.get()), validator_options);
82   SetUpIrrelevantIdFacts(transformation_context.GetFactManager());
83 
84   auto instruction_21_descriptor =
85       MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0);
86   auto instruction_24_descriptor =
87       MakeInstructionDescriptor(24, spv::Op::OpIAdd, 0);
88 
89   // %20 has not been declared as irrelevant.
90   ASSERT_FALSE(TransformationReplaceIrrelevantId(
91                    MakeIdUseDescriptor(20, instruction_24_descriptor, 0), 23)
92                    .IsApplicable(context.get(), transformation_context));
93 
94   // %22 is not used in %24.
95   ASSERT_FALSE(TransformationReplaceIrrelevantId(
96                    MakeIdUseDescriptor(22, instruction_24_descriptor, 1), 20)
97                    .IsApplicable(context.get(), transformation_context));
98 
99   // Replacement id %50 does not exist.
100   ASSERT_FALSE(TransformationReplaceIrrelevantId(
101                    MakeIdUseDescriptor(23, instruction_24_descriptor, 1), 50)
102                    .IsApplicable(context.get(), transformation_context));
103 
104   // %25 is not available to use at %24.
105   ASSERT_FALSE(TransformationReplaceIrrelevantId(
106                    MakeIdUseDescriptor(23, instruction_24_descriptor, 1), 25)
107                    .IsApplicable(context.get(), transformation_context));
108 
109   // %24 is not available to use at %24.
110   ASSERT_FALSE(TransformationReplaceIrrelevantId(
111                    MakeIdUseDescriptor(23, instruction_24_descriptor, 1), 24)
112                    .IsApplicable(context.get(), transformation_context));
113 
114   // %8 has not the same type as %23.
115   ASSERT_FALSE(TransformationReplaceIrrelevantId(
116                    MakeIdUseDescriptor(23, instruction_24_descriptor, 1), 8)
117                    .IsApplicable(context.get(), transformation_context));
118 
119   // %17 is an index to a struct in an access chain, so it can't be replaced.
120   ASSERT_FALSE(TransformationReplaceIrrelevantId(
121                    MakeIdUseDescriptor(17, instruction_21_descriptor, 2), 20)
122                    .IsApplicable(context.get(), transformation_context));
123 }
124 
TEST(TransformationReplaceIrrelevantIdTest,Apply)125 TEST(TransformationReplaceIrrelevantIdTest, Apply) {
126   const auto env = SPV_ENV_UNIVERSAL_1_5;
127   const auto consumer = nullptr;
128   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
129   spvtools::ValidatorOptions validator_options;
130   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
131                                                kConsoleMessageConsumer));
132   TransformationContext transformation_context(
133       MakeUnique<FactManager>(context.get()), validator_options);
134   SetUpIrrelevantIdFacts(transformation_context.GetFactManager());
135 
136   auto instruction_24_descriptor =
137       MakeInstructionDescriptor(24, spv::Op::OpIAdd, 0);
138 
139   // Replace the use of %23 in %24 with %22.
140   auto transformation = TransformationReplaceIrrelevantId(
141       MakeIdUseDescriptor(23, instruction_24_descriptor, 1), 22);
142   ASSERT_TRUE(
143       transformation.IsApplicable(context.get(), transformation_context));
144   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
145 
146   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
147                                                kConsoleMessageConsumer));
148 
149   std::string after_transformation = R"(
150                OpCapability Shader
151           %1 = OpExtInstImport "GLSL.std.450"
152                OpMemoryModel Logical GLSL450
153                OpEntryPoint Fragment %2 "main"
154                OpExecutionMode %2 OriginUpperLeft
155                OpSource ESSL 310
156                OpName %2 "main"
157                OpName %3 "a"
158                OpName %4 "b"
159           %5 = OpTypeVoid
160           %6 = OpTypeFunction %5
161           %7 = OpTypeBool
162           %8 = OpConstantTrue %7
163           %9 = OpTypeInt 32 1
164          %10 = OpTypePointer Function %9
165          %11 = OpConstant %9 2
166          %12 = OpTypeStruct %9
167          %13 = OpTypeInt 32 0
168          %14 = OpConstant %13 3
169          %15 = OpTypeArray %12 %14
170          %16 = OpTypePointer Function %15
171          %17 = OpConstant %9 0
172           %2 = OpFunction %5 None %6
173          %18 = OpLabel
174           %3 = OpVariable %10 Function
175           %4 = OpVariable %10 Function
176          %19 = OpVariable %16 Function
177                OpStore %3 %11
178          %20 = OpLoad %9 %3
179          %21 = OpAccessChain %10 %19 %20 %17
180          %22 = OpLoad %9 %21
181                OpStore %4 %22
182          %23 = OpLoad %9 %4
183          %24 = OpIAdd %9 %20 %22
184          %25 = OpISub %9 %23 %20
185                OpReturn
186                OpFunctionEnd
187 )";
188 
189   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
190 }
191 
TEST(TransformationReplaceIrrelevantIdTest,DoNotReplaceVariableInitializerWithNonConstant)192 TEST(TransformationReplaceIrrelevantIdTest,
193      DoNotReplaceVariableInitializerWithNonConstant) {
194   // Checks that it is not possible to replace the initializer of a variable
195   // with a non-constant id (such as a function parameter).
196   const std::string reference_shader = R"(
197                OpCapability Shader
198           %1 = OpExtInstImport "GLSL.std.450"
199                OpMemoryModel Logical GLSL450
200                OpEntryPoint Fragment %4 "main"
201                OpExecutionMode %4 OriginUpperLeft
202                OpSource ESSL 320
203           %2 = OpTypeVoid
204           %3 = OpTypeFunction %2
205           %6 = OpTypeInt 32 1
206           %7 = OpTypePointer Function %6
207           %8 = OpTypeFunction %2 %6
208          %13 = OpConstant %6 2
209           %4 = OpFunction %2 None %3
210           %5 = OpLabel
211                OpReturn
212                OpFunctionEnd
213          %10 = OpFunction %2 None %8
214           %9 = OpFunctionParameter %6
215          %11 = OpLabel
216          %12 = OpVariable %7 Function %13
217                OpReturn
218                OpFunctionEnd
219   )";
220 
221   const auto env = SPV_ENV_UNIVERSAL_1_5;
222   const auto consumer = nullptr;
223   const auto context =
224       BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
225   spvtools::ValidatorOptions validator_options;
226   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
227                                                kConsoleMessageConsumer));
228   TransformationContext transformation_context(
229       MakeUnique<FactManager>(context.get()), validator_options);
230   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(13);
231 
232   // We cannot replace the use of %13 in the initializer of %12 with %9 because
233   // %9 is not a constant.
234   ASSERT_FALSE(
235       TransformationReplaceIrrelevantId(
236           MakeIdUseDescriptor(
237               13, MakeInstructionDescriptor(12, spv::Op::OpVariable, 0), 1),
238           9)
239           .IsApplicable(context.get(), transformation_context));
240 }
241 
TEST(TransformationReplaceIrrelevantIdTest,DoNotReplaceIrrelevantIdWithOpFunction)242 TEST(TransformationReplaceIrrelevantIdTest,
243      DoNotReplaceIrrelevantIdWithOpFunction) {
244   // Checks that an OpFunction result id is not allowed to be used to replace an
245   // irrelevant id.
246   const std::string reference_shader = R"(
247                OpCapability Shader
248           %1 = OpExtInstImport "GLSL.std.450"
249                OpMemoryModel Logical GLSL450
250                OpEntryPoint Fragment %4 "main"
251                OpExecutionMode %4 OriginUpperLeft
252                OpSource ESSL 320
253           %2 = OpTypeVoid
254           %3 = OpTypeFunction %2
255           %6 = OpTypeInt 32 1
256           %7 = OpTypeFunction %6
257          %13 = OpConstant %6 2
258           %4 = OpFunction %2 None %3
259           %5 = OpLabel
260          %20 = OpCopyObject %6 %13
261          %21 = OpCopyObject %6 %20
262                OpReturn
263                OpFunctionEnd
264          %10 = OpFunction %6 None %7
265          %11 = OpLabel
266                OpReturnValue %13
267                OpFunctionEnd
268   )";
269 
270   const auto env = SPV_ENV_UNIVERSAL_1_5;
271   const auto consumer = nullptr;
272   const auto context =
273       BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
274   spvtools::ValidatorOptions validator_options;
275   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
276                                                kConsoleMessageConsumer));
277   TransformationContext transformation_context(
278       MakeUnique<FactManager>(context.get()), validator_options);
279   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(20);
280 
281   // We cannot replace the use of %20 in by %21 with %10 because %10 is an
282   // OpFunction instruction.
283   ASSERT_FALSE(
284       TransformationReplaceIrrelevantId(
285           MakeIdUseDescriptor(
286               20, MakeInstructionDescriptor(21, spv::Op::OpCopyObject, 0), 0),
287           10)
288           .IsApplicable(context.get(), transformation_context));
289 }
290 
TEST(TransformationReplaceIrrelevantIdTest,OpAccessChainIrrelevantIndex)291 TEST(TransformationReplaceIrrelevantIdTest, OpAccessChainIrrelevantIndex) {
292   // Checks that we can't replace irrelevant index operands in OpAccessChain.
293   const std::string reference_shader = R"(
294                OpCapability Shader
295           %1 = OpExtInstImport "GLSL.std.450"
296                OpMemoryModel Logical GLSL450
297                OpEntryPoint Fragment %4 "main"
298                OpExecutionMode %4 OriginUpperLeft
299                OpSource ESSL 320
300           %2 = OpTypeVoid
301           %3 = OpTypeFunction %2
302           %6 = OpTypeInt 32 1
303           %7 = OpTypeVector %6 2
304           %8 = OpTypePointer Function %7
305          %10 = OpConstant %6 0
306          %11 = OpConstant %6 2
307          %13 = OpTypePointer Function %6
308           %4 = OpFunction %2 None %3
309           %5 = OpLabel
310           %9 = OpVariable %8 Function
311          %12 = OpAccessChain %13 %9 %10
312                OpReturn
313                OpFunctionEnd
314   )";
315 
316   const auto env = SPV_ENV_UNIVERSAL_1_5;
317   const auto consumer = nullptr;
318   const auto context =
319       BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
320   spvtools::ValidatorOptions validator_options;
321   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
322                                                kConsoleMessageConsumer));
323   TransformationContext transformation_context(
324       MakeUnique<FactManager>(context.get()), validator_options);
325   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(10);
326 
327   // We cannot replace the use of %10 in %12 with %11 because %10 is an
328   // irrelevant id.
329   ASSERT_FALSE(
330       TransformationReplaceIrrelevantId(
331           MakeIdUseDescriptor(
332               10, MakeInstructionDescriptor(12, spv::Op::OpAccessChain, 0), 1),
333           11)
334           .IsApplicable(context.get(), transformation_context));
335 }
336 
337 }  // namespace
338 }  // namespace fuzz
339 }  // namespace spvtools
340