spirv-fuzz: Fix to id availability (#3971)

Fixes #3958.
diff --git a/source/fuzz/fuzzer_util.cpp b/source/fuzz/fuzzer_util.cpp
index a691a91..aa186c2 100644
--- a/source/fuzz/fuzzer_util.cpp
+++ b/source/fuzz/fuzzer_util.cpp
@@ -627,28 +627,45 @@
   assert(context->get_instr_block(instruction) &&
          "|instruction| must be in a basic block");
 
-  auto defining_instruction = context->get_def_use_mgr()->GetDef(id);
-  auto enclosing_function = context->get_instr_block(instruction)->GetParent();
+  auto id_definition = context->get_def_use_mgr()->GetDef(id);
+  auto function_enclosing_instruction =
+      context->get_instr_block(instruction)->GetParent();
   // If the id a function parameter, it needs to be associated with the
   // function containing the instruction.
-  if (defining_instruction->opcode() == SpvOpFunctionParameter) {
-    return InstructionIsFunctionParameter(defining_instruction,
-                                          enclosing_function);
+  if (id_definition->opcode() == SpvOpFunctionParameter) {
+    return InstructionIsFunctionParameter(id_definition,
+                                          function_enclosing_instruction);
   }
   if (!context->get_instr_block(id)) {
     // The id is at global scope.
     return true;
   }
-  if (defining_instruction == instruction) {
+  if (id_definition == instruction) {
     // The instruction is not available right before its own definition.
     return false;
   }
   const auto* dominator_analysis =
-      context->GetDominatorAnalysis(enclosing_function);
-  return dominator_analysis->IsReachable(
-             context->get_instr_block(instruction)) &&
-         dominator_analysis->IsReachable(context->get_instr_block(id)) &&
-         dominator_analysis->Dominates(defining_instruction, instruction);
+      context->GetDominatorAnalysis(function_enclosing_instruction);
+  if (dominator_analysis->IsReachable(context->get_instr_block(instruction)) &&
+      dominator_analysis->IsReachable(context->get_instr_block(id)) &&
+      dominator_analysis->Dominates(id_definition, instruction)) {
+    // The id's definition dominates the instruction, and both the definition
+    // and the instruction are in reachable blocks, thus the id is available at
+    // the instruction.
+    return true;
+  }
+  if (id_definition->opcode() == SpvOpVariable &&
+      function_enclosing_instruction ==
+          context->get_instr_block(id)->GetParent()) {
+    assert(!dominator_analysis->IsReachable(
+               context->get_instr_block(instruction)) &&
+           "If the instruction were in a reachable block we should already "
+           "have returned true.");
+    // The id is a variable and it is in the same function as |instruction|.
+    // This is OK despite |instruction| being unreachable.
+    return true;
+  }
+  return false;
 }
 
 bool InstructionIsFunctionParameter(opt::Instruction* instruction,
diff --git a/test/fuzz/transformation_add_copy_memory_test.cpp b/test/fuzz/transformation_add_copy_memory_test.cpp
index e599cae..642a556 100644
--- a/test/fuzz/transformation_add_copy_memory_test.cpp
+++ b/test/fuzz/transformation_add_copy_memory_test.cpp
@@ -82,6 +82,7 @@
                OpSelectionMerge %29 None
                OpBranchConditional %27 %28 %31
          %28 = OpLabel
+         %89 = OpCopyObject %18 %19
                OpBranch %29
          %31 = OpLabel
                OpBranch %29
@@ -151,86 +152,86 @@
                    SpvStorageClassPrivate, 20)
                    .IsApplicable(context.get(), transformation_context));
 
-  // Instruction descriptor is invalid (id 89 is undefined).
+  // Instruction descriptor is invalid (id 90 is undefined).
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(89, SpvOpVariable, 0), 89, 19,
+                   MakeInstructionDescriptor(90, SpvOpVariable, 0), 90, 19,
                    SpvStorageClassPrivate, 20)
                    .IsApplicable(context.get(), transformation_context));
 
   // Cannot insert OpCopyMemory before OpPhi.
   ASSERT_FALSE(
       TransformationAddCopyMemory(MakeInstructionDescriptor(75, SpvOpPhi, 0),
-                                  89, 19, SpvStorageClassPrivate, 20)
+                                  90, 19, SpvStorageClassPrivate, 20)
           .IsApplicable(context.get(), transformation_context));
 
   // Source instruction is invalid.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 89, 76,
+                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 76,
                    SpvStorageClassPrivate, 0)
                    .IsApplicable(context.get(), transformation_context));
 
   // Source instruction's type doesn't exist.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 89, 5,
+                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 5,
                    SpvStorageClassPrivate, 0)
                    .IsApplicable(context.get(), transformation_context));
 
   // Source instruction's type is invalid.
   ASSERT_FALSE(
       TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0),
-                                  89, 40, SpvStorageClassPrivate, 0)
+                                  90, 40, SpvStorageClassPrivate, 0)
           .IsApplicable(context.get(), transformation_context));
 
   // Source instruction is OpUndef.
   ASSERT_FALSE(
       TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0),
-                                  89, 87, SpvStorageClassPrivate, 0)
+                                  90, 87, SpvStorageClassPrivate, 0)
           .IsApplicable(context.get(), transformation_context));
 
   // Source instruction is OpConstantNull.
   ASSERT_FALSE(
       TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0),
-                                  89, 88, SpvStorageClassPrivate, 0)
+                                  90, 88, SpvStorageClassPrivate, 0)
           .IsApplicable(context.get(), transformation_context));
 
   // Storage class is invalid.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 89, 19,
+                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 19,
                    SpvStorageClassWorkgroup, 20)
                    .IsApplicable(context.get(), transformation_context));
 
   // Initializer is 0.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 89, 19,
+                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 19,
                    SpvStorageClassPrivate, 0)
                    .IsApplicable(context.get(), transformation_context));
 
   // Initializer has wrong type.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 89, 19,
+                   MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 19,
                    SpvStorageClassPrivate, 25)
                    .IsApplicable(context.get(), transformation_context));
 
   // Source and target instructions are in different functions.
   ASSERT_FALSE(
       TransformationAddCopyMemory(MakeInstructionDescriptor(13, SpvOpLoad, 0),
-                                  89, 19, SpvStorageClassPrivate, 20)
+                                  90, 19, SpvStorageClassPrivate, 20)
           .IsApplicable(context.get(), transformation_context));
 
   // Source instruction doesn't dominate the target instruction.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(77, SpvOpLogicalEqual, 0), 89, 19,
+                   MakeInstructionDescriptor(77, SpvOpLogicalEqual, 0), 90, 89,
                    SpvStorageClassPrivate, 20)
                    .IsApplicable(context.get(), transformation_context));
 
   // Source and target instructions are the same.
   ASSERT_FALSE(TransformationAddCopyMemory(
-                   MakeInstructionDescriptor(19, SpvOpVariable, 0), 89, 19,
+                   MakeInstructionDescriptor(19, SpvOpVariable, 0), 90, 19,
                    SpvStorageClassPrivate, 20)
                    .IsApplicable(context.get(), transformation_context));
 
   // Correct transformations.
-  uint32_t fresh_id = 89;
+  uint32_t fresh_id = 90;
   auto descriptor = MakeInstructionDescriptor(27, SpvOpFunctionCall, 0);
   std::vector<uint32_t> source_ids = {19, 23, 26, 30, 35, 39, 68, 86};
   std::vector<uint32_t> initializers = {20, 24, 25, 25, 36, 84, 85, 20};
@@ -294,16 +295,16 @@
          %86 = OpVariable %79 Private %20
          %87 = OpUndef %79
          %88 = OpConstantNull %79
-         %89 = OpVariable %79 Private %20
-         %91 = OpVariable %78 Private %25
-         %93 = OpVariable %81 Private %36
-         %95 = OpVariable %83 Private %85
+         %90 = OpVariable %79 Private %20
+         %92 = OpVariable %78 Private %25
+         %94 = OpVariable %81 Private %36
+         %96 = OpVariable %83 Private %85
           %4 = OpFunction %2 None %3
           %5 = OpLabel
-         %96 = OpVariable %18 Function %20
-         %94 = OpVariable %38 Function %84
-         %92 = OpVariable %7 Function %25
-         %90 = OpVariable %22 Function %24
+         %97 = OpVariable %18 Function %20
+         %95 = OpVariable %38 Function %84
+         %93 = OpVariable %7 Function %25
+         %91 = OpVariable %22 Function %24
          %19 = OpVariable %18 Function
          %23 = OpVariable %22 Function
          %26 = OpVariable %7 Function
@@ -314,18 +315,19 @@
                OpStore %19 %20
                OpStore %23 %24
                OpStore %26 %25
-               OpCopyMemory %89 %19
-               OpCopyMemory %90 %23
-               OpCopyMemory %91 %26
-               OpCopyMemory %92 %30
-               OpCopyMemory %93 %35
-               OpCopyMemory %94 %39
-               OpCopyMemory %95 %68
-               OpCopyMemory %96 %86
+               OpCopyMemory %90 %19
+               OpCopyMemory %91 %23
+               OpCopyMemory %92 %26
+               OpCopyMemory %93 %30
+               OpCopyMemory %94 %35
+               OpCopyMemory %95 %39
+               OpCopyMemory %96 %68
+               OpCopyMemory %97 %86
          %27 = OpFunctionCall %6 %10 %26
                OpSelectionMerge %29 None
                OpBranchConditional %27 %28 %31
          %28 = OpLabel
+         %89 = OpCopyObject %18 %19
                OpBranch %29
          %31 = OpLabel
                OpBranch %29
diff --git a/test/fuzz/transformation_mutate_pointer_test.cpp b/test/fuzz/transformation_mutate_pointer_test.cpp
index 76bd282..ae42310 100644
--- a/test/fuzz/transformation_mutate_pointer_test.cpp
+++ b/test/fuzz/transformation_mutate_pointer_test.cpp
@@ -280,10 +280,6 @@
 
   const auto insert_before = MakeInstructionDescriptor(10, SpvOpReturn, 0);
 
-  // Local variable doesn't dominate an unreachable block.
-  ASSERT_FALSE(TransformationMutatePointer(9, 50, insert_before)
-                   .IsApplicable(context.get(), transformation_context));
-
   // Can mutate a global variable in an unreachable block.
   TransformationMutatePointer transformation(12, 50, insert_before);
   ASSERT_TRUE(