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