1 // Copyright (c) 2020 Vasyl Teliman
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_move_instruction_down.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(TransformationMoveInstructionDownTest, BasicTest)26 TEST(TransformationMoveInstructionDownTest, BasicTest) {
27 std::string shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main"
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %6 = OpTypeInt 32 1
37 %9 = OpConstant %6 0
38 %16 = OpTypeBool
39 %17 = OpConstantFalse %16
40 %20 = OpUndef %6
41 %13 = OpTypePointer Function %6
42 %4 = OpFunction %2 None %3
43 %5 = OpLabel
44 %12 = OpVariable %13 Function
45 %10 = OpIAdd %6 %9 %9
46 %11 = OpISub %6 %9 %10
47 OpStore %12 %10
48 %14 = OpLoad %6 %12
49 %15 = OpIMul %6 %9 %14
50 OpSelectionMerge %19 None
51 OpBranchConditional %17 %18 %19
52 %18 = OpLabel
53 OpBranch %19
54 %19 = OpLabel
55 %42 = OpFunctionCall %2 %40
56 %22 = OpIAdd %6 %15 %15
57 %21 = OpIAdd %6 %15 %15
58 OpReturn
59 OpFunctionEnd
60 %40 = OpFunction %2 None %3
61 %41 = OpLabel
62 OpReturn
63 OpFunctionEnd
64 )";
65
66 const auto env = SPV_ENV_UNIVERSAL_1_3;
67 const auto consumer = nullptr;
68 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
69 spvtools::ValidatorOptions validator_options;
70 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
71 kConsoleMessageConsumer));
72 TransformationContext transformation_context(
73 MakeUnique<FactManager>(context.get()), validator_options);
74 // Instruction descriptor is invalid.
75 ASSERT_FALSE(TransformationMoveInstructionDown(
76 MakeInstructionDescriptor(30, spv::Op::OpNop, 0))
77 .IsApplicable(context.get(), transformation_context));
78
79 // Opcode is not supported.
80 ASSERT_FALSE(TransformationMoveInstructionDown(
81 MakeInstructionDescriptor(5, spv::Op::OpLabel, 0))
82 .IsApplicable(context.get(), transformation_context));
83 ASSERT_FALSE(TransformationMoveInstructionDown(
84 MakeInstructionDescriptor(12, spv::Op::OpVariable, 0))
85 .IsApplicable(context.get(), transformation_context));
86 ASSERT_FALSE(TransformationMoveInstructionDown(
87 MakeInstructionDescriptor(42, spv::Op::OpFunctionCall, 0))
88 .IsApplicable(context.get(), transformation_context));
89
90 // Can't move the last instruction in the block.
91 ASSERT_FALSE(
92 TransformationMoveInstructionDown(
93 MakeInstructionDescriptor(15, spv::Op::OpBranchConditional, 0))
94 .IsApplicable(context.get(), transformation_context));
95
96 // Can't move the instruction if the next instruction is the last one in the
97 // block.
98 ASSERT_FALSE(TransformationMoveInstructionDown(
99 MakeInstructionDescriptor(21, spv::Op::OpIAdd, 0))
100 .IsApplicable(context.get(), transformation_context));
101
102 // Can't insert instruction's opcode after its successor.
103 ASSERT_FALSE(TransformationMoveInstructionDown(
104 MakeInstructionDescriptor(15, spv::Op::OpIMul, 0))
105 .IsApplicable(context.get(), transformation_context));
106
107 // Instruction's successor depends on the instruction.
108 ASSERT_FALSE(TransformationMoveInstructionDown(
109 MakeInstructionDescriptor(10, spv::Op::OpIAdd, 0))
110 .IsApplicable(context.get(), transformation_context));
111
112 {
113 TransformationMoveInstructionDown transformation(
114 MakeInstructionDescriptor(11, spv::Op::OpISub, 0));
115 ASSERT_TRUE(
116 transformation.IsApplicable(context.get(), transformation_context));
117 ApplyAndCheckFreshIds(transformation, context.get(),
118 &transformation_context);
119 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
120 context.get(), validator_options, kConsoleMessageConsumer));
121 }
122 {
123 TransformationMoveInstructionDown transformation(
124 MakeInstructionDescriptor(22, spv::Op::OpIAdd, 0));
125 ASSERT_TRUE(
126 transformation.IsApplicable(context.get(), transformation_context));
127 ApplyAndCheckFreshIds(transformation, context.get(),
128 &transformation_context);
129 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
130 context.get(), validator_options, kConsoleMessageConsumer));
131 }
132
133 std::string after_transformation = R"(
134 OpCapability Shader
135 %1 = OpExtInstImport "GLSL.std.450"
136 OpMemoryModel Logical GLSL450
137 OpEntryPoint Fragment %4 "main"
138 OpExecutionMode %4 OriginUpperLeft
139 OpSource ESSL 310
140 %2 = OpTypeVoid
141 %3 = OpTypeFunction %2
142 %6 = OpTypeInt 32 1
143 %9 = OpConstant %6 0
144 %16 = OpTypeBool
145 %17 = OpConstantFalse %16
146 %20 = OpUndef %6
147 %13 = OpTypePointer Function %6
148 %4 = OpFunction %2 None %3
149 %5 = OpLabel
150 %12 = OpVariable %13 Function
151 %10 = OpIAdd %6 %9 %9
152 OpStore %12 %10
153 %11 = OpISub %6 %9 %10
154 %14 = OpLoad %6 %12
155 %15 = OpIMul %6 %9 %14
156 OpSelectionMerge %19 None
157 OpBranchConditional %17 %18 %19
158 %18 = OpLabel
159 OpBranch %19
160 %19 = OpLabel
161 %42 = OpFunctionCall %2 %40
162 %21 = OpIAdd %6 %15 %15
163 %22 = OpIAdd %6 %15 %15
164 OpReturn
165 OpFunctionEnd
166 %40 = OpFunction %2 None %3
167 %41 = OpLabel
168 OpReturn
169 OpFunctionEnd
170 )";
171
172 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
173 }
174
TEST(TransformationMoveInstructionDownTest, HandlesUnsupportedInstructions)175 TEST(TransformationMoveInstructionDownTest, HandlesUnsupportedInstructions) {
176 std::string shader = R"(
177 OpCapability Shader
178 %1 = OpExtInstImport "GLSL.std.450"
179 OpMemoryModel Logical GLSL450
180 OpEntryPoint GLCompute %4 "main"
181 OpExecutionMode %4 LocalSize 16 1 1
182 OpSource ESSL 320
183 %2 = OpTypeVoid
184 %3 = OpTypeFunction %2
185 %6 = OpTypeInt 32 0
186 %7 = OpConstant %6 2
187 %20 = OpTypePointer Function %6
188 %4 = OpFunction %2 None %3
189 %5 = OpLabel
190 %21 = OpVariable %20 Function %7
191
192 ; can swap simple and not supported instructions
193 %8 = OpCopyObject %6 %7
194 %9 = OpFunctionCall %2 %12
195
196 ; cannot swap memory and not supported instruction
197 %22 = OpLoad %6 %21
198 %23 = OpFunctionCall %2 %12
199
200 ; cannot swap barrier and not supported instruction
201 OpMemoryBarrier %7 %7
202 %24 = OpFunctionCall %2 %12
203
204 OpReturn
205 OpFunctionEnd
206 %12 = OpFunction %2 None %3
207 %13 = OpLabel
208 OpReturn
209 OpFunctionEnd
210 )";
211
212 const auto env = SPV_ENV_UNIVERSAL_1_3;
213 const auto consumer = nullptr;
214 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
215 spvtools::ValidatorOptions validator_options;
216 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
217 kConsoleMessageConsumer));
218 TransformationContext transformation_context(
219 MakeUnique<FactManager>(context.get()), validator_options);
220 // Swap memory instruction with an unsupported one.
221 ASSERT_FALSE(TransformationMoveInstructionDown(
222 MakeInstructionDescriptor(22, spv::Op::OpLoad, 0))
223 .IsApplicable(context.get(), transformation_context));
224
225 // Swap memory barrier with an unsupported one.
226 ASSERT_FALSE(TransformationMoveInstructionDown(
227 MakeInstructionDescriptor(23, spv::Op::OpMemoryBarrier, 0))
228 .IsApplicable(context.get(), transformation_context));
229
230 // Swap simple instruction with an unsupported one.
231 TransformationMoveInstructionDown transformation(
232 MakeInstructionDescriptor(8, spv::Op::OpCopyObject, 0));
233 ASSERT_TRUE(
234 transformation.IsApplicable(context.get(), transformation_context));
235 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
236 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
237 kConsoleMessageConsumer));
238
239 std::string after_transformation = R"(
240 OpCapability Shader
241 %1 = OpExtInstImport "GLSL.std.450"
242 OpMemoryModel Logical GLSL450
243 OpEntryPoint GLCompute %4 "main"
244 OpExecutionMode %4 LocalSize 16 1 1
245 OpSource ESSL 320
246 %2 = OpTypeVoid
247 %3 = OpTypeFunction %2
248 %6 = OpTypeInt 32 0
249 %7 = OpConstant %6 2
250 %20 = OpTypePointer Function %6
251 %4 = OpFunction %2 None %3
252 %5 = OpLabel
253 %21 = OpVariable %20 Function %7
254
255 ; can swap simple and not supported instructions
256 %9 = OpFunctionCall %2 %12
257 %8 = OpCopyObject %6 %7
258
259 ; cannot swap memory and not supported instruction
260 %22 = OpLoad %6 %21
261 %23 = OpFunctionCall %2 %12
262
263 ; cannot swap barrier and not supported instruction
264 OpMemoryBarrier %7 %7
265 %24 = OpFunctionCall %2 %12
266
267 OpReturn
268 OpFunctionEnd
269 %12 = OpFunction %2 None %3
270 %13 = OpLabel
271 OpReturn
272 OpFunctionEnd
273 )";
274
275 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
276 }
277
TEST(TransformationMoveInstructionDownTest, HandlesBarrierInstructions)278 TEST(TransformationMoveInstructionDownTest, HandlesBarrierInstructions) {
279 std::string shader = R"(
280 OpCapability Shader
281 %1 = OpExtInstImport "GLSL.std.450"
282 OpMemoryModel Logical GLSL450
283 OpEntryPoint GLCompute %4 "main"
284 OpExecutionMode %4 LocalSize 16 1 1
285 OpSource ESSL 320
286 %2 = OpTypeVoid
287 %3 = OpTypeFunction %2
288 %6 = OpTypeInt 32 0
289 %7 = OpConstant %6 2
290 %20 = OpTypePointer Function %6
291 %4 = OpFunction %2 None %3
292 %5 = OpLabel
293 %21 = OpVariable %20 Function %7
294
295 ; cannot swap two barrier instructions
296 OpMemoryBarrier %7 %7
297 OpMemoryBarrier %7 %7
298
299 ; cannot swap barrier and memory instructions
300 OpMemoryBarrier %7 %7
301 %22 = OpLoad %6 %21
302 OpMemoryBarrier %7 %7
303
304 ; can swap barrier and simple instructions
305 %23 = OpCopyObject %6 %7
306 OpMemoryBarrier %7 %7
307
308 OpReturn
309 OpFunctionEnd
310 %12 = OpFunction %2 None %3
311 %13 = OpLabel
312 OpReturn
313 OpFunctionEnd
314 )";
315
316 const auto env = SPV_ENV_UNIVERSAL_1_3;
317 const auto consumer = nullptr;
318 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
319 spvtools::ValidatorOptions validator_options;
320 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
321 kConsoleMessageConsumer));
322 TransformationContext transformation_context(
323 MakeUnique<FactManager>(context.get()), validator_options);
324 // Swap two barrier instructions.
325 ASSERT_FALSE(TransformationMoveInstructionDown(
326 MakeInstructionDescriptor(21, spv::Op::OpMemoryBarrier, 0))
327 .IsApplicable(context.get(), transformation_context));
328
329 // Swap barrier and memory instructions.
330 ASSERT_FALSE(TransformationMoveInstructionDown(
331 MakeInstructionDescriptor(21, spv::Op::OpMemoryBarrier, 2))
332 .IsApplicable(context.get(), transformation_context));
333 ASSERT_FALSE(TransformationMoveInstructionDown(
334 MakeInstructionDescriptor(22, spv::Op::OpLoad, 0))
335 .IsApplicable(context.get(), transformation_context));
336
337 // Swap barrier and simple instructions.
338 {
339 TransformationMoveInstructionDown transformation(
340 MakeInstructionDescriptor(23, spv::Op::OpCopyObject, 0));
341 ASSERT_TRUE(
342 transformation.IsApplicable(context.get(), transformation_context));
343 ApplyAndCheckFreshIds(transformation, context.get(),
344 &transformation_context);
345 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
346 context.get(), validator_options, kConsoleMessageConsumer));
347 }
348 {
349 TransformationMoveInstructionDown transformation(
350 MakeInstructionDescriptor(22, spv::Op::OpMemoryBarrier, 1));
351 ASSERT_TRUE(
352 transformation.IsApplicable(context.get(), transformation_context));
353 ApplyAndCheckFreshIds(transformation, context.get(),
354 &transformation_context);
355 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
356 context.get(), validator_options, kConsoleMessageConsumer));
357 }
358
359 ASSERT_TRUE(IsEqual(env, shader, context.get()));
360 }
361
TEST(TransformationMoveInstructionDownTest, HandlesSimpleInstructions)362 TEST(TransformationMoveInstructionDownTest, HandlesSimpleInstructions) {
363 std::string shader = R"(
364 OpCapability Shader
365 %1 = OpExtInstImport "GLSL.std.450"
366 OpMemoryModel Logical GLSL450
367 OpEntryPoint GLCompute %4 "main"
368 OpExecutionMode %4 LocalSize 16 1 1
369 OpSource ESSL 320
370 %2 = OpTypeVoid
371 %3 = OpTypeFunction %2
372 %6 = OpTypeInt 32 0
373 %7 = OpConstant %6 2
374 %20 = OpTypePointer Function %6
375 %4 = OpFunction %2 None %3
376 %5 = OpLabel
377 %21 = OpVariable %20 Function %7
378
379 ; can swap simple and barrier instructions
380 %40 = OpCopyObject %6 %7
381 OpMemoryBarrier %7 %7
382
383 ; can swap simple and memory instructions
384 %41 = OpCopyObject %6 %7
385 %22 = OpLoad %6 %21
386
387 ; can swap two simple instructions
388 %23 = OpCopyObject %6 %7
389 %42 = OpCopyObject %6 %7
390
391 OpReturn
392 OpFunctionEnd
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 // Swap simple and barrier instructions.
408 {
409 TransformationMoveInstructionDown transformation(
410 MakeInstructionDescriptor(40, spv::Op::OpCopyObject, 0));
411 ASSERT_TRUE(
412 transformation.IsApplicable(context.get(), transformation_context));
413 ApplyAndCheckFreshIds(transformation, context.get(),
414 &transformation_context);
415 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
416 context.get(), validator_options, kConsoleMessageConsumer));
417 }
418 {
419 TransformationMoveInstructionDown transformation(
420 MakeInstructionDescriptor(21, spv::Op::OpMemoryBarrier, 0));
421 ASSERT_TRUE(
422 transformation.IsApplicable(context.get(), transformation_context));
423 ApplyAndCheckFreshIds(transformation, context.get(),
424 &transformation_context);
425 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
426 context.get(), validator_options, kConsoleMessageConsumer));
427 }
428
429 // Swap simple and memory instructions.
430 {
431 TransformationMoveInstructionDown transformation(
432 MakeInstructionDescriptor(41, spv::Op::OpCopyObject, 0));
433 ASSERT_TRUE(
434 transformation.IsApplicable(context.get(), transformation_context));
435 ApplyAndCheckFreshIds(transformation, context.get(),
436 &transformation_context);
437 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
438 context.get(), validator_options, kConsoleMessageConsumer));
439 }
440 {
441 TransformationMoveInstructionDown transformation(
442 MakeInstructionDescriptor(22, spv::Op::OpLoad, 0));
443 ASSERT_TRUE(
444 transformation.IsApplicable(context.get(), transformation_context));
445 ApplyAndCheckFreshIds(transformation, context.get(),
446 &transformation_context);
447 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
448 context.get(), validator_options, kConsoleMessageConsumer));
449 }
450
451 // Swap two simple instructions.
452 {
453 TransformationMoveInstructionDown transformation(
454 MakeInstructionDescriptor(23, spv::Op::OpCopyObject, 0));
455 ASSERT_TRUE(
456 transformation.IsApplicable(context.get(), transformation_context));
457 ApplyAndCheckFreshIds(transformation, context.get(),
458 &transformation_context);
459 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
460 context.get(), validator_options, kConsoleMessageConsumer));
461 }
462
463 std::string after_transformation = R"(
464 OpCapability Shader
465 %1 = OpExtInstImport "GLSL.std.450"
466 OpMemoryModel Logical GLSL450
467 OpEntryPoint GLCompute %4 "main"
468 OpExecutionMode %4 LocalSize 16 1 1
469 OpSource ESSL 320
470 %2 = OpTypeVoid
471 %3 = OpTypeFunction %2
472 %6 = OpTypeInt 32 0
473 %7 = OpConstant %6 2
474 %20 = OpTypePointer Function %6
475 %4 = OpFunction %2 None %3
476 %5 = OpLabel
477 %21 = OpVariable %20 Function %7
478
479 ; can swap simple and barrier instructions
480 %40 = OpCopyObject %6 %7
481 OpMemoryBarrier %7 %7
482
483 ; can swap simple and memory instructions
484 %41 = OpCopyObject %6 %7
485 %22 = OpLoad %6 %21
486
487 ; can swap two simple instructions
488 %42 = OpCopyObject %6 %7
489 %23 = OpCopyObject %6 %7
490
491 OpReturn
492 OpFunctionEnd
493 %12 = OpFunction %2 None %3
494 %13 = OpLabel
495 OpReturn
496 OpFunctionEnd
497 )";
498
499 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
500 }
501
TEST(TransformationMoveInstructionDownTest, HandlesMemoryInstructions)502 TEST(TransformationMoveInstructionDownTest, HandlesMemoryInstructions) {
503 std::string shader = R"(
504 OpCapability Shader
505 %1 = OpExtInstImport "GLSL.std.450"
506 OpMemoryModel Logical GLSL450
507 OpEntryPoint GLCompute %4 "main"
508 OpExecutionMode %4 LocalSize 16 1 1
509 OpSource ESSL 320
510 %2 = OpTypeVoid
511 %3 = OpTypeFunction %2
512 %6 = OpTypeInt 32 0
513 %7 = OpConstant %6 2
514 %20 = OpTypePointer Function %6
515 %4 = OpFunction %2 None %3
516 %5 = OpLabel
517 %21 = OpVariable %20 Function %7
518 %22 = OpVariable %20 Function %7
519
520 ; swap R and R instructions
521 %23 = OpLoad %6 %21
522 %24 = OpLoad %6 %22
523
524 ; swap R and RW instructions
525
526 ; can't swap
527 %25 = OpLoad %6 %21
528 OpCopyMemory %21 %22
529
530 ; can swap
531 %26 = OpLoad %6 %21
532 OpCopyMemory %22 %21
533
534 %27 = OpLoad %6 %22
535 OpCopyMemory %21 %22
536
537 %28 = OpLoad %6 %22
538 OpCopyMemory %22 %21
539
540 ; swap R and W instructions
541
542 ; can't swap
543 %29 = OpLoad %6 %21
544 OpStore %21 %7
545
546 ; can swap
547 %30 = OpLoad %6 %22
548 OpStore %21 %7
549
550 %31 = OpLoad %6 %21
551 OpStore %22 %7
552
553 %32 = OpLoad %6 %22
554 OpStore %22 %7
555
556 ; swap RW and RW instructions
557
558 ; can't swap
559 OpCopyMemory %21 %21
560 OpCopyMemory %21 %21
561
562 OpCopyMemory %21 %22
563 OpCopyMemory %21 %21
564
565 OpCopyMemory %21 %21
566 OpCopyMemory %21 %22
567
568 ; can swap
569 OpCopyMemory %22 %21
570 OpCopyMemory %21 %22
571
572 OpCopyMemory %22 %21
573 OpCopyMemory %22 %21
574
575 OpCopyMemory %21 %22
576 OpCopyMemory %21 %22
577
578 ; swap RW and W instructions
579
580 ; can't swap
581 OpCopyMemory %21 %21
582 OpStore %21 %7
583
584 OpStore %21 %7
585 OpCopyMemory %21 %21
586
587 ; can swap
588 OpCopyMemory %22 %21
589 OpStore %21 %7
590
591 OpCopyMemory %21 %22
592 OpStore %21 %7
593
594 OpCopyMemory %21 %21
595 OpStore %22 %7
596
597 ; swap W and W instructions
598
599 ; can't swap
600 OpStore %21 %7
601 OpStore %21 %7
602
603 ; can swap
604 OpStore %22 %7
605 OpStore %21 %7
606
607 OpStore %22 %7
608 OpStore %22 %7
609
610 OpReturn
611 OpFunctionEnd
612 )";
613
614 const auto env = SPV_ENV_UNIVERSAL_1_3;
615 const auto consumer = nullptr;
616 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
617 spvtools::ValidatorOptions validator_options;
618 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
619 kConsoleMessageConsumer));
620 TransformationContext transformation_context(
621 MakeUnique<FactManager>(context.get()), validator_options);
622 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
623 22);
624
625 // Invalid swaps.
626
627 protobufs::InstructionDescriptor invalid_swaps[] = {
628 // R and RW
629 MakeInstructionDescriptor(25, spv::Op::OpLoad, 0),
630
631 // R and W
632 MakeInstructionDescriptor(29, spv::Op::OpLoad, 0),
633
634 // RW and RW
635 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 0),
636 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 2),
637 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 4),
638
639 // RW and W
640 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 12),
641 MakeInstructionDescriptor(32, spv::Op::OpStore, 1),
642
643 // W and W
644 MakeInstructionDescriptor(32, spv::Op::OpStore, 6),
645 };
646
647 for (const auto& descriptor : invalid_swaps) {
648 ASSERT_FALSE(TransformationMoveInstructionDown(descriptor)
649 .IsApplicable(context.get(), transformation_context));
650 }
651
652 // Valid swaps.
653 protobufs::InstructionDescriptor valid_swaps[] = {
654 // R and R
655 MakeInstructionDescriptor(23, spv::Op::OpLoad, 0),
656 MakeInstructionDescriptor(24, spv::Op::OpLoad, 0),
657
658 // R and RW
659 MakeInstructionDescriptor(26, spv::Op::OpLoad, 0),
660 MakeInstructionDescriptor(25, spv::Op::OpCopyMemory, 1),
661
662 MakeInstructionDescriptor(27, spv::Op::OpLoad, 0),
663 MakeInstructionDescriptor(26, spv::Op::OpCopyMemory, 1),
664
665 MakeInstructionDescriptor(28, spv::Op::OpLoad, 0),
666 MakeInstructionDescriptor(27, spv::Op::OpCopyMemory, 1),
667
668 // R and W
669 MakeInstructionDescriptor(30, spv::Op::OpLoad, 0),
670 MakeInstructionDescriptor(29, spv::Op::OpStore, 1),
671
672 MakeInstructionDescriptor(31, spv::Op::OpLoad, 0),
673 MakeInstructionDescriptor(30, spv::Op::OpStore, 1),
674
675 MakeInstructionDescriptor(32, spv::Op::OpLoad, 0),
676 MakeInstructionDescriptor(31, spv::Op::OpStore, 1),
677
678 // RW and RW
679 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 6),
680 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 6),
681
682 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 8),
683 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 8),
684
685 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 10),
686 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 10),
687
688 // RW and W
689 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 14),
690 MakeInstructionDescriptor(32, spv::Op::OpStore, 3),
691
692 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 15),
693 MakeInstructionDescriptor(32, spv::Op::OpStore, 4),
694
695 MakeInstructionDescriptor(32, spv::Op::OpCopyMemory, 16),
696 MakeInstructionDescriptor(32, spv::Op::OpStore, 5),
697
698 // W and W
699 MakeInstructionDescriptor(32, spv::Op::OpStore, 8),
700 MakeInstructionDescriptor(32, spv::Op::OpStore, 8),
701
702 MakeInstructionDescriptor(32, spv::Op::OpStore, 10),
703 MakeInstructionDescriptor(32, spv::Op::OpStore, 10),
704 };
705
706 for (const auto& descriptor : valid_swaps) {
707 TransformationMoveInstructionDown transformation(descriptor);
708 ASSERT_TRUE(
709 transformation.IsApplicable(context.get(), transformation_context));
710 ApplyAndCheckFreshIds(transformation, context.get(),
711 &transformation_context);
712 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
713 context.get(), validator_options, kConsoleMessageConsumer));
714 }
715
716 ASSERT_TRUE(IsEqual(env, shader, context.get()));
717 }
718
719 } // namespace
720 } // namespace fuzz
721 } // namespace spvtools
722