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(