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