blob: c5d6981c8fbd63592e403fc78912e92a73ca3757 [file] [log] [blame]
Alexis Hetu3eb4dd82020-10-29 21:37:20 -04001// 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
23namespace spvtools {
24namespace fuzz {
25namespace {
26const 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
66void 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
73TEST(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 =
Nicolas Capens84c9c452022-11-18 14:11:05 +000085 MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0);
86 auto instruction_24_descriptor =
87 MakeInstructionDescriptor(24, spv::Op::OpIAdd, 0);
Alexis Hetu3eb4dd82020-10-29 21:37:20 -040088
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
125TEST(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
Nicolas Capens84c9c452022-11-18 14:11:05 +0000136 auto instruction_24_descriptor =
137 MakeInstructionDescriptor(24, spv::Op::OpIAdd, 0);
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400138
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
192TEST(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.
Nicolas Capens84c9c452022-11-18 14:11:05 +0000234 ASSERT_FALSE(
235 TransformationReplaceIrrelevantId(
236 MakeIdUseDescriptor(
237 13, MakeInstructionDescriptor(12, spv::Op::OpVariable, 0), 1),
238 9)
239 .IsApplicable(context.get(), transformation_context));
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400240}
241
242TEST(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(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000286 20, MakeInstructionDescriptor(21, spv::Op::OpCopyObject, 0), 0),
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400287 10)
288 .IsApplicable(context.get(), transformation_context));
289}
290
291TEST(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(
Nicolas Capens84c9c452022-11-18 14:11:05 +0000332 10, MakeInstructionDescriptor(12, spv::Op::OpAccessChain, 0), 1),
Alexis Hetu3eb4dd82020-10-29 21:37:20 -0400333 11)
334 .IsApplicable(context.get(), transformation_context));
335}
336
337} // namespace
338} // namespace fuzz
339} // namespace spvtools