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

Fixes #3958.
This commit is contained in:
Alastair Donaldson 2020-10-21 22:52:47 +01:00 committed by GitHub
parent 3b7aebca45
commit 8496780f57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 46 deletions

View File

@ -627,28 +627,45 @@ bool IdIsAvailableBeforeInstruction(opt::IRContext* context,
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,

View File

@ -82,6 +82,7 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) {
OpSelectionMerge %29 None
OpBranchConditional %27 %28 %31
%28 = OpLabel
%89 = OpCopyObject %18 %19
OpBranch %29
%31 = OpLabel
OpBranch %29
@ -151,86 +152,86 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) {
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 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) {
%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 @@ TEST(TransformationAddCopyMemoryTest, BasicTest) {
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

View File

@ -280,10 +280,6 @@ TEST(TransformationMutatePointerTest, HandlesUnreachableBlocks) {
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(