1 // Copyright (c) 2020 Vasyl Teliman
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_parameter_with_global.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "test/fuzz/fuzz_test_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24
TEST(TransformationReplaceParameterWithGlobalTest,BasicTest)25 TEST(TransformationReplaceParameterWithGlobalTest, BasicTest) {
26 std::string shader = R"(
27 OpCapability Shader
28 %1 = OpExtInstImport "GLSL.std.450"
29 OpMemoryModel Logical GLSL450
30 OpEntryPoint Fragment %4 "main"
31 OpExecutionMode %4 OriginUpperLeft
32 OpSource ESSL 310
33 OpMemberDecorate %13 0 RelaxedPrecision
34 OpDecorate %16 RelaxedPrecision
35 %2 = OpTypeVoid
36 %3 = OpTypeFunction %2
37 %6 = OpTypeInt 32 1
38 %7 = OpTypePointer Private %6
39 %8 = OpTypeFloat 32
40 %9 = OpTypePointer Private %8
41 %10 = OpTypeVector %8 2
42 %11 = OpTypePointer Private %10
43 %12 = OpTypeBool
44 %71 = OpTypeFunction %2 %6
45 %83 = OpTypeFunction %2 %6 %12
46 %93 = OpTypeFunction %2 %10
47 %94 = OpTypeFunction %2 %8 %10
48 %40 = OpTypePointer Function %12
49 %13 = OpTypeStruct %6 %8
50 %14 = OpTypePointer Private %13
51 %15 = OpTypeFunction %2 %6 %8 %10 %13 %40 %12
52 %22 = OpConstant %6 0
53 %23 = OpConstant %8 0
54 %26 = OpConstantComposite %10 %23 %23
55 %27 = OpConstantTrue %12
56 %28 = OpConstantComposite %13 %22 %23
57 %4 = OpFunction %2 None %3
58 %5 = OpLabel
59 %41 = OpVariable %40 Function %27
60 %33 = OpFunctionCall %2 %20 %22 %23 %26 %28 %41 %27
61 OpReturn
62 OpFunctionEnd
63
64 ; adjust type of the function in-place
65 %20 = OpFunction %2 None %15
66 %16 = OpFunctionParameter %6
67 %17 = OpFunctionParameter %8
68 %18 = OpFunctionParameter %10
69 %19 = OpFunctionParameter %13
70 %42 = OpFunctionParameter %40
71 %43 = OpFunctionParameter %12
72 %21 = OpLabel
73 OpReturn
74 OpFunctionEnd
75
76 ; reuse an existing function type
77 %70 = OpFunction %2 None %71
78 %72 = OpFunctionParameter %6
79 %73 = OpLabel
80 OpReturn
81 OpFunctionEnd
82 %74 = OpFunction %2 None %71
83 %75 = OpFunctionParameter %6
84 %76 = OpLabel
85 OpReturn
86 OpFunctionEnd
87
88 ; create a new function type
89 %77 = OpFunction %2 None %83
90 %78 = OpFunctionParameter %6
91 %84 = OpFunctionParameter %12
92 %79 = OpLabel
93 OpReturn
94 OpFunctionEnd
95 %80 = OpFunction %2 None %83
96 %81 = OpFunctionParameter %6
97 %85 = OpFunctionParameter %12
98 %82 = OpLabel
99 OpReturn
100 OpFunctionEnd
101
102 ; don't adjust the type of the function if it creates a duplicate
103 %86 = OpFunction %2 None %93
104 %87 = OpFunctionParameter %10
105 %89 = OpLabel
106 OpReturn
107 OpFunctionEnd
108 %90 = OpFunction %2 None %94
109 %91 = OpFunctionParameter %8
110 %95 = OpFunctionParameter %10
111 %92 = OpLabel
112 OpReturn
113 OpFunctionEnd
114 )";
115
116 const auto env = SPV_ENV_UNIVERSAL_1_3;
117 const auto consumer = nullptr;
118 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
119 spvtools::ValidatorOptions validator_options;
120 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
121 kConsoleMessageConsumer));
122 TransformationContext transformation_context(
123 MakeUnique<FactManager>(context.get()), validator_options);
124 // Parameter id is invalid.
125 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 50, 51)
126 .IsApplicable(context.get(), transformation_context));
127
128 // Parameter id is not a result id of an OpFunctionParameter instruction.
129 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 21, 51)
130 .IsApplicable(context.get(), transformation_context));
131
132 // Parameter has unsupported type.
133 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 42, 51)
134 .IsApplicable(context.get(), transformation_context));
135
136 // Initializer for a global variable doesn't exist in the module.
137 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 43, 51)
138 .IsApplicable(context.get(), transformation_context));
139
140 // Pointer type for a global variable doesn't exist in the module.
141 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 43, 51)
142 .IsApplicable(context.get(), transformation_context));
143
144 // Function type id is not fresh.
145 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(16, 16, 51)
146 .IsApplicable(context.get(), transformation_context));
147
148 // Global variable id is not fresh.
149 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 16, 16)
150 .IsApplicable(context.get(), transformation_context));
151
152 // Function type fresh id and global variable fresh id are equal.
153 ASSERT_FALSE(TransformationReplaceParameterWithGlobal(50, 16, 50)
154 .IsApplicable(context.get(), transformation_context));
155
156 {
157 TransformationReplaceParameterWithGlobal transformation(50, 16, 51);
158 ASSERT_TRUE(
159 transformation.IsApplicable(context.get(), transformation_context));
160 ApplyAndCheckFreshIds(transformation, context.get(),
161 &transformation_context);
162 }
163 {
164 TransformationReplaceParameterWithGlobal transformation(52, 17, 53);
165 ASSERT_TRUE(
166 transformation.IsApplicable(context.get(), transformation_context));
167 ApplyAndCheckFreshIds(transformation, context.get(),
168 &transformation_context);
169 }
170 {
171 TransformationReplaceParameterWithGlobal transformation(54, 18, 55);
172 ASSERT_TRUE(
173 transformation.IsApplicable(context.get(), transformation_context));
174 ApplyAndCheckFreshIds(transformation, context.get(),
175 &transformation_context);
176 }
177 {
178 TransformationReplaceParameterWithGlobal transformation(56, 19, 57);
179 ASSERT_TRUE(
180 transformation.IsApplicable(context.get(), transformation_context));
181 ApplyAndCheckFreshIds(transformation, context.get(),
182 &transformation_context);
183 }
184 {
185 TransformationReplaceParameterWithGlobal transformation(58, 75, 59);
186 ASSERT_TRUE(
187 transformation.IsApplicable(context.get(), transformation_context));
188 ApplyAndCheckFreshIds(transformation, context.get(),
189 &transformation_context);
190 }
191 {
192 TransformationReplaceParameterWithGlobal transformation(60, 81, 61);
193 ASSERT_TRUE(
194 transformation.IsApplicable(context.get(), transformation_context));
195 ApplyAndCheckFreshIds(transformation, context.get(),
196 &transformation_context);
197 }
198 {
199 TransformationReplaceParameterWithGlobal transformation(62, 91, 63);
200 ASSERT_TRUE(
201 transformation.IsApplicable(context.get(), transformation_context));
202 ApplyAndCheckFreshIds(transformation, context.get(),
203 &transformation_context);
204 }
205
206 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
207 kConsoleMessageConsumer));
208
209 std::string expected_shader = R"(
210 OpCapability Shader
211 %1 = OpExtInstImport "GLSL.std.450"
212 OpMemoryModel Logical GLSL450
213 OpEntryPoint Fragment %4 "main"
214 OpExecutionMode %4 OriginUpperLeft
215 OpSource ESSL 310
216 OpMemberDecorate %13 0 RelaxedPrecision
217 OpDecorate %16 RelaxedPrecision
218 %2 = OpTypeVoid
219 %3 = OpTypeFunction %2
220 %6 = OpTypeInt 32 1
221 %7 = OpTypePointer Private %6
222 %8 = OpTypeFloat 32
223 %9 = OpTypePointer Private %8
224 %10 = OpTypeVector %8 2
225 %11 = OpTypePointer Private %10
226 %12 = OpTypeBool
227 %71 = OpTypeFunction %2 %6
228 %83 = OpTypeFunction %2 %6 %12
229 %93 = OpTypeFunction %2 %10
230 %40 = OpTypePointer Function %12
231 %13 = OpTypeStruct %6 %8
232 %14 = OpTypePointer Private %13
233 %22 = OpConstant %6 0
234 %23 = OpConstant %8 0
235 %26 = OpConstantComposite %10 %23 %23
236 %27 = OpConstantTrue %12
237 %28 = OpConstantComposite %13 %22 %23
238 %51 = OpVariable %7 Private %22
239 %53 = OpVariable %9 Private %23
240 %55 = OpVariable %11 Private %26
241 %57 = OpVariable %14 Private %28
242 %15 = OpTypeFunction %2 %40 %12
243 %59 = OpVariable %7 Private %22
244 %61 = OpVariable %7 Private %22
245 %60 = OpTypeFunction %2 %12
246 %63 = OpVariable %9 Private %23
247 %4 = OpFunction %2 None %3
248 %5 = OpLabel
249 %41 = OpVariable %40 Function %27
250 OpStore %51 %22
251 OpStore %53 %23
252 OpStore %55 %26
253 OpStore %57 %28
254 %33 = OpFunctionCall %2 %20 %41 %27
255 OpReturn
256 OpFunctionEnd
257 %20 = OpFunction %2 None %15
258 %42 = OpFunctionParameter %40
259 %43 = OpFunctionParameter %12
260 %21 = OpLabel
261 %19 = OpLoad %13 %57
262 %18 = OpLoad %10 %55
263 %17 = OpLoad %8 %53
264 %16 = OpLoad %6 %51
265 OpReturn
266 OpFunctionEnd
267 %70 = OpFunction %2 None %71
268 %72 = OpFunctionParameter %6
269 %73 = OpLabel
270 OpReturn
271 OpFunctionEnd
272 %74 = OpFunction %2 None %3
273 %76 = OpLabel
274 %75 = OpLoad %6 %59
275 OpReturn
276 OpFunctionEnd
277 %77 = OpFunction %2 None %83
278 %78 = OpFunctionParameter %6
279 %84 = OpFunctionParameter %12
280 %79 = OpLabel
281 OpReturn
282 OpFunctionEnd
283 %80 = OpFunction %2 None %60
284 %85 = OpFunctionParameter %12
285 %82 = OpLabel
286 %81 = OpLoad %6 %61
287 OpReturn
288 OpFunctionEnd
289 %86 = OpFunction %2 None %93
290 %87 = OpFunctionParameter %10
291 %89 = OpLabel
292 OpReturn
293 OpFunctionEnd
294 %90 = OpFunction %2 None %93
295 %95 = OpFunctionParameter %10
296 %92 = OpLabel
297 %91 = OpLoad %8 %63
298 OpReturn
299 OpFunctionEnd
300 )";
301
302 ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
303 }
304
TEST(TransformationReplaceParameterWithGlobalTest,HandlesIrrelevantParameters)305 TEST(TransformationReplaceParameterWithGlobalTest,
306 HandlesIrrelevantParameters) {
307 std::string shader = R"(
308 OpCapability Shader
309 %1 = OpExtInstImport "GLSL.std.450"
310 OpMemoryModel Logical GLSL450
311 OpEntryPoint Fragment %4 "main"
312 OpExecutionMode %4 OriginUpperLeft
313 OpSource ESSL 310
314 %2 = OpTypeVoid
315 %9 = OpTypeInt 32 1
316 %3 = OpTypeFunction %2
317 %7 = OpTypeFunction %2 %9 %9
318 %12 = OpTypePointer Private %9
319 %13 = OpConstant %9 0
320 %4 = OpFunction %2 None %3
321 %5 = OpLabel
322 OpReturn
323 OpFunctionEnd
324 %6 = OpFunction %2 None %7
325 %10 = OpFunctionParameter %9
326 %11 = OpFunctionParameter %9
327 %8 = OpLabel
328 OpReturn
329 OpFunctionEnd
330 )";
331
332 const auto env = SPV_ENV_UNIVERSAL_1_3;
333 const auto consumer = nullptr;
334 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
335 spvtools::ValidatorOptions validator_options;
336 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
337 kConsoleMessageConsumer));
338 TransformationContext transformation_context(
339 MakeUnique<FactManager>(context.get()), validator_options);
340 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(10);
341
342 {
343 TransformationReplaceParameterWithGlobal transformation(20, 10, 21);
344 ASSERT_TRUE(
345 transformation.IsApplicable(context.get(), transformation_context));
346 ApplyAndCheckFreshIds(transformation, context.get(),
347 &transformation_context);
348 ASSERT_TRUE(
349 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(21));
350 }
351 {
352 TransformationReplaceParameterWithGlobal transformation(22, 11, 23);
353 ASSERT_TRUE(
354 transformation.IsApplicable(context.get(), transformation_context));
355 ApplyAndCheckFreshIds(transformation, context.get(),
356 &transformation_context);
357 ASSERT_FALSE(
358 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(23));
359 }
360 }
361
362 } // namespace
363 } // namespace fuzz
364 } // namespace spvtools
365