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