spirv-fuzz: Avoid invalidating analyses (#4176)
The performance of spirv-fuzz is sometimes poor due to analyses being
conservatively invalidated. This can lead to quadratic time algorithms
when a fuzzer pass applies O(N) transformations, and where every
transformation e.g. depends on def-use analysis and invalidates
def-use analysis (because building def-use analysis is O(N)).
This change avoids invalidating analyses for certain transformations.
diff --git a/source/fuzz/transformation_composite_construct.cpp b/source/fuzz/transformation_composite_construct.cpp
index f0de1ae..f21a584 100644
--- a/source/fuzz/transformation_composite_construct.cpp
+++ b/source/fuzz/transformation_composite_construct.cpp
@@ -120,12 +120,18 @@
}
// Insert an OpCompositeConstruct instruction.
- insert_before.InsertBefore(MakeUnique<opt::Instruction>(
+ auto new_instruction = MakeUnique<opt::Instruction>(
ir_context, SpvOpCompositeConstruct, message_.composite_type_id(),
- message_.fresh_id(), in_operands));
+ message_.fresh_id(), in_operands);
+ auto new_instruction_ptr = new_instruction.get();
+ insert_before.InsertBefore(std::move(new_instruction));
+ ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
+ ir_context->set_instr_block(new_instruction_ptr, destination_block);
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
- ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+
+ // No analyses need to be invalidated since the transformation is local to a
+ // block and the def-use and instruction-to-block mappings have been updated.
AddDataSynonymFacts(ir_context, transformation_context);
}
diff --git a/source/fuzz/transformation_composite_extract.cpp b/source/fuzz/transformation_composite_extract.cpp
index 2aff02f..b688779 100644
--- a/source/fuzz/transformation_composite_extract.cpp
+++ b/source/fuzz/transformation_composite_extract.cpp
@@ -89,15 +89,21 @@
auto extracted_type = fuzzerutil::WalkCompositeTypeIndices(
ir_context, composite_instruction->type_id(), message_.index());
- FindInstruction(message_.instruction_to_insert_before(), ir_context)
- ->InsertBefore(MakeUnique<opt::Instruction>(
- ir_context, SpvOpCompositeExtract, extracted_type,
- message_.fresh_id(), extract_operands));
+ auto insert_before =
+ FindInstruction(message_.instruction_to_insert_before(), ir_context);
+ auto new_instruction = MakeUnique<opt::Instruction>(
+ ir_context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(),
+ extract_operands);
+ auto new_instruction_ptr = new_instruction.get();
+ insert_before->InsertBefore(std::move(new_instruction));
+ ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
+ ir_context->set_instr_block(new_instruction_ptr,
+ ir_context->get_instr_block(insert_before));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
- ir_context->InvalidateAnalysesExceptFor(
- opt::IRContext::Analysis::kAnalysisNone);
+ // No analyses need to be invalidated since the transformation is local to a
+ // block and the def-use and instruction-to-block mappings have been updated.
AddDataSynonymFacts(ir_context, transformation_context);
}
diff --git a/source/fuzz/transformation_replace_id_with_synonym.cpp b/source/fuzz/transformation_replace_id_with_synonym.cpp
index 24e079f..53d3a85 100644
--- a/source/fuzz/transformation_replace_id_with_synonym.cpp
+++ b/source/fuzz/transformation_replace_id_with_synonym.cpp
@@ -95,8 +95,12 @@
instruction_to_change->SetInOperand(
message_.id_use_descriptor().in_operand_index(),
{message_.synonymous_id()});
- ir_context->InvalidateAnalysesExceptFor(
- opt::IRContext::Analysis::kAnalysisNone);
+ ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(
+ instruction_to_change);
+ ir_context->get_def_use_mgr()->AnalyzeInstUse(instruction_to_change);
+
+ // No analyses need to be invalidated, since the transformation is local to a
+ // block, and the def-use analysis has been updated.
}
protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage()
diff --git a/source/fuzz/transformation_swap_conditional_branch_operands.cpp b/source/fuzz/transformation_swap_conditional_branch_operands.cpp
index 866fee6..35cc44f 100644
--- a/source/fuzz/transformation_swap_conditional_branch_operands.cpp
+++ b/source/fuzz/transformation_swap_conditional_branch_operands.cpp
@@ -70,11 +70,13 @@
// We are swapping the labels in OpBranchConditional. This means that we must
// invert the guard as well. We are using OpLogicalNot for that purpose here.
- iter.InsertBefore(MakeUnique<opt::Instruction>(
+ auto new_instruction = MakeUnique<opt::Instruction>(
ir_context, SpvOpLogicalNot, condition_inst->type_id(),
message_.fresh_id(),
opt::Instruction::OperandList{
- {SPV_OPERAND_TYPE_ID, {condition_inst->result_id()}}}));
+ {SPV_OPERAND_TYPE_ID, {condition_inst->result_id()}}});
+ auto new_instruction_ptr = new_instruction.get();
+ iter.InsertBefore(std::move(new_instruction));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
@@ -89,9 +91,13 @@
std::swap(branch_inst->GetInOperand(3), branch_inst->GetInOperand(4));
}
- // Make sure the changes are analyzed.
- ir_context->InvalidateAnalysesExceptFor(
- opt::IRContext::Analysis::kAnalysisNone);
+ ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
+ ir_context->set_instr_block(new_instruction_ptr, block);
+ ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(branch_inst);
+ ir_context->get_def_use_mgr()->AnalyzeInstUse(branch_inst);
+
+ // No analyses need to be invalidated since the transformation is local to a
+ // block and the def-use and instruction-to-block mappings have been updated.
}
protobufs::Transformation