spirv-fuzz: Enhancing permute function variables and its testing (#4295)

Fixes the way instruction swapping is implemented.

Fixes #4257.
Fixes #4259.
diff --git a/source/fuzz/fuzzer_pass_permute_function_variables.cpp b/source/fuzz/fuzzer_pass_permute_function_variables.cpp
index af83118..a4e19e3 100644
--- a/source/fuzz/fuzzer_pass_permute_function_variables.cpp
+++ b/source/fuzz/fuzzer_pass_permute_function_variables.cpp
@@ -31,10 +31,10 @@
     FuzzerContext* fuzzer_context,
     protobufs::TransformationSequence* transformations)
     : FuzzerPass(ir_context, transformation_context, fuzzer_context,
-                 transformations) {}  // Here we call parent constructor
+                 transformations) {}  // Here we call parent constructor.
 
 void FuzzerPassPermuteFunctionVariables::Apply() {
-  // Permuting OpVariable instructions in each function
+  // Permuting OpVariable instructions in each function.
   for (auto& function : *GetIRContext()->module()) {
     if (!GetFuzzerContext()->ChoosePercentage(
             GetFuzzerContext()->GetChanceOfPermutingFunctionVariables())) {
@@ -49,7 +49,9 @@
         variables.push_back(&instruction);
       }
     }
-
+    if (variables.size() <= 1) {
+      continue;
+    }
     do {
       uint32_t instruction_1_index = GetFuzzerContext()->RandomIndex(variables);
       uint32_t instruction_2_index = GetFuzzerContext()->RandomIndex(variables);
@@ -61,8 +63,9 @@
       }
 
     } while (GetFuzzerContext()->ChoosePercentage(
-        GetFuzzerContext()
-            ->GetChanceOfSwappingAnotherPairOfFunctionVariables()));
+                 GetFuzzerContext()
+                     ->GetChanceOfSwappingAnotherPairOfFunctionVariables()) &&
+             variables.size() > 2);
   }
 }
 
diff --git a/source/fuzz/transformation_swap_function_variables.cpp b/source/fuzz/transformation_swap_function_variables.cpp
index 44cd595..aec32fe 100644
--- a/source/fuzz/transformation_swap_function_variables.cpp
+++ b/source/fuzz/transformation_swap_function_variables.cpp
@@ -68,7 +68,13 @@
   auto instruction2 =
       ir_context->get_def_use_mgr()->GetDef(message_.result_id2());
 
-  std::swap(*instruction1, *instruction2);
+  std::unique_ptr<opt::Instruction> temp_instruction =
+      MakeUnique<opt::Instruction>();
+
+  temp_instruction->InsertBefore(instruction1);
+  instruction1->InsertAfter(instruction2);
+  instruction2->InsertAfter(temp_instruction.get());
+  temp_instruction->RemoveFromList();
 }
 
 protobufs::Transformation TransformationSwapFunctionVariables::ToMessage()
diff --git a/test/fuzz/transformation_swap_function_variables_test.cpp b/test/fuzz/transformation_swap_function_variables_test.cpp
index a036496..8132aa4 100644
--- a/test/fuzz/transformation_swap_function_variables_test.cpp
+++ b/test/fuzz/transformation_swap_function_variables_test.cpp
@@ -175,6 +175,7 @@
 
   const auto env = SPV_ENV_UNIVERSAL_1_5;
   const auto consumer = nullptr;
+  // Get Unique pointer of IRContext.
   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
   spvtools::ValidatorOptions validator_options;
 
@@ -185,24 +186,40 @@
 
   // Successful transformations
   {
+    auto first_instruction = context->get_def_use_mgr()->GetDef(24);
+    auto second_instruction = context->get_def_use_mgr()->GetDef(28);
     // Swap two OpVariable instructions in the same function.
     TransformationSwapFunctionVariables transformation(24, 28);
+
     ASSERT_TRUE(
         transformation.IsApplicable(context.get(), transformation_context));
+
     ApplyAndCheckFreshIds(transformation, context.get(),
                           &transformation_context);
+
     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
         context.get(), validator_options, kConsoleMessageConsumer));
+
+    ASSERT_EQ(first_instruction, context->get_def_use_mgr()->GetDef(24));
+    ASSERT_EQ(second_instruction, context->get_def_use_mgr()->GetDef(28));
   }
   {
+    auto first_instruction = context->get_def_use_mgr()->GetDef(38);
+    auto second_instruction = context->get_def_use_mgr()->GetDef(40);
     // Swap two OpVariable instructions in the same function.
     TransformationSwapFunctionVariables transformation(38, 40);
+
     ASSERT_TRUE(
         transformation.IsApplicable(context.get(), transformation_context));
+
     ApplyAndCheckFreshIds(transformation, context.get(),
                           &transformation_context);
+
     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
         context.get(), validator_options, kConsoleMessageConsumer));
+
+    ASSERT_EQ(first_instruction, context->get_def_use_mgr()->GetDef(38));
+    ASSERT_EQ(second_instruction, context->get_def_use_mgr()->GetDef(40));
   }
   std::string after_transformation = R"(
                OpCapability Shader