• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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