• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 Google LLC
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_equation_instruction.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(TransformationEquationInstructionTest,SignedNegate)26 TEST(TransformationEquationInstructionTest, SignedNegate) {
27   std::string shader = R"(
28                OpCapability Shader
29           %1 = OpExtInstImport "GLSL.std.450"
30                OpMemoryModel Logical GLSL450
31                OpEntryPoint Fragment %12 "main"
32                OpExecutionMode %12 OriginUpperLeft
33                OpSource ESSL 310
34           %2 = OpTypeVoid
35           %3 = OpTypeFunction %2
36           %6 = OpTypeInt 32 1
37           %7 = OpConstant %6 24
38          %40 = OpTypeBool
39          %41 = OpConstantTrue %40
40          %20 = OpUndef %6
41          %12 = OpFunction %2 None %3
42          %13 = OpLabel
43          %30 = OpCopyObject %6 %7
44                OpReturn
45                OpFunctionEnd
46   )";
47 
48   const auto env = SPV_ENV_UNIVERSAL_1_3;
49   const auto consumer = nullptr;
50   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
51   spvtools::ValidatorOptions validator_options;
52   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
53                                                kConsoleMessageConsumer));
54   TransformationContext transformation_context(
55       MakeUnique<FactManager>(context.get()), validator_options);
56   protobufs::InstructionDescriptor return_instruction =
57       MakeInstructionDescriptor(13, SpvOpReturn, 0);
58 
59   // Bad: id already in use.
60   ASSERT_FALSE(TransformationEquationInstruction(7, SpvOpSNegate, {7},
61                                                  return_instruction)
62                    .IsApplicable(context.get(), transformation_context));
63 
64   // Bad: identified instruction does not exist.
65   ASSERT_FALSE(
66       TransformationEquationInstruction(
67           14, SpvOpSNegate, {7}, MakeInstructionDescriptor(13, SpvOpLoad, 0))
68           .IsApplicable(context.get(), transformation_context));
69 
70   // Bad: id 100 does not exist
71   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpSNegate, {100},
72                                                  return_instruction)
73                    .IsApplicable(context.get(), transformation_context));
74 
75   // Bad: id 20 is an OpUndef
76   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpSNegate, {20},
77                                                  return_instruction)
78                    .IsApplicable(context.get(), transformation_context));
79 
80   // Bad: id 30 is not available right before its definition
81   ASSERT_FALSE(TransformationEquationInstruction(
82                    14, SpvOpSNegate, {30},
83                    MakeInstructionDescriptor(30, SpvOpCopyObject, 0))
84                    .IsApplicable(context.get(), transformation_context));
85 
86   // Bad: too many arguments to OpSNegate.
87   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpSNegate, {7, 7},
88                                                  return_instruction)
89                    .IsApplicable(context.get(), transformation_context));
90 
91   // Bad: 40 is a type id.
92   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpSNegate, {40},
93                                                  return_instruction)
94                    .IsApplicable(context.get(), transformation_context));
95 
96   // Bad: wrong type of argument to OpSNegate.
97   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpSNegate, {41},
98                                                  return_instruction)
99                    .IsApplicable(context.get(), transformation_context));
100 
101   auto transformation1 = TransformationEquationInstruction(
102       14, SpvOpSNegate, {7}, return_instruction);
103   ASSERT_TRUE(
104       transformation1.IsApplicable(context.get(), transformation_context));
105   ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(14));
106   ASSERT_EQ(nullptr, context->get_instr_block(14));
107   ApplyAndCheckFreshIds(transformation1, context.get(),
108                         &transformation_context);
109   ASSERT_EQ(SpvOpSNegate, context->get_def_use_mgr()->GetDef(14)->opcode());
110   ASSERT_EQ(13, context->get_instr_block(14)->id());
111   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
112                                                kConsoleMessageConsumer));
113 
114   auto transformation2 = TransformationEquationInstruction(
115       15, SpvOpSNegate, {14}, return_instruction);
116   ASSERT_TRUE(
117       transformation2.IsApplicable(context.get(), transformation_context));
118   ApplyAndCheckFreshIds(transformation2, context.get(),
119                         &transformation_context);
120   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
121                                                kConsoleMessageConsumer));
122 
123   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
124       MakeDataDescriptor(15, {}), MakeDataDescriptor(7, {})));
125 
126   std::string after_transformation = R"(
127                OpCapability Shader
128           %1 = OpExtInstImport "GLSL.std.450"
129                OpMemoryModel Logical GLSL450
130                OpEntryPoint Fragment %12 "main"
131                OpExecutionMode %12 OriginUpperLeft
132                OpSource ESSL 310
133           %2 = OpTypeVoid
134           %3 = OpTypeFunction %2
135           %6 = OpTypeInt 32 1
136           %7 = OpConstant %6 24
137          %40 = OpTypeBool
138          %41 = OpConstantTrue %40
139          %20 = OpUndef %6
140          %12 = OpFunction %2 None %3
141          %13 = OpLabel
142          %30 = OpCopyObject %6 %7
143          %14 = OpSNegate %6 %7
144          %15 = OpSNegate %6 %14
145                OpReturn
146                OpFunctionEnd
147   )";
148 
149   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
150 }
151 
TEST(TransformationEquationInstructionTest,LogicalNot)152 TEST(TransformationEquationInstructionTest, LogicalNot) {
153   std::string shader = R"(
154                OpCapability Shader
155           %1 = OpExtInstImport "GLSL.std.450"
156                OpMemoryModel Logical GLSL450
157                OpEntryPoint Fragment %12 "main"
158                OpExecutionMode %12 OriginUpperLeft
159                OpSource ESSL 310
160           %2 = OpTypeVoid
161           %3 = OpTypeFunction %2
162           %6 = OpTypeBool
163           %7 = OpConstantTrue %6
164          %20 = OpTypeInt 32 0
165          %21 = OpConstant %20 5
166          %12 = OpFunction %2 None %3
167          %13 = OpLabel
168                OpReturn
169                OpFunctionEnd
170   )";
171 
172   const auto env = SPV_ENV_UNIVERSAL_1_3;
173   const auto consumer = nullptr;
174   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
175   spvtools::ValidatorOptions validator_options;
176   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
177                                                kConsoleMessageConsumer));
178   TransformationContext transformation_context(
179       MakeUnique<FactManager>(context.get()), validator_options);
180   protobufs::InstructionDescriptor return_instruction =
181       MakeInstructionDescriptor(13, SpvOpReturn, 0);
182 
183   // Bad: too few arguments to OpLogicalNot.
184   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpLogicalNot, {},
185                                                  return_instruction)
186                    .IsApplicable(context.get(), transformation_context));
187 
188   // Bad: 6 is a type id.
189   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpLogicalNot, {6},
190                                                  return_instruction)
191                    .IsApplicable(context.get(), transformation_context));
192 
193   // Bad: wrong type of argument to OpLogicalNot.
194   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpLogicalNot, {21},
195                                                  return_instruction)
196                    .IsApplicable(context.get(), transformation_context));
197 
198   auto transformation1 = TransformationEquationInstruction(
199       14, SpvOpLogicalNot, {7}, return_instruction);
200   ASSERT_TRUE(
201       transformation1.IsApplicable(context.get(), transformation_context));
202   ApplyAndCheckFreshIds(transformation1, context.get(),
203                         &transformation_context);
204   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
205                                                kConsoleMessageConsumer));
206 
207   auto transformation2 = TransformationEquationInstruction(
208       15, SpvOpLogicalNot, {14}, return_instruction);
209   ASSERT_TRUE(
210       transformation2.IsApplicable(context.get(), transformation_context));
211   ApplyAndCheckFreshIds(transformation2, context.get(),
212                         &transformation_context);
213   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
214                                                kConsoleMessageConsumer));
215 
216   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
217       MakeDataDescriptor(15, {}), MakeDataDescriptor(7, {})));
218 
219   std::string after_transformation = R"(
220                OpCapability Shader
221           %1 = OpExtInstImport "GLSL.std.450"
222                OpMemoryModel Logical GLSL450
223                OpEntryPoint Fragment %12 "main"
224                OpExecutionMode %12 OriginUpperLeft
225                OpSource ESSL 310
226           %2 = OpTypeVoid
227           %3 = OpTypeFunction %2
228           %6 = OpTypeBool
229           %7 = OpConstantTrue %6
230          %20 = OpTypeInt 32 0
231          %21 = OpConstant %20 5
232          %12 = OpFunction %2 None %3
233          %13 = OpLabel
234          %14 = OpLogicalNot %6 %7
235          %15 = OpLogicalNot %6 %14
236                OpReturn
237                OpFunctionEnd
238   )";
239 
240   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
241 }
242 
TEST(TransformationEquationInstructionTest,AddSubNegate1)243 TEST(TransformationEquationInstructionTest, AddSubNegate1) {
244   std::string shader = R"(
245                OpCapability Shader
246           %1 = OpExtInstImport "GLSL.std.450"
247                OpMemoryModel Logical GLSL450
248                OpEntryPoint Fragment %12 "main"
249                OpExecutionMode %12 OriginUpperLeft
250                OpSource ESSL 310
251           %2 = OpTypeVoid
252           %3 = OpTypeFunction %2
253           %6 = OpTypeInt 32 1
254          %30 = OpTypeVector %6 3
255          %15 = OpConstant %6 24
256          %16 = OpConstant %6 37
257          %31 = OpConstantComposite %30 %15 %16 %15
258          %33 = OpTypeBool
259          %32 = OpConstantTrue %33
260          %12 = OpFunction %2 None %3
261          %13 = OpLabel
262                OpReturn
263                OpFunctionEnd
264   )";
265 
266   const auto env = SPV_ENV_UNIVERSAL_1_3;
267   const auto consumer = nullptr;
268   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
269   spvtools::ValidatorOptions validator_options;
270   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
271                                                kConsoleMessageConsumer));
272   TransformationContext transformation_context(
273       MakeUnique<FactManager>(context.get()), validator_options);
274   protobufs::InstructionDescriptor return_instruction =
275       MakeInstructionDescriptor(13, SpvOpReturn, 0);
276 
277   // Bad: too many arguments to OpIAdd.
278   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpIAdd, {15, 16, 16},
279                                                  return_instruction)
280                    .IsApplicable(context.get(), transformation_context));
281   // Bad: boolean argument to OpIAdd.
282   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpIAdd, {15, 32},
283                                                  return_instruction)
284                    .IsApplicable(context.get(), transformation_context));
285   // Bad: type as argument to OpIAdd.
286   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpIAdd, {33, 16},
287                                                  return_instruction)
288                    .IsApplicable(context.get(), transformation_context));
289   // Bad: arguments of mismatched widths
290   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpIAdd, {15, 31},
291                                                  return_instruction)
292                    .IsApplicable(context.get(), transformation_context));
293   // Bad: arguments of mismatched widths
294   ASSERT_FALSE(TransformationEquationInstruction(14, SpvOpIAdd, {31, 15},
295                                                  return_instruction)
296                    .IsApplicable(context.get(), transformation_context));
297 
298   auto transformation1 = TransformationEquationInstruction(
299       14, SpvOpIAdd, {15, 16}, return_instruction);
300   ASSERT_TRUE(
301       transformation1.IsApplicable(context.get(), transformation_context));
302   ApplyAndCheckFreshIds(transformation1, context.get(),
303                         &transformation_context);
304   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
305                                                kConsoleMessageConsumer));
306 
307   auto transformation2 = TransformationEquationInstruction(
308       19, SpvOpISub, {14, 16}, return_instruction);
309   ASSERT_TRUE(
310       transformation2.IsApplicable(context.get(), transformation_context));
311   ApplyAndCheckFreshIds(transformation2, context.get(),
312                         &transformation_context);
313   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
314                                                kConsoleMessageConsumer));
315   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
316       MakeDataDescriptor(15, {}), MakeDataDescriptor(19, {})));
317 
318   auto transformation3 = TransformationEquationInstruction(
319       20, SpvOpISub, {14, 15}, return_instruction);
320   ASSERT_TRUE(
321       transformation3.IsApplicable(context.get(), transformation_context));
322   ApplyAndCheckFreshIds(transformation3, context.get(),
323                         &transformation_context);
324   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
325                                                kConsoleMessageConsumer));
326   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
327       MakeDataDescriptor(20, {}), MakeDataDescriptor(16, {})));
328 
329   auto transformation4 = TransformationEquationInstruction(
330       22, SpvOpISub, {16, 14}, return_instruction);
331   ASSERT_TRUE(
332       transformation4.IsApplicable(context.get(), transformation_context));
333   ApplyAndCheckFreshIds(transformation4, context.get(),
334                         &transformation_context);
335   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
336                                                kConsoleMessageConsumer));
337 
338   auto transformation5 = TransformationEquationInstruction(
339       24, SpvOpSNegate, {22}, return_instruction);
340   ASSERT_TRUE(
341       transformation5.IsApplicable(context.get(), transformation_context));
342   ApplyAndCheckFreshIds(transformation5, context.get(),
343                         &transformation_context);
344   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
345                                                kConsoleMessageConsumer));
346   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
347       MakeDataDescriptor(24, {}), MakeDataDescriptor(15, {})));
348 
349   std::string after_transformation = R"(
350                OpCapability Shader
351           %1 = OpExtInstImport "GLSL.std.450"
352                OpMemoryModel Logical GLSL450
353                OpEntryPoint Fragment %12 "main"
354                OpExecutionMode %12 OriginUpperLeft
355                OpSource ESSL 310
356           %2 = OpTypeVoid
357           %3 = OpTypeFunction %2
358           %6 = OpTypeInt 32 1
359          %30 = OpTypeVector %6 3
360          %15 = OpConstant %6 24
361          %16 = OpConstant %6 37
362          %31 = OpConstantComposite %30 %15 %16 %15
363          %33 = OpTypeBool
364          %32 = OpConstantTrue %33
365          %12 = OpFunction %2 None %3
366          %13 = OpLabel
367          %14 = OpIAdd %6 %15 %16
368          %19 = OpISub %6 %14 %16 ; ==> synonymous(%19, %15)
369          %20 = OpISub %6 %14 %15 ; ==> synonymous(%20, %16)
370          %22 = OpISub %6 %16 %14
371          %24 = OpSNegate %6 %22 ; ==> synonymous(%24, %15)
372                OpReturn
373                OpFunctionEnd
374   )";
375 
376   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
377 }
378 
TEST(TransformationEquationInstructionTest,AddSubNegate2)379 TEST(TransformationEquationInstructionTest, AddSubNegate2) {
380   std::string shader = R"(
381                OpCapability Shader
382           %1 = OpExtInstImport "GLSL.std.450"
383                OpMemoryModel Logical GLSL450
384                OpEntryPoint Fragment %12 "main"
385                OpExecutionMode %12 OriginUpperLeft
386                OpSource ESSL 310
387           %2 = OpTypeVoid
388           %3 = OpTypeFunction %2
389           %6 = OpTypeInt 32 1
390          %15 = OpConstant %6 24
391          %16 = OpConstant %6 37
392          %12 = OpFunction %2 None %3
393          %13 = OpLabel
394                OpReturn
395                OpFunctionEnd
396   )";
397 
398   const auto env = SPV_ENV_UNIVERSAL_1_3;
399   const auto consumer = nullptr;
400   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
401   spvtools::ValidatorOptions validator_options;
402   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
403                                                kConsoleMessageConsumer));
404   TransformationContext transformation_context(
405       MakeUnique<FactManager>(context.get()), validator_options);
406   protobufs::InstructionDescriptor return_instruction =
407       MakeInstructionDescriptor(13, SpvOpReturn, 0);
408 
409   auto transformation1 = TransformationEquationInstruction(
410       14, SpvOpISub, {15, 16}, return_instruction);
411   ASSERT_TRUE(
412       transformation1.IsApplicable(context.get(), transformation_context));
413   ApplyAndCheckFreshIds(transformation1, context.get(),
414                         &transformation_context);
415   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
416                                                kConsoleMessageConsumer));
417 
418   auto transformation2 = TransformationEquationInstruction(
419       17, SpvOpIAdd, {14, 16}, return_instruction);
420   ASSERT_TRUE(
421       transformation2.IsApplicable(context.get(), transformation_context));
422   ApplyAndCheckFreshIds(transformation2, context.get(),
423                         &transformation_context);
424   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
425                                                kConsoleMessageConsumer));
426   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
427       MakeDataDescriptor(17, {}), MakeDataDescriptor(15, {})));
428 
429   auto transformation3 = TransformationEquationInstruction(
430       18, SpvOpIAdd, {16, 14}, return_instruction);
431   ASSERT_TRUE(
432       transformation3.IsApplicable(context.get(), transformation_context));
433   ApplyAndCheckFreshIds(transformation3, context.get(),
434                         &transformation_context);
435   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
436                                                kConsoleMessageConsumer));
437   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
438       MakeDataDescriptor(17, {}), MakeDataDescriptor(18, {})));
439   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
440       MakeDataDescriptor(18, {}), MakeDataDescriptor(15, {})));
441 
442   auto transformation4 = TransformationEquationInstruction(
443       19, SpvOpISub, {14, 15}, return_instruction);
444   ASSERT_TRUE(
445       transformation4.IsApplicable(context.get(), transformation_context));
446   ApplyAndCheckFreshIds(transformation4, context.get(),
447                         &transformation_context);
448   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
449                                                kConsoleMessageConsumer));
450 
451   auto transformation5 = TransformationEquationInstruction(
452       20, SpvOpSNegate, {19}, return_instruction);
453   ASSERT_TRUE(
454       transformation5.IsApplicable(context.get(), transformation_context));
455   ApplyAndCheckFreshIds(transformation5, context.get(),
456                         &transformation_context);
457   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
458                                                kConsoleMessageConsumer));
459   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
460       MakeDataDescriptor(20, {}), MakeDataDescriptor(16, {})));
461 
462   auto transformation6 = TransformationEquationInstruction(
463       21, SpvOpISub, {14, 19}, return_instruction);
464   ASSERT_TRUE(
465       transformation6.IsApplicable(context.get(), transformation_context));
466   ApplyAndCheckFreshIds(transformation6, context.get(),
467                         &transformation_context);
468   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
469                                                kConsoleMessageConsumer));
470   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
471       MakeDataDescriptor(21, {}), MakeDataDescriptor(15, {})));
472 
473   auto transformation7 = TransformationEquationInstruction(
474       22, SpvOpISub, {14, 18}, return_instruction);
475   ASSERT_TRUE(
476       transformation7.IsApplicable(context.get(), transformation_context));
477   ApplyAndCheckFreshIds(transformation7, context.get(),
478                         &transformation_context);
479   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
480                                                kConsoleMessageConsumer));
481 
482   auto transformation8 = TransformationEquationInstruction(
483       23, SpvOpSNegate, {22}, return_instruction);
484   ASSERT_TRUE(
485       transformation8.IsApplicable(context.get(), transformation_context));
486   ApplyAndCheckFreshIds(transformation8, context.get(),
487                         &transformation_context);
488   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
489                                                kConsoleMessageConsumer));
490   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
491       MakeDataDescriptor(23, {}), MakeDataDescriptor(16, {})));
492 
493   std::string after_transformation = R"(
494                OpCapability Shader
495           %1 = OpExtInstImport "GLSL.std.450"
496                OpMemoryModel Logical GLSL450
497                OpEntryPoint Fragment %12 "main"
498                OpExecutionMode %12 OriginUpperLeft
499                OpSource ESSL 310
500           %2 = OpTypeVoid
501           %3 = OpTypeFunction %2
502           %6 = OpTypeInt 32 1
503          %15 = OpConstant %6 24
504          %16 = OpConstant %6 37
505          %12 = OpFunction %2 None %3
506          %13 = OpLabel
507          %14 = OpISub %6 %15 %16
508          %17 = OpIAdd %6 %14 %16 ; ==> synonymous(%17, %15)
509          %18 = OpIAdd %6 %16 %14 ; ==> synonymous(%17, %18, %15)
510          %19 = OpISub %6 %14 %15
511          %20 = OpSNegate %6 %19 ; ==> synonymous(%20, %16)
512          %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15)
513          %22 = OpISub %6 %14 %18
514          %23 = OpSNegate %6 %22 ; ==> synonymous(%23, %16)
515                OpReturn
516                OpFunctionEnd
517   )";
518 
519   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
520 }
521 
TEST(TransformationEquationInstructionTest,Bitcast)522 TEST(TransformationEquationInstructionTest, Bitcast) {
523   std::string shader = R"(
524                OpCapability Shader
525           %1 = OpExtInstImport "GLSL.std.450"
526                OpMemoryModel Logical GLSL450
527                OpEntryPoint Fragment %12 "main"
528                OpExecutionMode %12 OriginUpperLeft
529                OpSource ESSL 310
530           %2 = OpTypeVoid
531           %3 = OpTypeFunction %2
532           %6 = OpTypeInt 32 1
533           %7 = OpTypeInt 32 0
534           %8 = OpTypeFloat 32
535           %9 = OpTypeVector %6 2
536          %10 = OpTypeVector %7 2
537          %11 = OpTypeVector %8 2
538          %21 = OpTypeBool
539          %22 = OpTypeVector %21 2
540          %15 = OpConstant %6 24
541          %16 = OpConstant %7 24
542          %17 = OpConstant %8 24
543          %18 = OpConstantComposite %9 %15 %15
544          %19 = OpConstantComposite %10 %16 %16
545          %20 = OpConstantComposite %11 %17 %17
546          %23 = OpConstantTrue %21
547          %24 = OpConstantComposite %22 %23 %23
548          %12 = OpFunction %2 None %3
549          %13 = OpLabel
550                OpReturn
551                OpFunctionEnd
552   )";
553 
554   const auto env = SPV_ENV_UNIVERSAL_1_3;
555   const auto consumer = nullptr;
556   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
557   spvtools::ValidatorOptions validator_options;
558   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
559                                                kConsoleMessageConsumer));
560   TransformationContext transformation_context(
561       MakeUnique<FactManager>(context.get()), validator_options);
562   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
563 
564   // Too many operands.
565   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpBitcast, {15, 16},
566                                                  insert_before)
567                    .IsApplicable(context.get(), transformation_context));
568 
569   // Too few operands.
570   ASSERT_FALSE(
571       TransformationEquationInstruction(50, SpvOpBitcast, {}, insert_before)
572           .IsApplicable(context.get(), transformation_context));
573 
574   // Operand's id is invalid.
575   ASSERT_FALSE(
576       TransformationEquationInstruction(50, SpvOpBitcast, {50}, insert_before)
577           .IsApplicable(context.get(), transformation_context));
578 
579   // Operand's type is invalid
580   ASSERT_FALSE(
581       TransformationEquationInstruction(50, SpvOpBitcast, {13}, insert_before)
582           .IsApplicable(context.get(), transformation_context));
583 
584   // Operand must be a scalar or a vector of numerical type.
585 #ifndef NDEBUG
586   ASSERT_DEATH(
587       TransformationEquationInstruction(50, SpvOpBitcast, {23}, insert_before)
588           .IsApplicable(context.get(), transformation_context),
589       "Operand is not a scalar or a vector of numerical type");
590   ASSERT_DEATH(
591       TransformationEquationInstruction(50, SpvOpBitcast, {24}, insert_before)
592           .IsApplicable(context.get(), transformation_context),
593       "Only vectors of numerical components are supported");
594 #else
595   ASSERT_FALSE(
596       TransformationEquationInstruction(50, SpvOpBitcast, {23}, insert_before)
597           .IsApplicable(context.get(), transformation_context));
598   ASSERT_FALSE(
599       TransformationEquationInstruction(50, SpvOpBitcast, {24}, insert_before)
600           .IsApplicable(context.get(), transformation_context));
601 #endif
602 
603   for (uint32_t operand_id = 15, fresh_id = 50; operand_id <= 20;
604        ++operand_id, ++fresh_id) {
605     TransformationEquationInstruction transformation(
606         fresh_id, SpvOpBitcast, {operand_id}, insert_before);
607     ASSERT_TRUE(
608         transformation.IsApplicable(context.get(), transformation_context));
609     ApplyAndCheckFreshIds(transformation, context.get(),
610                           &transformation_context);
611   }
612 
613   std::string expected_shader = R"(
614                OpCapability Shader
615           %1 = OpExtInstImport "GLSL.std.450"
616                OpMemoryModel Logical GLSL450
617                OpEntryPoint Fragment %12 "main"
618                OpExecutionMode %12 OriginUpperLeft
619                OpSource ESSL 310
620           %2 = OpTypeVoid
621           %3 = OpTypeFunction %2
622           %6 = OpTypeInt 32 1
623           %7 = OpTypeInt 32 0
624           %8 = OpTypeFloat 32
625           %9 = OpTypeVector %6 2
626          %10 = OpTypeVector %7 2
627          %11 = OpTypeVector %8 2
628          %21 = OpTypeBool
629          %22 = OpTypeVector %21 2
630          %15 = OpConstant %6 24
631          %16 = OpConstant %7 24
632          %17 = OpConstant %8 24
633          %18 = OpConstantComposite %9 %15 %15
634          %19 = OpConstantComposite %10 %16 %16
635          %20 = OpConstantComposite %11 %17 %17
636          %23 = OpConstantTrue %21
637          %24 = OpConstantComposite %22 %23 %23
638          %12 = OpFunction %2 None %3
639          %13 = OpLabel
640          %50 = OpBitcast %8 %15
641          %51 = OpBitcast %8 %16
642          %52 = OpBitcast %6 %17
643          %53 = OpBitcast %11 %18
644          %54 = OpBitcast %11 %19
645          %55 = OpBitcast %9 %20
646                OpReturn
647                OpFunctionEnd
648   )";
649 
650   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
651 }
652 
TEST(TransformationEquationInstructionTest,BitcastResultTypeFloatDoesNotExist)653 TEST(TransformationEquationInstructionTest,
654      BitcastResultTypeFloatDoesNotExist) {
655   std::string shader = R"(
656                OpCapability Shader
657           %1 = OpExtInstImport "GLSL.std.450"
658                OpMemoryModel Logical GLSL450
659                OpEntryPoint Fragment %12 "main"
660                OpExecutionMode %12 OriginUpperLeft
661                OpSource ESSL 310
662           %2 = OpTypeVoid
663           %3 = OpTypeFunction %2
664           %6 = OpTypeInt 32 1
665           %7 = OpTypeInt 32 0
666           %9 = OpTypeVector %6 2
667          %10 = OpTypeVector %7 2
668          %15 = OpConstant %6 24
669          %16 = OpConstant %7 24
670          %18 = OpConstantComposite %9 %15 %15
671          %19 = OpConstantComposite %10 %16 %16
672          %12 = OpFunction %2 None %3
673          %13 = OpLabel
674                OpReturn
675                OpFunctionEnd
676   )";
677 
678   const auto env = SPV_ENV_UNIVERSAL_1_3;
679   const auto consumer = nullptr;
680   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
681   spvtools::ValidatorOptions validator_options;
682   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
683                                                kConsoleMessageConsumer));
684   TransformationContext transformation_context(
685       MakeUnique<FactManager>(context.get()), validator_options);
686   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
687 
688   // Scalar floating-point type does not exist.
689   ASSERT_FALSE(
690       TransformationEquationInstruction(50, SpvOpBitcast, {15}, insert_before)
691           .IsApplicable(context.get(), transformation_context));
692   ASSERT_FALSE(
693       TransformationEquationInstruction(50, SpvOpBitcast, {16}, insert_before)
694           .IsApplicable(context.get(), transformation_context));
695 
696   // Vector of floating-point components does not exist.
697   ASSERT_FALSE(
698       TransformationEquationInstruction(50, SpvOpBitcast, {18}, insert_before)
699           .IsApplicable(context.get(), transformation_context));
700   ASSERT_FALSE(
701       TransformationEquationInstruction(50, SpvOpBitcast, {19}, insert_before)
702           .IsApplicable(context.get(), transformation_context));
703 }
704 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist1)705 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist1) {
706   std::string shader = R"(
707                OpCapability Shader
708           %1 = OpExtInstImport "GLSL.std.450"
709                OpMemoryModel Logical GLSL450
710                OpEntryPoint Fragment %12 "main"
711                OpExecutionMode %12 OriginUpperLeft
712                OpSource ESSL 310
713           %2 = OpTypeVoid
714           %3 = OpTypeFunction %2
715           %8 = OpTypeFloat 32
716          %11 = OpTypeVector %8 2
717          %17 = OpConstant %8 24
718          %20 = OpConstantComposite %11 %17 %17
719          %12 = OpFunction %2 None %3
720          %13 = OpLabel
721                OpReturn
722                OpFunctionEnd
723   )";
724 
725   const auto env = SPV_ENV_UNIVERSAL_1_3;
726   const auto consumer = nullptr;
727   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
728   spvtools::ValidatorOptions validator_options;
729   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
730                                                kConsoleMessageConsumer));
731   TransformationContext transformation_context(
732       MakeUnique<FactManager>(context.get()), validator_options);
733   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
734 
735   // Scalar integral type does not exist.
736   ASSERT_FALSE(
737       TransformationEquationInstruction(50, SpvOpBitcast, {17}, insert_before)
738           .IsApplicable(context.get(), transformation_context));
739 
740   // Vector of integral components does not exist.
741   ASSERT_FALSE(
742       TransformationEquationInstruction(50, SpvOpBitcast, {20}, insert_before)
743           .IsApplicable(context.get(), transformation_context));
744 }
745 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist2)746 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist2) {
747   std::string shader = R"(
748                OpCapability Shader
749           %1 = OpExtInstImport "GLSL.std.450"
750                OpMemoryModel Logical GLSL450
751                OpEntryPoint Fragment %12 "main"
752                OpExecutionMode %12 OriginUpperLeft
753                OpSource ESSL 310
754           %2 = OpTypeVoid
755           %3 = OpTypeFunction %2
756           %4 = OpTypeInt 32 0
757           %8 = OpTypeFloat 32
758           %9 = OpTypeVector %4 2
759          %11 = OpTypeVector %8 2
760          %17 = OpConstant %8 24
761          %20 = OpConstantComposite %11 %17 %17
762          %12 = OpFunction %2 None %3
763          %13 = OpLabel
764                OpReturn
765                OpFunctionEnd
766   )";
767 
768   const auto env = SPV_ENV_UNIVERSAL_1_3;
769   const auto consumer = nullptr;
770   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
771   spvtools::ValidatorOptions validator_options;
772   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
773                                                kConsoleMessageConsumer));
774   TransformationContext transformation_context(
775       MakeUnique<FactManager>(context.get()), validator_options);
776   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
777 
778   {
779     TransformationEquationInstruction transformation(50, SpvOpBitcast, {17},
780                                                      insert_before);
781     ASSERT_TRUE(
782         transformation.IsApplicable(context.get(), transformation_context));
783     ApplyAndCheckFreshIds(transformation, context.get(),
784                           &transformation_context);
785   }
786   {
787     TransformationEquationInstruction transformation(51, SpvOpBitcast, {20},
788                                                      insert_before);
789     ASSERT_TRUE(
790         transformation.IsApplicable(context.get(), transformation_context));
791     ApplyAndCheckFreshIds(transformation, context.get(),
792                           &transformation_context);
793   }
794 
795   std::string expected_shader = R"(
796                OpCapability Shader
797           %1 = OpExtInstImport "GLSL.std.450"
798                OpMemoryModel Logical GLSL450
799                OpEntryPoint Fragment %12 "main"
800                OpExecutionMode %12 OriginUpperLeft
801                OpSource ESSL 310
802           %2 = OpTypeVoid
803           %3 = OpTypeFunction %2
804           %4 = OpTypeInt 32 0
805           %8 = OpTypeFloat 32
806           %9 = OpTypeVector %4 2
807          %11 = OpTypeVector %8 2
808          %17 = OpConstant %8 24
809          %20 = OpConstantComposite %11 %17 %17
810          %12 = OpFunction %2 None %3
811          %13 = OpLabel
812          %50 = OpBitcast %4 %17
813          %51 = OpBitcast %9 %20
814                OpReturn
815                OpFunctionEnd
816   )";
817 
818   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
819 }
820 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist3)821 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist3) {
822   std::string shader = R"(
823                OpCapability Shader
824           %1 = OpExtInstImport "GLSL.std.450"
825                OpMemoryModel Logical GLSL450
826                OpEntryPoint Fragment %12 "main"
827                OpExecutionMode %12 OriginUpperLeft
828                OpSource ESSL 310
829           %2 = OpTypeVoid
830           %3 = OpTypeFunction %2
831           %4 = OpTypeInt 32 1
832           %8 = OpTypeFloat 32
833           %9 = OpTypeVector %4 2
834          %11 = OpTypeVector %8 2
835          %17 = OpConstant %8 24
836          %20 = OpConstantComposite %11 %17 %17
837          %12 = OpFunction %2 None %3
838          %13 = OpLabel
839                OpReturn
840                OpFunctionEnd
841   )";
842 
843   const auto env = SPV_ENV_UNIVERSAL_1_3;
844   const auto consumer = nullptr;
845   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
846   spvtools::ValidatorOptions validator_options;
847   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
848                                                kConsoleMessageConsumer));
849   TransformationContext transformation_context(
850       MakeUnique<FactManager>(context.get()), validator_options);
851   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
852 
853   {
854     TransformationEquationInstruction transformation(50, SpvOpBitcast, {17},
855                                                      insert_before);
856     ASSERT_TRUE(
857         transformation.IsApplicable(context.get(), transformation_context));
858     ApplyAndCheckFreshIds(transformation, context.get(),
859                           &transformation_context);
860   }
861   {
862     TransformationEquationInstruction transformation(51, SpvOpBitcast, {20},
863                                                      insert_before);
864     ASSERT_TRUE(
865         transformation.IsApplicable(context.get(), transformation_context));
866     ApplyAndCheckFreshIds(transformation, context.get(),
867                           &transformation_context);
868   }
869 
870   std::string expected_shader = R"(
871                OpCapability Shader
872           %1 = OpExtInstImport "GLSL.std.450"
873                OpMemoryModel Logical GLSL450
874                OpEntryPoint Fragment %12 "main"
875                OpExecutionMode %12 OriginUpperLeft
876                OpSource ESSL 310
877           %2 = OpTypeVoid
878           %3 = OpTypeFunction %2
879           %4 = OpTypeInt 32 1
880           %8 = OpTypeFloat 32
881           %9 = OpTypeVector %4 2
882          %11 = OpTypeVector %8 2
883          %17 = OpConstant %8 24
884          %20 = OpConstantComposite %11 %17 %17
885          %12 = OpFunction %2 None %3
886          %13 = OpLabel
887          %50 = OpBitcast %4 %17
888          %51 = OpBitcast %9 %20
889                OpReturn
890                OpFunctionEnd
891   )";
892 
893   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
894 }
895 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist4)896 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist4) {
897   std::string shader = R"(
898                OpCapability Shader
899           %1 = OpExtInstImport "GLSL.std.450"
900                OpMemoryModel Logical GLSL450
901                OpEntryPoint Fragment %12 "main"
902                OpExecutionMode %12 OriginUpperLeft
903                OpSource ESSL 310
904           %2 = OpTypeVoid
905           %3 = OpTypeFunction %2
906           %4 = OpTypeInt 32 1
907           %8 = OpTypeFloat 32
908          %11 = OpTypeVector %8 2
909          %17 = OpConstant %8 24
910          %20 = OpConstantComposite %11 %17 %17
911          %12 = OpFunction %2 None %3
912          %13 = OpLabel
913                OpReturn
914                OpFunctionEnd
915   )";
916 
917   const auto env = SPV_ENV_UNIVERSAL_1_3;
918   const auto consumer = nullptr;
919   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
920   spvtools::ValidatorOptions validator_options;
921   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
922                                                kConsoleMessageConsumer));
923   TransformationContext transformation_context(
924       MakeUnique<FactManager>(context.get()), validator_options);
925   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
926 
927   {
928     TransformationEquationInstruction transformation(50, SpvOpBitcast, {17},
929                                                      insert_before);
930     ASSERT_TRUE(
931         transformation.IsApplicable(context.get(), transformation_context));
932     ApplyAndCheckFreshIds(transformation, context.get(),
933                           &transformation_context);
934   }
935 
936   ASSERT_FALSE(
937       TransformationEquationInstruction(51, SpvOpBitcast, {20}, insert_before)
938           .IsApplicable(context.get(), transformation_context));
939 
940   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
941                                                kConsoleMessageConsumer));
942 
943   std::string expected_shader = R"(
944                OpCapability Shader
945           %1 = OpExtInstImport "GLSL.std.450"
946                OpMemoryModel Logical GLSL450
947                OpEntryPoint Fragment %12 "main"
948                OpExecutionMode %12 OriginUpperLeft
949                OpSource ESSL 310
950           %2 = OpTypeVoid
951           %3 = OpTypeFunction %2
952           %4 = OpTypeInt 32 1
953           %8 = OpTypeFloat 32
954          %11 = OpTypeVector %8 2
955          %17 = OpConstant %8 24
956          %20 = OpConstantComposite %11 %17 %17
957          %12 = OpFunction %2 None %3
958          %13 = OpLabel
959          %50 = OpBitcast %4 %17
960                OpReturn
961                OpFunctionEnd
962   )";
963 
964   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
965 }
966 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist5)967 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist5) {
968   std::string shader = R"(
969                OpCapability Shader
970           %1 = OpExtInstImport "GLSL.std.450"
971                OpMemoryModel Logical GLSL450
972                OpEntryPoint Fragment %12 "main"
973                OpExecutionMode %12 OriginUpperLeft
974                OpSource ESSL 310
975           %2 = OpTypeVoid
976           %3 = OpTypeFunction %2
977           %4 = OpTypeInt 32 0
978           %8 = OpTypeFloat 32
979          %11 = OpTypeVector %8 2
980          %17 = OpConstant %8 24
981          %20 = OpConstantComposite %11 %17 %17
982          %12 = OpFunction %2 None %3
983          %13 = OpLabel
984                OpReturn
985                OpFunctionEnd
986   )";
987 
988   const auto env = SPV_ENV_UNIVERSAL_1_3;
989   const auto consumer = nullptr;
990   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
991   spvtools::ValidatorOptions validator_options;
992   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
993                                                kConsoleMessageConsumer));
994   TransformationContext transformation_context(
995       MakeUnique<FactManager>(context.get()), validator_options);
996   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
997 
998   {
999     TransformationEquationInstruction transformation(50, SpvOpBitcast, {17},
1000                                                      insert_before);
1001     ASSERT_TRUE(
1002         transformation.IsApplicable(context.get(), transformation_context));
1003     ApplyAndCheckFreshIds(transformation, context.get(),
1004                           &transformation_context);
1005   }
1006 
1007   ASSERT_FALSE(
1008       TransformationEquationInstruction(51, SpvOpBitcast, {20}, insert_before)
1009           .IsApplicable(context.get(), transformation_context));
1010 
1011   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1012                                                kConsoleMessageConsumer));
1013 
1014   std::string expected_shader = R"(
1015                OpCapability Shader
1016           %1 = OpExtInstImport "GLSL.std.450"
1017                OpMemoryModel Logical GLSL450
1018                OpEntryPoint Fragment %12 "main"
1019                OpExecutionMode %12 OriginUpperLeft
1020                OpSource ESSL 310
1021           %2 = OpTypeVoid
1022           %3 = OpTypeFunction %2
1023           %4 = OpTypeInt 32 0
1024           %8 = OpTypeFloat 32
1025          %11 = OpTypeVector %8 2
1026          %17 = OpConstant %8 24
1027          %20 = OpConstantComposite %11 %17 %17
1028          %12 = OpFunction %2 None %3
1029          %13 = OpLabel
1030          %50 = OpBitcast %4 %17
1031                OpReturn
1032                OpFunctionEnd
1033   )";
1034 
1035   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1036 }
1037 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist6)1038 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist6) {
1039   std::string shader = R"(
1040                OpCapability Shader
1041           %1 = OpExtInstImport "GLSL.std.450"
1042                OpMemoryModel Logical GLSL450
1043                OpEntryPoint Fragment %12 "main"
1044                OpExecutionMode %12 OriginUpperLeft
1045                OpSource ESSL 310
1046           %2 = OpTypeVoid
1047           %3 = OpTypeFunction %2
1048           %4 = OpTypeInt 32 1
1049           %5 = OpTypeInt 32 0
1050           %8 = OpTypeFloat 32
1051           %9 = OpTypeVector %5 2
1052          %11 = OpTypeVector %8 2
1053          %17 = OpConstant %8 24
1054          %20 = OpConstantComposite %11 %17 %17
1055          %12 = OpFunction %2 None %3
1056          %13 = OpLabel
1057                OpReturn
1058                OpFunctionEnd
1059   )";
1060 
1061   const auto env = SPV_ENV_UNIVERSAL_1_3;
1062   const auto consumer = nullptr;
1063   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1064   spvtools::ValidatorOptions validator_options;
1065   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1066                                                kConsoleMessageConsumer));
1067   TransformationContext transformation_context(
1068       MakeUnique<FactManager>(context.get()), validator_options);
1069   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
1070 
1071   {
1072     TransformationEquationInstruction transformation(50, SpvOpBitcast, {17},
1073                                                      insert_before);
1074     ASSERT_TRUE(
1075         transformation.IsApplicable(context.get(), transformation_context));
1076     ApplyAndCheckFreshIds(transformation, context.get(),
1077                           &transformation_context);
1078   }
1079   {
1080     TransformationEquationInstruction transformation(51, SpvOpBitcast, {20},
1081                                                      insert_before);
1082     ASSERT_TRUE(
1083         transformation.IsApplicable(context.get(), transformation_context));
1084     ApplyAndCheckFreshIds(transformation, context.get(),
1085                           &transformation_context);
1086   }
1087 
1088   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1089                                                kConsoleMessageConsumer));
1090 
1091   std::string expected_shader = R"(
1092                OpCapability Shader
1093           %1 = OpExtInstImport "GLSL.std.450"
1094                OpMemoryModel Logical GLSL450
1095                OpEntryPoint Fragment %12 "main"
1096                OpExecutionMode %12 OriginUpperLeft
1097                OpSource ESSL 310
1098           %2 = OpTypeVoid
1099           %3 = OpTypeFunction %2
1100           %4 = OpTypeInt 32 1
1101           %5 = OpTypeInt 32 0
1102           %8 = OpTypeFloat 32
1103           %9 = OpTypeVector %5 2
1104          %11 = OpTypeVector %8 2
1105          %17 = OpConstant %8 24
1106          %20 = OpConstantComposite %11 %17 %17
1107          %12 = OpFunction %2 None %3
1108          %13 = OpLabel
1109          %50 = OpBitcast %4 %17
1110          %51 = OpBitcast %9 %20
1111                OpReturn
1112                OpFunctionEnd
1113   )";
1114 
1115   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1116 }
1117 
TEST(TransformationEquationInstructionTest,BitcastResultTypeIntDoesNotExist7)1118 TEST(TransformationEquationInstructionTest, BitcastResultTypeIntDoesNotExist7) {
1119   std::string shader = R"(
1120                OpCapability Shader
1121           %1 = OpExtInstImport "GLSL.std.450"
1122                OpMemoryModel Logical GLSL450
1123                OpEntryPoint Fragment %12 "main"
1124                OpExecutionMode %12 OriginUpperLeft
1125                OpSource ESSL 310
1126           %2 = OpTypeVoid
1127           %3 = OpTypeFunction %2
1128           %4 = OpTypeInt 32 1
1129           %5 = OpTypeInt 32 0
1130           %8 = OpTypeFloat 32
1131           %9 = OpTypeVector %4 2
1132          %11 = OpTypeVector %8 2
1133          %17 = OpConstant %8 24
1134          %20 = OpConstantComposite %11 %17 %17
1135          %12 = OpFunction %2 None %3
1136          %13 = OpLabel
1137                OpReturn
1138                OpFunctionEnd
1139   )";
1140 
1141   const auto env = SPV_ENV_UNIVERSAL_1_3;
1142   const auto consumer = nullptr;
1143   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1144   spvtools::ValidatorOptions validator_options;
1145   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1146                                                kConsoleMessageConsumer));
1147   TransformationContext transformation_context(
1148       MakeUnique<FactManager>(context.get()), validator_options);
1149   auto insert_before = MakeInstructionDescriptor(13, SpvOpReturn, 0);
1150 
1151   {
1152     TransformationEquationInstruction transformation(50, SpvOpBitcast, {17},
1153                                                      insert_before);
1154     ASSERT_TRUE(
1155         transformation.IsApplicable(context.get(), transformation_context));
1156     ApplyAndCheckFreshIds(transformation, context.get(),
1157                           &transformation_context);
1158   }
1159   {
1160     TransformationEquationInstruction transformation(51, SpvOpBitcast, {20},
1161                                                      insert_before);
1162     ASSERT_TRUE(
1163         transformation.IsApplicable(context.get(), transformation_context));
1164     ApplyAndCheckFreshIds(transformation, context.get(),
1165                           &transformation_context);
1166   }
1167 
1168   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1169                                                kConsoleMessageConsumer));
1170 
1171   std::string expected_shader = R"(
1172                OpCapability Shader
1173           %1 = OpExtInstImport "GLSL.std.450"
1174                OpMemoryModel Logical GLSL450
1175                OpEntryPoint Fragment %12 "main"
1176                OpExecutionMode %12 OriginUpperLeft
1177                OpSource ESSL 310
1178           %2 = OpTypeVoid
1179           %3 = OpTypeFunction %2
1180           %4 = OpTypeInt 32 1
1181           %5 = OpTypeInt 32 0
1182           %8 = OpTypeFloat 32
1183           %9 = OpTypeVector %4 2
1184          %11 = OpTypeVector %8 2
1185          %17 = OpConstant %8 24
1186          %20 = OpConstantComposite %11 %17 %17
1187          %12 = OpFunction %2 None %3
1188          %13 = OpLabel
1189          %50 = OpBitcast %4 %17
1190          %51 = OpBitcast %9 %20
1191                OpReturn
1192                OpFunctionEnd
1193   )";
1194 
1195   ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
1196 }
1197 
TEST(TransformationEquationInstructionTest,Miscellaneous1)1198 TEST(TransformationEquationInstructionTest, Miscellaneous1) {
1199   std::string shader = R"(
1200                OpCapability Shader
1201           %1 = OpExtInstImport "GLSL.std.450"
1202                OpMemoryModel Logical GLSL450
1203                OpEntryPoint Fragment %12 "main"
1204                OpExecutionMode %12 OriginUpperLeft
1205                OpSource ESSL 310
1206           %2 = OpTypeVoid
1207           %3 = OpTypeFunction %2
1208           %6 = OpTypeInt 32 1
1209         %113 = OpConstant %6 24
1210          %12 = OpFunction %2 None %3
1211          %13 = OpLabel
1212                OpReturn
1213                OpFunctionEnd
1214   )";
1215 
1216   const auto env = SPV_ENV_UNIVERSAL_1_3;
1217   const auto consumer = nullptr;
1218   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1219   spvtools::ValidatorOptions validator_options;
1220   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1221                                                kConsoleMessageConsumer));
1222   TransformationContext transformation_context(
1223       MakeUnique<FactManager>(context.get()), validator_options);
1224   protobufs::InstructionDescriptor return_instruction =
1225       MakeInstructionDescriptor(13, SpvOpReturn, 0);
1226 
1227   auto transformation1 = TransformationEquationInstruction(
1228       522, SpvOpISub, {113, 113}, return_instruction);
1229   ASSERT_TRUE(
1230       transformation1.IsApplicable(context.get(), transformation_context));
1231   ApplyAndCheckFreshIds(transformation1, context.get(),
1232                         &transformation_context);
1233   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1234                                                kConsoleMessageConsumer));
1235 
1236   auto transformation2 = TransformationEquationInstruction(
1237       570, SpvOpIAdd, {522, 113}, return_instruction);
1238   ASSERT_TRUE(
1239       transformation2.IsApplicable(context.get(), transformation_context));
1240   ApplyAndCheckFreshIds(transformation2, context.get(),
1241                         &transformation_context);
1242   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1243                                                kConsoleMessageConsumer));
1244 
1245   std::string after_transformation = R"(
1246                OpCapability Shader
1247           %1 = OpExtInstImport "GLSL.std.450"
1248                OpMemoryModel Logical GLSL450
1249                OpEntryPoint Fragment %12 "main"
1250                OpExecutionMode %12 OriginUpperLeft
1251                OpSource ESSL 310
1252           %2 = OpTypeVoid
1253           %3 = OpTypeFunction %2
1254           %6 = OpTypeInt 32 1
1255         %113 = OpConstant %6 24
1256          %12 = OpFunction %2 None %3
1257          %13 = OpLabel
1258         %522 = OpISub %6 %113 %113
1259         %570 = OpIAdd %6 %522 %113
1260                OpReturn
1261                OpFunctionEnd
1262   )";
1263 
1264   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1265       MakeDataDescriptor(570, {}), MakeDataDescriptor(113, {})));
1266 
1267   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1268 }
1269 
TEST(TransformationEquationInstructionTest,Miscellaneous2)1270 TEST(TransformationEquationInstructionTest, Miscellaneous2) {
1271   std::string shader = R"(
1272                OpCapability Shader
1273           %1 = OpExtInstImport "GLSL.std.450"
1274                OpMemoryModel Logical GLSL450
1275                OpEntryPoint Fragment %12 "main"
1276                OpExecutionMode %12 OriginUpperLeft
1277                OpSource ESSL 310
1278           %2 = OpTypeVoid
1279           %3 = OpTypeFunction %2
1280           %6 = OpTypeInt 32 1
1281         %113 = OpConstant %6 24
1282          %12 = OpFunction %2 None %3
1283          %13 = OpLabel
1284                OpReturn
1285                OpFunctionEnd
1286   )";
1287 
1288   const auto env = SPV_ENV_UNIVERSAL_1_3;
1289   const auto consumer = nullptr;
1290   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1291   spvtools::ValidatorOptions validator_options;
1292   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1293                                                kConsoleMessageConsumer));
1294   TransformationContext transformation_context(
1295       MakeUnique<FactManager>(context.get()), validator_options);
1296   protobufs::InstructionDescriptor return_instruction =
1297       MakeInstructionDescriptor(13, SpvOpReturn, 0);
1298 
1299   auto transformation1 = TransformationEquationInstruction(
1300       522, SpvOpISub, {113, 113}, return_instruction);
1301   ASSERT_TRUE(
1302       transformation1.IsApplicable(context.get(), transformation_context));
1303   ApplyAndCheckFreshIds(transformation1, context.get(),
1304                         &transformation_context);
1305   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1306                                                kConsoleMessageConsumer));
1307 
1308   auto transformation2 = TransformationEquationInstruction(
1309       570, SpvOpIAdd, {522, 113}, return_instruction);
1310   ASSERT_TRUE(
1311       transformation2.IsApplicable(context.get(), transformation_context));
1312   ApplyAndCheckFreshIds(transformation2, context.get(),
1313                         &transformation_context);
1314   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1315                                                kConsoleMessageConsumer));
1316 
1317   std::string after_transformation = R"(
1318                OpCapability Shader
1319           %1 = OpExtInstImport "GLSL.std.450"
1320                OpMemoryModel Logical GLSL450
1321                OpEntryPoint Fragment %12 "main"
1322                OpExecutionMode %12 OriginUpperLeft
1323                OpSource ESSL 310
1324           %2 = OpTypeVoid
1325           %3 = OpTypeFunction %2
1326           %6 = OpTypeInt 32 1
1327         %113 = OpConstant %6 24
1328          %12 = OpFunction %2 None %3
1329          %13 = OpLabel
1330         %522 = OpISub %6 %113 %113
1331         %570 = OpIAdd %6 %522 %113
1332                OpReturn
1333                OpFunctionEnd
1334   )";
1335 
1336   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1337       MakeDataDescriptor(570, {}), MakeDataDescriptor(113, {})));
1338 
1339   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1340 }
1341 
TEST(TransformationEquationInstructionTest,ConversionInstructions)1342 TEST(TransformationEquationInstructionTest, ConversionInstructions) {
1343   std::string shader = R"(
1344                OpCapability Shader
1345           %1 = OpExtInstImport "GLSL.std.450"
1346                OpMemoryModel Logical GLSL450
1347                OpEntryPoint Fragment %12 "main"
1348                OpExecutionMode %12 OriginUpperLeft
1349                OpSource ESSL 310
1350           %2 = OpTypeVoid
1351           %3 = OpTypeFunction %2
1352           %6 = OpTypeInt 32 1
1353           %4 = OpTypeInt 32 0
1354           %5 = OpTypeFloat 32
1355           %7 = OpTypeVector %6 3
1356           %8 = OpTypeVector %4 3
1357           %9 = OpTypeVector %5 3
1358          %10 = OpConstant %6 12
1359          %20 = OpConstant %6 12
1360          %11 = OpConstant %4 12
1361          %21 = OpConstant %4 12
1362          %14 = OpConstant %5 12
1363          %15 = OpConstantComposite %7 %10 %10 %10
1364          %18 = OpConstantComposite %7 %10 %10 %10
1365          %16 = OpConstantComposite %8 %11 %11 %11
1366          %19 = OpConstantComposite %8 %11 %11 %11
1367          %17 = OpConstantComposite %9 %14 %14 %14
1368          %12 = OpFunction %2 None %3
1369          %13 = OpLabel
1370                OpReturn
1371                OpFunctionEnd
1372   )";
1373 
1374   const auto env = SPV_ENV_UNIVERSAL_1_3;
1375   const auto consumer = nullptr;
1376   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1377   spvtools::ValidatorOptions validator_options;
1378   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1379                                                kConsoleMessageConsumer));
1380   TransformationContext transformation_context(
1381       MakeUnique<FactManager>(context.get()), validator_options);
1382   protobufs::InstructionDescriptor return_instruction =
1383       MakeInstructionDescriptor(13, SpvOpReturn, 0);
1384 
1385   // Too few instruction operands.
1386   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertSToF, {},
1387                                                  return_instruction)
1388                    .IsApplicable(context.get(), transformation_context));
1389 
1390   // Too many instruction operands.
1391   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertSToF, {15, 16},
1392                                                  return_instruction)
1393                    .IsApplicable(context.get(), transformation_context));
1394 
1395   // Operand has no type id.
1396   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertSToF, {7},
1397                                                  return_instruction)
1398                    .IsApplicable(context.get(), transformation_context));
1399 
1400   // OpConvertSToF and OpConvertUToF require an operand to have scalar or vector
1401   // of integral components type.
1402   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertSToF, {17},
1403                                                  return_instruction)
1404                    .IsApplicable(context.get(), transformation_context));
1405   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertSToF, {14},
1406                                                  return_instruction)
1407                    .IsApplicable(context.get(), transformation_context));
1408   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertUToF, {17},
1409                                                  return_instruction)
1410                    .IsApplicable(context.get(), transformation_context));
1411   ASSERT_FALSE(TransformationEquationInstruction(50, SpvOpConvertUToF, {14},
1412                                                  return_instruction)
1413                    .IsApplicable(context.get(), transformation_context));
1414 
1415   {
1416     TransformationEquationInstruction transformation(50, SpvOpConvertSToF, {15},
1417                                                      return_instruction);
1418     ASSERT_TRUE(
1419         transformation.IsApplicable(context.get(), transformation_context));
1420     ApplyAndCheckFreshIds(transformation, context.get(),
1421                           &transformation_context);
1422   }
1423   {
1424     TransformationEquationInstruction transformation(51, SpvOpConvertSToF, {10},
1425                                                      return_instruction);
1426     ASSERT_TRUE(
1427         transformation.IsApplicable(context.get(), transformation_context));
1428     ApplyAndCheckFreshIds(transformation, context.get(),
1429                           &transformation_context);
1430   }
1431   {
1432     TransformationEquationInstruction transformation(52, SpvOpConvertUToF, {16},
1433                                                      return_instruction);
1434     ASSERT_TRUE(
1435         transformation.IsApplicable(context.get(), transformation_context));
1436     ApplyAndCheckFreshIds(transformation, context.get(),
1437                           &transformation_context);
1438   }
1439   {
1440     TransformationEquationInstruction transformation(53, SpvOpConvertUToF, {11},
1441                                                      return_instruction);
1442     ASSERT_TRUE(
1443         transformation.IsApplicable(context.get(), transformation_context));
1444     ApplyAndCheckFreshIds(transformation, context.get(),
1445                           &transformation_context);
1446   }
1447   {
1448     TransformationEquationInstruction transformation(58, SpvOpConvertSToF, {18},
1449                                                      return_instruction);
1450     ASSERT_TRUE(
1451         transformation.IsApplicable(context.get(), transformation_context));
1452     ApplyAndCheckFreshIds(transformation, context.get(),
1453                           &transformation_context);
1454   }
1455   {
1456     TransformationEquationInstruction transformation(59, SpvOpConvertUToF, {19},
1457                                                      return_instruction);
1458     ASSERT_TRUE(
1459         transformation.IsApplicable(context.get(), transformation_context));
1460     ApplyAndCheckFreshIds(transformation, context.get(),
1461                           &transformation_context);
1462   }
1463   {
1464     TransformationEquationInstruction transformation(60, SpvOpConvertSToF, {20},
1465                                                      return_instruction);
1466     ASSERT_TRUE(
1467         transformation.IsApplicable(context.get(), transformation_context));
1468     ApplyAndCheckFreshIds(transformation, context.get(),
1469                           &transformation_context);
1470   }
1471   {
1472     TransformationEquationInstruction transformation(61, SpvOpConvertUToF, {21},
1473                                                      return_instruction);
1474     ASSERT_TRUE(
1475         transformation.IsApplicable(context.get(), transformation_context));
1476     ApplyAndCheckFreshIds(transformation, context.get(),
1477                           &transformation_context);
1478   }
1479 
1480   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1481                                                kConsoleMessageConsumer));
1482 
1483   std::string after_transformations = R"(
1484                OpCapability Shader
1485           %1 = OpExtInstImport "GLSL.std.450"
1486                OpMemoryModel Logical GLSL450
1487                OpEntryPoint Fragment %12 "main"
1488                OpExecutionMode %12 OriginUpperLeft
1489                OpSource ESSL 310
1490           %2 = OpTypeVoid
1491           %3 = OpTypeFunction %2
1492           %6 = OpTypeInt 32 1
1493           %4 = OpTypeInt 32 0
1494           %5 = OpTypeFloat 32
1495           %7 = OpTypeVector %6 3
1496           %8 = OpTypeVector %4 3
1497           %9 = OpTypeVector %5 3
1498          %10 = OpConstant %6 12
1499          %20 = OpConstant %6 12
1500          %11 = OpConstant %4 12
1501          %21 = OpConstant %4 12
1502          %14 = OpConstant %5 12
1503          %15 = OpConstantComposite %7 %10 %10 %10
1504          %18 = OpConstantComposite %7 %10 %10 %10
1505          %16 = OpConstantComposite %8 %11 %11 %11
1506          %19 = OpConstantComposite %8 %11 %11 %11
1507          %17 = OpConstantComposite %9 %14 %14 %14
1508          %12 = OpFunction %2 None %3
1509          %13 = OpLabel
1510          %50 = OpConvertSToF %9 %15
1511          %51 = OpConvertSToF %5 %10
1512          %52 = OpConvertUToF %9 %16
1513          %53 = OpConvertUToF %5 %11
1514          %58 = OpConvertSToF %9 %18
1515          %59 = OpConvertUToF %9 %19
1516          %60 = OpConvertSToF %5 %20
1517          %61 = OpConvertUToF %5 %21
1518                OpReturn
1519                OpFunctionEnd
1520   )";
1521 
1522   ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
1523 }
1524 
TEST(TransformationEquationInstructionTest,FloatResultTypeDoesNotExist)1525 TEST(TransformationEquationInstructionTest, FloatResultTypeDoesNotExist) {
1526   std::string shader = R"(
1527                OpCapability Shader
1528           %1 = OpExtInstImport "GLSL.std.450"
1529                OpMemoryModel Logical GLSL450
1530                OpEntryPoint Fragment %12 "main"
1531                OpExecutionMode %12 OriginUpperLeft
1532                OpSource ESSL 310
1533           %2 = OpTypeVoid
1534           %3 = OpTypeFunction %2
1535           %6 = OpTypeInt 32 0
1536           %7 = OpTypeInt 32 1
1537           %8 = OpTypeVector %6 3
1538           %9 = OpTypeVector %7 3
1539          %10 = OpConstant %6 24
1540          %11 = OpConstant %7 25
1541          %14 = OpConstantComposite %8 %10 %10 %10
1542          %15 = OpConstantComposite %9 %11 %11 %11
1543          %12 = OpFunction %2 None %3
1544          %13 = OpLabel
1545                OpReturn
1546                OpFunctionEnd
1547   )";
1548 
1549   const auto env = SPV_ENV_UNIVERSAL_1_3;
1550   const auto consumer = nullptr;
1551   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1552   spvtools::ValidatorOptions validator_options;
1553   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1554                                                kConsoleMessageConsumer));
1555   TransformationContext transformation_context(
1556       MakeUnique<FactManager>(context.get()), validator_options);
1557   protobufs::InstructionDescriptor return_instruction =
1558       MakeInstructionDescriptor(13, SpvOpReturn, 0);
1559 
1560   // Scalar float type doesn't exist.
1561   ASSERT_FALSE(TransformationEquationInstruction(16, SpvOpConvertUToF, {10},
1562                                                  return_instruction)
1563                    .IsApplicable(context.get(), transformation_context));
1564   ASSERT_FALSE(TransformationEquationInstruction(16, SpvOpConvertSToF, {11},
1565                                                  return_instruction)
1566                    .IsApplicable(context.get(), transformation_context));
1567 
1568   // Vector float type doesn't exist.
1569   ASSERT_FALSE(TransformationEquationInstruction(16, SpvOpConvertUToF, {14},
1570                                                  return_instruction)
1571                    .IsApplicable(context.get(), transformation_context));
1572   ASSERT_FALSE(TransformationEquationInstruction(16, SpvOpConvertSToF, {15},
1573                                                  return_instruction)
1574                    .IsApplicable(context.get(), transformation_context));
1575 }
1576 
TEST(TransformationEquationInstructionTest,HandlesIrrelevantIds)1577 TEST(TransformationEquationInstructionTest, HandlesIrrelevantIds) {
1578   std::string shader = R"(
1579                OpCapability Shader
1580           %1 = OpExtInstImport "GLSL.std.450"
1581                OpMemoryModel Logical GLSL450
1582                OpEntryPoint Fragment %12 "main"
1583                OpExecutionMode %12 OriginUpperLeft
1584                OpSource ESSL 310
1585           %2 = OpTypeVoid
1586           %3 = OpTypeFunction %2
1587           %6 = OpTypeInt 32 1
1588          %30 = OpTypeVector %6 3
1589          %15 = OpConstant %6 24
1590          %16 = OpConstant %6 37
1591          %31 = OpConstantComposite %30 %15 %16 %15
1592          %33 = OpTypeBool
1593          %32 = OpConstantTrue %33
1594          %12 = OpFunction %2 None %3
1595          %13 = OpLabel
1596                OpReturn
1597                OpFunctionEnd
1598   )";
1599 
1600   const auto env = SPV_ENV_UNIVERSAL_1_3;
1601   const auto consumer = nullptr;
1602   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1603   spvtools::ValidatorOptions validator_options;
1604   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1605                                                kConsoleMessageConsumer));
1606   TransformationContext transformation_context(
1607       MakeUnique<FactManager>(context.get()), validator_options);
1608   auto return_instruction = MakeInstructionDescriptor(13, SpvOpReturn, 0);
1609 
1610   // Applicable.
1611   TransformationEquationInstruction transformation(14, SpvOpIAdd, {15, 16},
1612                                                    return_instruction);
1613   ASSERT_TRUE(
1614       transformation.IsApplicable(context.get(), transformation_context));
1615 
1616   // Handles irrelevant ids.
1617   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(16);
1618   ASSERT_FALSE(
1619       transformation.IsApplicable(context.get(), transformation_context));
1620   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(15);
1621   ASSERT_FALSE(
1622       transformation.IsApplicable(context.get(), transformation_context));
1623 }
1624 
TEST(TransformationEquationInstructionTest,HandlesDeadBlock)1625 TEST(TransformationEquationInstructionTest, HandlesDeadBlock) {
1626   std::string shader = R"(
1627                OpCapability Shader
1628           %1 = OpExtInstImport "GLSL.std.450"
1629                OpMemoryModel Logical GLSL450
1630                OpEntryPoint Fragment %12 "main"
1631                OpExecutionMode %12 OriginUpperLeft
1632                OpSource ESSL 310
1633           %2 = OpTypeVoid
1634           %3 = OpTypeFunction %2
1635           %6 = OpTypeInt 32 1
1636          %30 = OpTypeVector %6 3
1637          %15 = OpConstant %6 24
1638          %16 = OpConstant %6 37
1639          %31 = OpConstantComposite %30 %15 %16 %15
1640          %33 = OpTypeBool
1641          %32 = OpConstantTrue %33
1642          %12 = OpFunction %2 None %3
1643          %13 = OpLabel
1644                OpSelectionMerge %40 None
1645                OpBranchConditional %32 %40 %41
1646          %41 = OpLabel
1647                OpBranch %40
1648          %40 = OpLabel
1649                OpReturn
1650                OpFunctionEnd
1651   )";
1652 
1653   const auto env = SPV_ENV_UNIVERSAL_1_3;
1654   const auto consumer = nullptr;
1655   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1656   spvtools::ValidatorOptions validator_options;
1657   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1658                                                kConsoleMessageConsumer));
1659   TransformationContext transformation_context(
1660       MakeUnique<FactManager>(context.get()), validator_options);
1661 
1662   transformation_context.GetFactManager()->AddFactBlockIsDead(41);
1663 
1664   TransformationEquationInstruction transformation1(
1665       14, SpvOpIAdd, {15, 16},
1666       MakeInstructionDescriptor(13, SpvOpSelectionMerge, 0));
1667   // No synonym is created since block is dead.
1668   TransformationEquationInstruction transformation2(
1669       100, SpvOpISub, {14, 16}, MakeInstructionDescriptor(41, SpvOpBranch, 0));
1670   ASSERT_TRUE(
1671       transformation1.IsApplicable(context.get(), transformation_context));
1672   ApplyAndCheckFreshIds(transformation1, context.get(),
1673                         &transformation_context);
1674   ASSERT_TRUE(
1675       transformation2.IsApplicable(context.get(), transformation_context));
1676   ApplyAndCheckFreshIds(transformation2, context.get(),
1677                         &transformation_context);
1678   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1679       MakeDataDescriptor(100, {}), MakeDataDescriptor(15, {})));
1680 }
1681 
1682 }  // namespace
1683 }  // namespace fuzz
1684 }  // namespace spvtools
1685