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