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