spirv-fuzz: Fix to FuzzerPassFlattenConditionalBranches (#3865)
Fixes #3864.
diff --git a/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp b/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp
index 132d50a..5e79ec8 100644
--- a/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp
+++ b/source/fuzz/fuzzer_pass_flatten_conditional_branches.cpp
@@ -34,11 +34,12 @@
default;
void FuzzerPassFlattenConditionalBranches::Apply() {
- // Get all the selection headers that we want to flatten. We need to collect
- // all of them first, because, since we are changing the structure of the
- // module, it's not safe to modify them while iterating.
- std::vector<opt::BasicBlock*> selection_headers;
for (auto& function : *GetIRContext()->module()) {
+ // Get all the selection headers that we want to flatten. We need to collect
+ // all of them first, because, since we are changing the structure of the
+ // module, it's not safe to modify them while iterating.
+ std::vector<opt::BasicBlock*> selection_headers;
+
for (auto& block : function) {
// Randomly decide whether to consider this block.
if (!GetFuzzerContext()->ChoosePercentage(
@@ -53,70 +54,71 @@
selection_headers.emplace_back(&block);
}
}
- }
- // Sort the headers so that those that are more deeply nested are considered
- // first, possibly enabling outer conditionals to be flattened.
- std::sort(selection_headers.begin(), selection_headers.end(),
- ComparatorDeepBlocksFirst(GetIRContext()));
+ // Sort the headers so that those that are more deeply nested are considered
+ // first, possibly enabling outer conditionals to be flattened.
+ std::sort(selection_headers.begin(), selection_headers.end(),
+ ComparatorDeepBlocksFirst(GetIRContext()));
- // Apply the transformation to the headers which can be flattened.
- for (auto header : selection_headers) {
- // Make a set to keep track of the instructions that need fresh ids.
- std::set<opt::Instruction*> instructions_that_need_ids;
+ // Apply the transformation to the headers which can be flattened.
+ for (auto header : selection_headers) {
+ // Make a set to keep track of the instructions that need fresh ids.
+ std::set<opt::Instruction*> instructions_that_need_ids;
- // Do not consider this header if the conditional cannot be flattened.
- if (!TransformationFlattenConditionalBranch::
- GetProblematicInstructionsIfConditionalCanBeFlattened(
- GetIRContext(), header, &instructions_that_need_ids)) {
- continue;
- }
-
- // Some instructions will require to be enclosed inside conditionals because
- // they have side effects (for example, loads and stores). Some of this have
- // no result id, so we require instruction descriptors to identify them.
- // Each of them is associated with the necessary ids for it via a
- // SideEffectWrapperInfo message.
- std::vector<protobufs::SideEffectWrapperInfo> wrappers_info;
-
- for (auto instruction : instructions_that_need_ids) {
- protobufs::SideEffectWrapperInfo wrapper_info;
- *wrapper_info.mutable_instruction() =
- MakeInstructionDescriptor(GetIRContext(), instruction);
- wrapper_info.set_merge_block_id(GetFuzzerContext()->GetFreshId());
- wrapper_info.set_execute_block_id(GetFuzzerContext()->GetFreshId());
-
- // If the instruction has a non-void result id, we need to define more
- // fresh ids and provide an id of the suitable type whose value can be
- // copied in order to create a placeholder id.
- if (TransformationFlattenConditionalBranch::InstructionNeedsPlaceholder(
- GetIRContext(), *instruction)) {
- wrapper_info.set_actual_result_id(GetFuzzerContext()->GetFreshId());
- wrapper_info.set_alternative_block_id(GetFuzzerContext()->GetFreshId());
- wrapper_info.set_placeholder_result_id(
- GetFuzzerContext()->GetFreshId());
-
- // The id will be a zero constant if the type allows it, and an OpUndef
- // otherwise. We want to avoid using OpUndef, if possible, to avoid
- // undefined behaviour in the module as much as possible.
- if (fuzzerutil::CanCreateConstant(
- *GetIRContext()->get_type_mgr()->GetType(
- instruction->type_id()))) {
- wrapper_info.set_value_to_copy_id(
- FindOrCreateZeroConstant(instruction->type_id(), true));
- } else {
- wrapper_info.set_value_to_copy_id(
- FindOrCreateGlobalUndef(instruction->type_id()));
- }
+ // Do not consider this header if the conditional cannot be flattened.
+ if (!TransformationFlattenConditionalBranch::
+ GetProblematicInstructionsIfConditionalCanBeFlattened(
+ GetIRContext(), header, &instructions_that_need_ids)) {
+ continue;
}
- wrappers_info.emplace_back(wrapper_info);
- }
+ // Some instructions will require to be enclosed inside conditionals
+ // because they have side effects (for example, loads and stores). Some of
+ // this have no result id, so we require instruction descriptors to
+ // identify them. Each of them is associated with the necessary ids for it
+ // via a SideEffectWrapperInfo message.
+ std::vector<protobufs::SideEffectWrapperInfo> wrappers_info;
- // Apply the transformation, evenly choosing whether to lay out the true
- // branch or the false branch first.
- ApplyTransformation(TransformationFlattenConditionalBranch(
- header->id(), GetFuzzerContext()->ChooseEven(), wrappers_info));
+ for (auto instruction : instructions_that_need_ids) {
+ protobufs::SideEffectWrapperInfo wrapper_info;
+ *wrapper_info.mutable_instruction() =
+ MakeInstructionDescriptor(GetIRContext(), instruction);
+ wrapper_info.set_merge_block_id(GetFuzzerContext()->GetFreshId());
+ wrapper_info.set_execute_block_id(GetFuzzerContext()->GetFreshId());
+
+ // If the instruction has a non-void result id, we need to define more
+ // fresh ids and provide an id of the suitable type whose value can be
+ // copied in order to create a placeholder id.
+ if (TransformationFlattenConditionalBranch::InstructionNeedsPlaceholder(
+ GetIRContext(), *instruction)) {
+ wrapper_info.set_actual_result_id(GetFuzzerContext()->GetFreshId());
+ wrapper_info.set_alternative_block_id(
+ GetFuzzerContext()->GetFreshId());
+ wrapper_info.set_placeholder_result_id(
+ GetFuzzerContext()->GetFreshId());
+
+ // The id will be a zero constant if the type allows it, and an
+ // OpUndef otherwise. We want to avoid using OpUndef, if possible, to
+ // avoid undefined behaviour in the module as much as possible.
+ if (fuzzerutil::CanCreateConstant(
+ *GetIRContext()->get_type_mgr()->GetType(
+ instruction->type_id()))) {
+ wrapper_info.set_value_to_copy_id(
+ FindOrCreateZeroConstant(instruction->type_id(), true));
+ } else {
+ wrapper_info.set_value_to_copy_id(
+ FindOrCreateGlobalUndef(instruction->type_id()));
+ }
+ }
+
+ wrappers_info.emplace_back(wrapper_info);
+ }
+
+ // Apply the transformation, evenly choosing whether to lay out the true
+ // branch or the false branch first.
+ ApplyTransformation(TransformationFlattenConditionalBranch(
+ header->id(), GetFuzzerContext()->ChooseEven(), wrappers_info));
+ }
}
}