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