1 // Copyright (c) 2020 André Perez Maselco
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_push_id_through_variable.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25
TEST(TransformationPushIdThroughVariableTest,IsApplicable)26 TEST(TransformationPushIdThroughVariableTest, IsApplicable) {
27 std::string reference_shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main" %92 %52 %53
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 OpDecorate %92 BuiltIn FragCoord
35 %2 = OpTypeVoid
36 %3 = OpTypeFunction %2
37 %6 = OpTypeInt 32 1
38 %7 = OpTypeFloat 32
39 %8 = OpTypeStruct %6 %7
40 %9 = OpTypePointer Function %8
41 %10 = OpTypeFunction %6 %9
42 %14 = OpConstant %6 0
43 %15 = OpTypePointer Function %6
44 %51 = OpTypePointer Private %6
45 %21 = OpConstant %6 2
46 %23 = OpConstant %6 1
47 %24 = OpConstant %7 1
48 %25 = OpTypePointer Function %7
49 %50 = OpTypePointer Private %7
50 %34 = OpTypeBool
51 %35 = OpConstantFalse %34
52 %60 = OpConstantNull %50
53 %61 = OpUndef %51
54 %52 = OpVariable %50 Private
55 %53 = OpVariable %51 Private
56 %80 = OpConstantComposite %8 %21 %24
57 %90 = OpTypeVector %7 4
58 %91 = OpTypePointer Input %90
59 %92 = OpVariable %91 Input
60 %93 = OpConstantComposite %90 %24 %24 %24 %24
61 %4 = OpFunction %2 None %3
62 %5 = OpLabel
63 %20 = OpVariable %9 Function
64 %27 = OpVariable %9 Function
65 %22 = OpAccessChain %15 %20 %14
66 %44 = OpCopyObject %9 %20
67 %26 = OpAccessChain %25 %20 %23
68 %29 = OpFunctionCall %6 %12 %27
69 %30 = OpAccessChain %15 %20 %14
70 %45 = OpCopyObject %15 %30
71 %81 = OpCopyObject %9 %27
72 %33 = OpAccessChain %15 %20 %14
73 OpSelectionMerge %37 None
74 OpBranchConditional %35 %36 %37
75 %36 = OpLabel
76 %38 = OpAccessChain %15 %20 %14
77 %40 = OpAccessChain %15 %20 %14
78 %43 = OpAccessChain %15 %20 %14
79 %82 = OpCopyObject %9 %27
80 OpBranch %37
81 %37 = OpLabel
82 OpReturn
83 OpFunctionEnd
84 %12 = OpFunction %6 None %10
85 %11 = OpFunctionParameter %9
86 %13 = OpLabel
87 %46 = OpCopyObject %9 %11
88 %16 = OpAccessChain %15 %11 %14
89 %95 = OpCopyObject %8 %80
90 OpReturnValue %21
91 %100 = OpLabel
92 OpUnreachable
93 OpFunctionEnd
94 )";
95
96 const auto env = SPV_ENV_UNIVERSAL_1_4;
97 const auto consumer = nullptr;
98 const auto context =
99 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
100
101 spvtools::ValidatorOptions validator_options;
102 TransformationContext transformation_context(
103 MakeUnique<FactManager>(context.get()), validator_options);
104 // Tests the reference shader validity.
105 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
106 kConsoleMessageConsumer));
107
108 // Tests |value_synonym_id| and |variable_id| are fresh ids.
109 uint32_t value_id = 21;
110 uint32_t value_synonym_id = 62;
111 uint32_t variable_id = 63;
112 uint32_t initializer_id = 23;
113 uint32_t variable_storage_class = SpvStorageClassPrivate;
114 auto instruction_descriptor =
115 MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
116 auto transformation = TransformationPushIdThroughVariable(
117 value_id, value_synonym_id, variable_id, variable_storage_class,
118 initializer_id, instruction_descriptor);
119 ASSERT_TRUE(
120 transformation.IsApplicable(context.get(), transformation_context));
121
122 // Tests |value_synonym_id| and |variable_id| are non-fresh ids.
123 value_id = 80;
124 value_synonym_id = 60;
125 variable_id = 61;
126 initializer_id = 80;
127 variable_storage_class = SpvStorageClassFunction;
128 instruction_descriptor = MakeInstructionDescriptor(38, SpvOpAccessChain, 0);
129 transformation = TransformationPushIdThroughVariable(
130 value_id, value_synonym_id, variable_id, variable_storage_class,
131 initializer_id, instruction_descriptor);
132 ASSERT_FALSE(
133 transformation.IsApplicable(context.get(), transformation_context));
134
135 // The instruction to insert before is not defined.
136 value_id = 80;
137 value_synonym_id = 62;
138 variable_id = 63;
139 initializer_id = 80;
140 variable_storage_class = SpvStorageClassFunction;
141 instruction_descriptor = MakeInstructionDescriptor(64, SpvOpAccessChain, 0);
142 transformation = TransformationPushIdThroughVariable(
143 value_id, value_synonym_id, variable_id, variable_storage_class,
144 initializer_id, instruction_descriptor);
145 ASSERT_FALSE(
146 transformation.IsApplicable(context.get(), transformation_context));
147
148 // Attempting to insert the store and load instructions
149 // before an OpVariable instruction.
150 value_id = 24;
151 value_synonym_id = 62;
152 variable_id = 63;
153 initializer_id = 24;
154 variable_storage_class = SpvStorageClassFunction;
155 instruction_descriptor = MakeInstructionDescriptor(27, SpvOpVariable, 0);
156 transformation = TransformationPushIdThroughVariable(
157 value_id, value_synonym_id, variable_id, variable_storage_class,
158 initializer_id, instruction_descriptor);
159 ASSERT_FALSE(
160 transformation.IsApplicable(context.get(), transformation_context));
161
162 // The block containing instruction descriptor must be reachable.
163 value_id = 80;
164 value_synonym_id = 62;
165 variable_id = 63;
166 initializer_id = 80;
167 variable_storage_class = SpvStorageClassFunction;
168 instruction_descriptor = MakeInstructionDescriptor(100, SpvOpUnreachable, 0);
169 transformation = TransformationPushIdThroughVariable(
170 value_id, value_synonym_id, variable_id, variable_storage_class,
171 initializer_id, instruction_descriptor);
172 ASSERT_FALSE(
173 transformation.IsApplicable(context.get(), transformation_context));
174
175 // Tests value instruction not available.
176 value_id = 64;
177 value_synonym_id = 62;
178 variable_id = 63;
179 initializer_id = 23;
180 variable_storage_class = SpvStorageClassFunction;
181 instruction_descriptor = MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
182 transformation = TransformationPushIdThroughVariable(
183 value_id, value_synonym_id, variable_id, variable_storage_class,
184 initializer_id, instruction_descriptor);
185 ASSERT_FALSE(
186 transformation.IsApplicable(context.get(), transformation_context));
187
188 // Tests pointer type not available.
189 value_id = 80;
190 value_synonym_id = 62;
191 variable_id = 63;
192 initializer_id = 80;
193 variable_storage_class = SpvStorageClassPrivate;
194 instruction_descriptor = MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
195 transformation = TransformationPushIdThroughVariable(
196 value_id, value_synonym_id, variable_id, variable_storage_class,
197 initializer_id, instruction_descriptor);
198 ASSERT_FALSE(
199 transformation.IsApplicable(context.get(), transformation_context));
200
201 // Tests not a private nor function storage class.
202 value_id = 93;
203 value_synonym_id = 62;
204 variable_id = 63;
205 initializer_id = 93;
206 variable_storage_class = SpvStorageClassInput;
207 instruction_descriptor = MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
208 transformation = TransformationPushIdThroughVariable(
209 value_id, value_synonym_id, variable_id, variable_storage_class,
210 initializer_id, instruction_descriptor);
211 #ifndef NDEBUG
212 ASSERT_DEATH(
213 transformation.IsApplicable(context.get(), transformation_context),
214 "The variable storage class must be private or function");
215 #endif
216
217 // Tests value instruction not available before instruction.
218 value_id = 95;
219 value_synonym_id = 62;
220 variable_id = 63;
221 initializer_id = 80;
222 variable_storage_class = SpvStorageClassFunction;
223 instruction_descriptor = MakeInstructionDescriptor(40, SpvOpAccessChain, 0);
224 transformation = TransformationPushIdThroughVariable(
225 value_id, value_synonym_id, variable_id, variable_storage_class,
226 initializer_id, instruction_descriptor);
227 ASSERT_FALSE(
228 transformation.IsApplicable(context.get(), transformation_context));
229
230 // Variable initializer is not constant.
231 value_id = 95;
232 value_synonym_id = 62;
233 variable_id = 63;
234 initializer_id = 95;
235 variable_storage_class = SpvStorageClassFunction;
236 instruction_descriptor = MakeInstructionDescriptor(40, SpvOpAccessChain, 0);
237 transformation = TransformationPushIdThroughVariable(
238 value_id, value_synonym_id, variable_id, variable_storage_class,
239 initializer_id, instruction_descriptor);
240 ASSERT_FALSE(
241 transformation.IsApplicable(context.get(), transformation_context));
242
243 // Variable initializer has wrong type.
244 value_id = 95;
245 value_synonym_id = 62;
246 variable_id = 63;
247 initializer_id = 93;
248 variable_storage_class = SpvStorageClassFunction;
249 instruction_descriptor = MakeInstructionDescriptor(40, SpvOpAccessChain, 0);
250 transformation = TransformationPushIdThroughVariable(
251 value_id, value_synonym_id, variable_id, variable_storage_class,
252 initializer_id, instruction_descriptor);
253 ASSERT_FALSE(
254 transformation.IsApplicable(context.get(), transformation_context));
255 }
256
TEST(TransformationPushIdThroughVariableTest,Apply)257 TEST(TransformationPushIdThroughVariableTest, Apply) {
258 std::string reference_shader = R"(
259 OpCapability Shader
260 %1 = OpExtInstImport "GLSL.std.450"
261 OpMemoryModel Logical GLSL450
262 OpEntryPoint Fragment %4 "main" %92 %52 %53
263 OpExecutionMode %4 OriginUpperLeft
264 OpSource ESSL 310
265 OpDecorate %92 BuiltIn FragCoord
266 %2 = OpTypeVoid
267 %3 = OpTypeFunction %2
268 %6 = OpTypeInt 32 1
269 %7 = OpTypeFloat 32
270 %8 = OpTypeStruct %6 %7
271 %9 = OpTypePointer Function %8
272 %10 = OpTypeFunction %6 %9
273 %14 = OpConstant %6 0
274 %15 = OpTypePointer Function %6
275 %51 = OpTypePointer Private %6
276 %21 = OpConstant %6 2
277 %23 = OpConstant %6 1
278 %24 = OpConstant %7 1
279 %25 = OpTypePointer Function %7
280 %50 = OpTypePointer Private %7
281 %34 = OpTypeBool
282 %35 = OpConstantFalse %34
283 %60 = OpConstantNull %50
284 %61 = OpUndef %51
285 %52 = OpVariable %50 Private
286 %53 = OpVariable %51 Private
287 %80 = OpConstantComposite %8 %21 %24
288 %90 = OpTypeVector %7 4
289 %91 = OpTypePointer Input %90
290 %92 = OpVariable %91 Input
291 %93 = OpConstantComposite %90 %24 %24 %24 %24
292 %4 = OpFunction %2 None %3
293 %5 = OpLabel
294 %20 = OpVariable %9 Function
295 %27 = OpVariable %9 Function
296 OpStore %53 %21
297 %22 = OpAccessChain %15 %20 %14
298 %44 = OpCopyObject %9 %20
299 %26 = OpAccessChain %25 %20 %23
300 %29 = OpFunctionCall %6 %12 %27
301 %30 = OpAccessChain %15 %20 %14
302 %45 = OpCopyObject %15 %30
303 %81 = OpCopyObject %9 %27
304 %33 = OpAccessChain %15 %20 %14
305 OpSelectionMerge %37 None
306 OpBranchConditional %35 %36 %37
307 %36 = OpLabel
308 %38 = OpAccessChain %15 %20 %14
309 %40 = OpAccessChain %15 %20 %14
310 %43 = OpAccessChain %15 %20 %14
311 %82 = OpCopyObject %9 %27
312 OpBranch %37
313 %37 = OpLabel
314 OpReturn
315 OpFunctionEnd
316 %12 = OpFunction %6 None %10
317 %11 = OpFunctionParameter %9
318 %13 = OpLabel
319 %46 = OpCopyObject %9 %11
320 %16 = OpAccessChain %15 %11 %14
321 %95 = OpCopyObject %8 %80
322 OpReturnValue %21
323 OpFunctionEnd
324 )";
325
326 const auto env = SPV_ENV_UNIVERSAL_1_4;
327 const auto consumer = nullptr;
328 const auto context =
329 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
330
331 spvtools::ValidatorOptions validator_options;
332 TransformationContext transformation_context(
333 MakeUnique<FactManager>(context.get()), validator_options);
334 uint32_t value_id = 80;
335 uint32_t value_synonym_id = 100;
336 uint32_t variable_id = 101;
337 uint32_t initializer_id = 80;
338 uint32_t variable_storage_class = SpvStorageClassFunction;
339 auto instruction_descriptor =
340 MakeInstructionDescriptor(38, SpvOpAccessChain, 0);
341 auto transformation = TransformationPushIdThroughVariable(
342 value_id, value_synonym_id, variable_id, variable_storage_class,
343 initializer_id, instruction_descriptor);
344 ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(value_synonym_id));
345 ASSERT_EQ(nullptr, context->get_instr_block(value_synonym_id));
346 ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(variable_id));
347 ASSERT_EQ(nullptr, context->get_instr_block(variable_id));
348 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
349 ASSERT_EQ(SpvOpLoad,
350 context->get_def_use_mgr()->GetDef(value_synonym_id)->opcode());
351 ASSERT_EQ(36, context->get_instr_block(value_synonym_id)->id());
352 ASSERT_EQ(SpvOpVariable,
353 context->get_def_use_mgr()->GetDef(variable_id)->opcode());
354 ASSERT_EQ(5, context->get_instr_block(variable_id)->id());
355 uint32_t variable_use_count = 0;
356 context->get_def_use_mgr()->ForEachUse(
357 variable_id,
358 [&variable_use_count](opt::Instruction* inst, uint32_t /*unused*/) {
359 ASSERT_TRUE(inst->opcode() == SpvOpLoad ||
360 inst->opcode() == SpvOpStore);
361 variable_use_count++;
362 });
363 ASSERT_EQ(2, variable_use_count);
364
365 value_id = 21;
366 value_synonym_id = 102;
367 variable_id = 103;
368 initializer_id = 21;
369 variable_storage_class = SpvStorageClassFunction;
370 instruction_descriptor = MakeInstructionDescriptor(38, SpvOpAccessChain, 0);
371 transformation = TransformationPushIdThroughVariable(
372 value_id, value_synonym_id, variable_id, variable_storage_class,
373 initializer_id, instruction_descriptor);
374 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
375
376 value_id = 95;
377 value_synonym_id = 104;
378 variable_id = 105;
379 initializer_id = 80;
380 variable_storage_class = SpvStorageClassFunction;
381 instruction_descriptor = MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
382 transformation = TransformationPushIdThroughVariable(
383 value_id, value_synonym_id, variable_id, variable_storage_class,
384 initializer_id, instruction_descriptor);
385 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
386
387 value_id = 80;
388 value_synonym_id = 106;
389 variable_id = 107;
390 initializer_id = 80;
391 variable_storage_class = SpvStorageClassFunction;
392 instruction_descriptor = MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
393 transformation = TransformationPushIdThroughVariable(
394 value_id, value_synonym_id, variable_id, variable_storage_class,
395 initializer_id, instruction_descriptor);
396 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
397
398 value_id = 21;
399 value_synonym_id = 108;
400 variable_id = 109;
401 initializer_id = 21;
402 variable_storage_class = SpvStorageClassPrivate;
403 instruction_descriptor = MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
404 transformation = TransformationPushIdThroughVariable(
405 value_id, value_synonym_id, variable_id, variable_storage_class,
406 initializer_id, instruction_descriptor);
407 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
408
409 value_id = 23;
410 value_synonym_id = 110;
411 variable_id = 111;
412 initializer_id = 21;
413 variable_storage_class = SpvStorageClassPrivate;
414 instruction_descriptor = MakeInstructionDescriptor(27, SpvOpStore, 0);
415 transformation = TransformationPushIdThroughVariable(
416 value_id, value_synonym_id, variable_id, variable_storage_class,
417 initializer_id, instruction_descriptor);
418 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
419
420 std::string variant_shader = R"(
421 OpCapability Shader
422 %1 = OpExtInstImport "GLSL.std.450"
423 OpMemoryModel Logical GLSL450
424 OpEntryPoint Fragment %4 "main" %92 %52 %53 %109 %111
425 OpExecutionMode %4 OriginUpperLeft
426 OpSource ESSL 310
427 OpDecorate %92 BuiltIn FragCoord
428 %2 = OpTypeVoid
429 %3 = OpTypeFunction %2
430 %6 = OpTypeInt 32 1
431 %7 = OpTypeFloat 32
432 %8 = OpTypeStruct %6 %7
433 %9 = OpTypePointer Function %8
434 %10 = OpTypeFunction %6 %9
435 %14 = OpConstant %6 0
436 %15 = OpTypePointer Function %6
437 %51 = OpTypePointer Private %6
438 %21 = OpConstant %6 2
439 %23 = OpConstant %6 1
440 %24 = OpConstant %7 1
441 %25 = OpTypePointer Function %7
442 %50 = OpTypePointer Private %7
443 %34 = OpTypeBool
444 %35 = OpConstantFalse %34
445 %60 = OpConstantNull %50
446 %61 = OpUndef %51
447 %52 = OpVariable %50 Private
448 %53 = OpVariable %51 Private
449 %80 = OpConstantComposite %8 %21 %24
450 %90 = OpTypeVector %7 4
451 %91 = OpTypePointer Input %90
452 %92 = OpVariable %91 Input
453 %93 = OpConstantComposite %90 %24 %24 %24 %24
454 %109 = OpVariable %51 Private %21
455 %111 = OpVariable %51 Private %21
456 %4 = OpFunction %2 None %3
457 %5 = OpLabel
458 %103 = OpVariable %15 Function %21
459 %101 = OpVariable %9 Function %80
460 %20 = OpVariable %9 Function
461 %27 = OpVariable %9 Function
462 OpStore %111 %23
463 %110 = OpLoad %6 %111
464 OpStore %53 %21
465 %22 = OpAccessChain %15 %20 %14
466 %44 = OpCopyObject %9 %20
467 %26 = OpAccessChain %25 %20 %23
468 %29 = OpFunctionCall %6 %12 %27
469 %30 = OpAccessChain %15 %20 %14
470 %45 = OpCopyObject %15 %30
471 %81 = OpCopyObject %9 %27
472 %33 = OpAccessChain %15 %20 %14
473 OpSelectionMerge %37 None
474 OpBranchConditional %35 %36 %37
475 %36 = OpLabel
476 OpStore %101 %80
477 %100 = OpLoad %8 %101
478 OpStore %103 %21
479 %102 = OpLoad %6 %103
480 %38 = OpAccessChain %15 %20 %14
481 %40 = OpAccessChain %15 %20 %14
482 %43 = OpAccessChain %15 %20 %14
483 %82 = OpCopyObject %9 %27
484 OpBranch %37
485 %37 = OpLabel
486 OpReturn
487 OpFunctionEnd
488 %12 = OpFunction %6 None %10
489 %11 = OpFunctionParameter %9
490 %13 = OpLabel
491 %107 = OpVariable %9 Function %80
492 %105 = OpVariable %9 Function %80
493 %46 = OpCopyObject %9 %11
494 %16 = OpAccessChain %15 %11 %14
495 %95 = OpCopyObject %8 %80
496 OpStore %105 %95
497 %104 = OpLoad %8 %105
498 OpStore %107 %80
499 %106 = OpLoad %8 %107
500 OpStore %109 %21
501 %108 = OpLoad %6 %109
502 OpReturnValue %21
503 OpFunctionEnd
504 )";
505
506 ASSERT_TRUE(IsEqual(env, variant_shader, context.get()));
507 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
508 MakeDataDescriptor(80, {}), MakeDataDescriptor(100, {})));
509 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
510 MakeDataDescriptor(21, {}), MakeDataDescriptor(102, {})));
511 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
512 MakeDataDescriptor(95, {}), MakeDataDescriptor(104, {})));
513 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
514 MakeDataDescriptor(80, {}), MakeDataDescriptor(106, {})));
515 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
516 MakeDataDescriptor(21, {}), MakeDataDescriptor(108, {})));
517 }
518
TEST(TransformationPushIdThroughVariableTest,AddSynonymsForRelevantIds)519 TEST(TransformationPushIdThroughVariableTest, AddSynonymsForRelevantIds) {
520 std::string reference_shader = R"(
521 OpCapability Shader
522 %1 = OpExtInstImport "GLSL.std.450"
523 OpMemoryModel Logical GLSL450
524 OpEntryPoint Fragment %4 "main" %92 %52 %53
525 OpExecutionMode %4 OriginUpperLeft
526 OpSource ESSL 310
527 OpDecorate %92 BuiltIn FragCoord
528 %2 = OpTypeVoid
529 %3 = OpTypeFunction %2
530 %6 = OpTypeInt 32 1
531 %7 = OpTypeFloat 32
532 %8 = OpTypeStruct %6 %7
533 %9 = OpTypePointer Function %8
534 %10 = OpTypeFunction %6 %9
535 %14 = OpConstant %6 0
536 %15 = OpTypePointer Function %6
537 %51 = OpTypePointer Private %6
538 %21 = OpConstant %6 2
539 %23 = OpConstant %6 1
540 %24 = OpConstant %7 1
541 %25 = OpTypePointer Function %7
542 %50 = OpTypePointer Private %7
543 %34 = OpTypeBool
544 %35 = OpConstantFalse %34
545 %60 = OpConstantNull %50
546 %61 = OpUndef %51
547 %52 = OpVariable %50 Private
548 %53 = OpVariable %51 Private
549 %80 = OpConstantComposite %8 %21 %24
550 %90 = OpTypeVector %7 4
551 %91 = OpTypePointer Input %90
552 %92 = OpVariable %91 Input
553 %93 = OpConstantComposite %90 %24 %24 %24 %24
554 %4 = OpFunction %2 None %3
555 %5 = OpLabel
556 %20 = OpVariable %9 Function
557 %27 = OpVariable %9 Function
558 %22 = OpAccessChain %15 %20 %14
559 %44 = OpCopyObject %9 %20
560 %26 = OpAccessChain %25 %20 %23
561 %29 = OpFunctionCall %6 %12 %27
562 %30 = OpAccessChain %15 %20 %14
563 %45 = OpCopyObject %15 %30
564 %81 = OpCopyObject %9 %27
565 %33 = OpAccessChain %15 %20 %14
566 OpSelectionMerge %37 None
567 OpBranchConditional %35 %36 %37
568 %36 = OpLabel
569 %38 = OpAccessChain %15 %20 %14
570 %40 = OpAccessChain %15 %20 %14
571 %43 = OpAccessChain %15 %20 %14
572 %82 = OpCopyObject %9 %27
573 OpBranch %37
574 %37 = OpLabel
575 OpReturn
576 OpFunctionEnd
577 %12 = OpFunction %6 None %10
578 %11 = OpFunctionParameter %9
579 %13 = OpLabel
580 %46 = OpCopyObject %9 %11
581 %16 = OpAccessChain %15 %11 %14
582 %95 = OpCopyObject %8 %80
583 OpReturnValue %21
584 %100 = OpLabel
585 OpUnreachable
586 OpFunctionEnd
587 )";
588
589 const auto env = SPV_ENV_UNIVERSAL_1_4;
590 const auto consumer = nullptr;
591 const auto context =
592 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
593
594 spvtools::ValidatorOptions validator_options;
595 TransformationContext transformation_context(
596 MakeUnique<FactManager>(context.get()), validator_options);
597 // Tests the reference shader validity.
598 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
599 kConsoleMessageConsumer));
600
601 uint32_t value_id = 21;
602 uint32_t value_synonym_id = 62;
603 uint32_t variable_id = 63;
604 uint32_t initializer_id = 23;
605 uint32_t variable_storage_class = SpvStorageClassPrivate;
606 auto instruction_descriptor =
607 MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
608 auto transformation = TransformationPushIdThroughVariable(
609 value_id, value_synonym_id, variable_id, variable_storage_class,
610 initializer_id, instruction_descriptor);
611 ASSERT_TRUE(
612 transformation.IsApplicable(context.get(), transformation_context));
613 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
614 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
615 kConsoleMessageConsumer));
616 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
617 MakeDataDescriptor(21, {}), MakeDataDescriptor(62, {})));
618 }
619
TEST(TransformationPushIdThroughVariableTest,DontAddSynonymsForIrrelevantIds)620 TEST(TransformationPushIdThroughVariableTest, DontAddSynonymsForIrrelevantIds) {
621 std::string reference_shader = R"(
622 OpCapability Shader
623 %1 = OpExtInstImport "GLSL.std.450"
624 OpMemoryModel Logical GLSL450
625 OpEntryPoint Fragment %4 "main" %92 %52 %53
626 OpExecutionMode %4 OriginUpperLeft
627 OpSource ESSL 310
628 OpDecorate %92 BuiltIn FragCoord
629 %2 = OpTypeVoid
630 %3 = OpTypeFunction %2
631 %6 = OpTypeInt 32 1
632 %7 = OpTypeFloat 32
633 %8 = OpTypeStruct %6 %7
634 %9 = OpTypePointer Function %8
635 %10 = OpTypeFunction %6 %9
636 %14 = OpConstant %6 0
637 %15 = OpTypePointer Function %6
638 %51 = OpTypePointer Private %6
639 %21 = OpConstant %6 2
640 %23 = OpConstant %6 1
641 %24 = OpConstant %7 1
642 %25 = OpTypePointer Function %7
643 %50 = OpTypePointer Private %7
644 %34 = OpTypeBool
645 %35 = OpConstantFalse %34
646 %60 = OpConstantNull %50
647 %61 = OpUndef %51
648 %52 = OpVariable %50 Private
649 %53 = OpVariable %51 Private
650 %80 = OpConstantComposite %8 %21 %24
651 %90 = OpTypeVector %7 4
652 %91 = OpTypePointer Input %90
653 %92 = OpVariable %91 Input
654 %93 = OpConstantComposite %90 %24 %24 %24 %24
655 %4 = OpFunction %2 None %3
656 %5 = OpLabel
657 %20 = OpVariable %9 Function
658 %27 = OpVariable %9 Function
659 %22 = OpAccessChain %15 %20 %14
660 %44 = OpCopyObject %9 %20
661 %26 = OpAccessChain %25 %20 %23
662 %29 = OpFunctionCall %6 %12 %27
663 %30 = OpAccessChain %15 %20 %14
664 %45 = OpCopyObject %15 %30
665 %81 = OpCopyObject %9 %27
666 %33 = OpAccessChain %15 %20 %14
667 OpSelectionMerge %37 None
668 OpBranchConditional %35 %36 %37
669 %36 = OpLabel
670 %38 = OpAccessChain %15 %20 %14
671 %40 = OpAccessChain %15 %20 %14
672 %43 = OpAccessChain %15 %20 %14
673 %82 = OpCopyObject %9 %27
674 OpBranch %37
675 %37 = OpLabel
676 OpReturn
677 OpFunctionEnd
678 %12 = OpFunction %6 None %10
679 %11 = OpFunctionParameter %9
680 %13 = OpLabel
681 %46 = OpCopyObject %9 %11
682 %16 = OpAccessChain %15 %11 %14
683 %95 = OpCopyObject %8 %80
684 OpReturnValue %21
685 %100 = OpLabel
686 OpUnreachable
687 OpFunctionEnd
688 )";
689
690 const auto env = SPV_ENV_UNIVERSAL_1_4;
691 const auto consumer = nullptr;
692 const auto context =
693 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
694
695 spvtools::ValidatorOptions validator_options;
696 TransformationContext transformation_context(
697 MakeUnique<FactManager>(context.get()), validator_options);
698 // Tests the reference shader validity.
699 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
700 kConsoleMessageConsumer));
701
702 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(21);
703
704 uint32_t value_id = 21;
705 uint32_t value_synonym_id = 62;
706 uint32_t variable_id = 63;
707 uint32_t initializer_id = 23;
708 uint32_t variable_storage_class = SpvStorageClassPrivate;
709 auto instruction_descriptor =
710 MakeInstructionDescriptor(95, SpvOpReturnValue, 0);
711 auto transformation = TransformationPushIdThroughVariable(
712 value_id, value_synonym_id, variable_id, variable_storage_class,
713 initializer_id, instruction_descriptor);
714 ASSERT_TRUE(
715 transformation.IsApplicable(context.get(), transformation_context));
716 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
717 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
718 kConsoleMessageConsumer));
719 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
720 MakeDataDescriptor(21, {}), MakeDataDescriptor(62, {})));
721 }
722
TEST(TransformationPushIdThroughVariableTest,DontAddSynonymsInDeadBlocks)723 TEST(TransformationPushIdThroughVariableTest, DontAddSynonymsInDeadBlocks) {
724 std::string reference_shader = R"(
725 OpCapability Shader
726 %1 = OpExtInstImport "GLSL.std.450"
727 OpMemoryModel Logical GLSL450
728 OpEntryPoint Fragment %4 "main"
729 OpExecutionMode %4 OriginUpperLeft
730 OpSource ESSL 320
731 %2 = OpTypeVoid
732 %3 = OpTypeFunction %2
733 %6 = OpTypeInt 32 1
734 %7 = OpTypeVector %6 2
735 %8 = OpTypePointer Function %7
736 %10 = OpConstant %6 0
737 %11 = OpConstant %6 1
738 %12 = OpConstantComposite %7 %10 %11
739 %13 = OpTypeBool
740 %50 = OpTypePointer Function %13
741 %14 = OpConstantFalse %13
742 %4 = OpFunction %2 None %3
743 %5 = OpLabel
744 %9 = OpVariable %8 Function
745 OpStore %9 %12
746 OpSelectionMerge %16 None
747 OpBranchConditional %14 %15 %16
748 %15 = OpLabel
749 OpBranch %16
750 %16 = OpLabel
751 OpReturn
752 OpFunctionEnd
753 )";
754
755 const auto env = SPV_ENV_UNIVERSAL_1_4;
756 const auto consumer = nullptr;
757 const auto context =
758 BuildModule(env, consumer, reference_shader, kFuzzAssembleOption);
759
760 spvtools::ValidatorOptions validator_options;
761 TransformationContext transformation_context(
762 MakeUnique<FactManager>(context.get()), validator_options);
763 // Tests the reference shader validity.
764 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
765 kConsoleMessageConsumer));
766
767 transformation_context.GetFactManager()->AddFactBlockIsDead(15);
768 auto transformation = TransformationPushIdThroughVariable(
769 14, 100, 101, SpvStorageClassFunction, 14,
770 MakeInstructionDescriptor(15, SpvOpBranch, 0));
771 ASSERT_TRUE(
772 transformation.IsApplicable(context.get(), transformation_context));
773 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
774 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
775 kConsoleMessageConsumer));
776 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
777 MakeDataDescriptor(14, {}), MakeDataDescriptor(100, {})));
778 }
779
780 } // namespace
781 } // namespace fuzz
782 } // namespace spvtools
783