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