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