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 OpCapability VariablePointers
30 %1 = OpExtInstImport "GLSL.std.450"
31 OpMemoryModel Logical GLSL450
32 OpEntryPoint Fragment %4 "main" %92 %52 %53
33 OpExecutionMode %4 OriginUpperLeft
34 OpSource ESSL 310
35 OpDecorate %92 BuiltIn FragCoord
36 %2 = OpTypeVoid
37 %3 = OpTypeFunction %2
38 %6 = OpTypeInt 32 1
39 %7 = OpTypeFloat 32
40 %8 = OpTypeStruct %6 %7
41 %9 = OpTypePointer Function %8
42 %10 = OpTypeFunction %6 %9
43 %14 = OpConstant %6 0
44 %15 = OpTypePointer Function %6
45 %51 = OpTypePointer Private %6
46 %21 = OpConstant %6 2
47 %23 = OpConstant %6 1
48 %24 = OpConstant %7 1
49 %25 = OpTypePointer Function %7
50 %50 = OpTypePointer Private %7
51 %34 = OpTypeBool
52 %35 = OpConstantFalse %34
53 %60 = OpConstantNull %50
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 OpCapability VariablePointers
261 %1 = OpExtInstImport "GLSL.std.450"
262 OpMemoryModel Logical GLSL450
263 OpEntryPoint Fragment %4 "main" %92 %52 %53
264 OpExecutionMode %4 OriginUpperLeft
265 OpSource ESSL 310
266 OpDecorate %92 BuiltIn FragCoord
267 %2 = OpTypeVoid
268 %3 = OpTypeFunction %2
269 %6 = OpTypeInt 32 1
270 %7 = OpTypeFloat 32
271 %8 = OpTypeStruct %6 %7
272 %9 = OpTypePointer Function %8
273 %10 = OpTypeFunction %6 %9
274 %14 = OpConstant %6 0
275 %15 = OpTypePointer Function %6
276 %51 = OpTypePointer Private %6
277 %21 = OpConstant %6 2
278 %23 = OpConstant %6 1
279 %24 = OpConstant %7 1
280 %25 = OpTypePointer Function %7
281 %50 = OpTypePointer Private %7
282 %34 = OpTypeBool
283 %35 = OpConstantFalse %34
284 %60 = OpConstantNull %50
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 OpCapability VariablePointers
423 %1 = OpExtInstImport "GLSL.std.450"
424 OpMemoryModel Logical GLSL450
425 OpEntryPoint Fragment %4 "main" %92 %52 %53 %109 %111
426 OpExecutionMode %4 OriginUpperLeft
427 OpSource ESSL 310
428 OpDecorate %92 BuiltIn FragCoord
429 %2 = OpTypeVoid
430 %3 = OpTypeFunction %2
431 %6 = OpTypeInt 32 1
432 %7 = OpTypeFloat 32
433 %8 = OpTypeStruct %6 %7
434 %9 = OpTypePointer Function %8
435 %10 = OpTypeFunction %6 %9
436 %14 = OpConstant %6 0
437 %15 = OpTypePointer Function %6
438 %51 = OpTypePointer Private %6
439 %21 = OpConstant %6 2
440 %23 = OpConstant %6 1
441 %24 = OpConstant %7 1
442 %25 = OpTypePointer Function %7
443 %50 = OpTypePointer Private %7
444 %34 = OpTypeBool
445 %35 = OpConstantFalse %34
446 %60 = OpConstantNull %50
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 OpCapability VariablePointers
523 %1 = OpExtInstImport "GLSL.std.450"
524 OpMemoryModel Logical GLSL450
525 OpEntryPoint Fragment %4 "main" %92 %52 %53
526 OpExecutionMode %4 OriginUpperLeft
527 OpSource ESSL 310
528 OpDecorate %92 BuiltIn FragCoord
529 %2 = OpTypeVoid
530 %3 = OpTypeFunction %2
531 %6 = OpTypeInt 32 1
532 %7 = OpTypeFloat 32
533 %8 = OpTypeStruct %6 %7
534 %9 = OpTypePointer Function %8
535 %10 = OpTypeFunction %6 %9
536 %14 = OpConstant %6 0
537 %15 = OpTypePointer Function %6
538 %51 = OpTypePointer Private %6
539 %21 = OpConstant %6 2
540 %23 = OpConstant %6 1
541 %24 = OpConstant %7 1
542 %25 = OpTypePointer Function %7
543 %50 = OpTypePointer Private %7
544 %34 = OpTypeBool
545 %35 = OpConstantFalse %34
546 %60 = OpConstantNull %50
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 OpCapability VariablePointers
624 %1 = OpExtInstImport "GLSL.std.450"
625 OpMemoryModel Logical GLSL450
626 OpEntryPoint Fragment %4 "main" %92 %52 %53
627 OpExecutionMode %4 OriginUpperLeft
628 OpSource ESSL 310
629 OpDecorate %92 BuiltIn FragCoord
630 %2 = OpTypeVoid
631 %3 = OpTypeFunction %2
632 %6 = OpTypeInt 32 1
633 %7 = OpTypeFloat 32
634 %8 = OpTypeStruct %6 %7
635 %9 = OpTypePointer Function %8
636 %10 = OpTypeFunction %6 %9
637 %14 = OpConstant %6 0
638 %15 = OpTypePointer Function %6
639 %51 = OpTypePointer Private %6
640 %21 = OpConstant %6 2
641 %23 = OpConstant %6 1
642 %24 = OpConstant %7 1
643 %25 = OpTypePointer Function %7
644 %50 = OpTypePointer Private %7
645 %34 = OpTypeBool
646 %35 = OpConstantFalse %34
647 %60 = OpConstantNull %50
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