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