Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authoralan-baker <alanbaker@google.com>2022-10-28 21:13:20 +0300
committerGitHub <noreply@github.com>2022-10-28 21:13:20 +0300
commita52de681dd17f8b545ecd9ea2138f72b39bf449a (patch)
tree541daceceb71316ee32acd6e87fba0eafbee0545 /source
parent4563d9093426fd8c5b461a8df338c500ae708d4c (diff)
Prevent eliminating case constructs in block merging (#4976)
Fixes #4918 * Prevent block merging from producing an invalid case construct by merging a switch target/default with another construct's merge or continue block * This is to satisfy the structural dominance requirement between the switch header and the case constructs
Diffstat (limited to 'source')
-rw-r--r--source/opt/block_merge_util.cpp20
1 files changed, 20 insertions, 0 deletions
diff --git a/source/opt/block_merge_util.cpp b/source/opt/block_merge_util.cpp
index 8ae8020a5..83c702ca3 100644
--- a/source/opt/block_merge_util.cpp
+++ b/source/opt/block_merge_util.cpp
@@ -125,6 +125,26 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) {
return false;
}
}
+
+ if (succ_is_merge || IsContinue(context, lab_id)) {
+ auto* struct_cfg = context->GetStructuredCFGAnalysis();
+ auto switch_block_id = struct_cfg->ContainingSwitch(block->id());
+ if (switch_block_id) {
+ auto switch_merge_id = struct_cfg->SwitchMergeBlock(switch_block_id);
+ const auto* switch_inst =
+ &*block->GetParent()->FindBlock(switch_block_id)->tail();
+ for (uint32_t i = 1; i < switch_inst->NumInOperands(); i += 2) {
+ auto target_id = switch_inst->GetSingleWordInOperand(i);
+ if (target_id == block->id() && target_id != switch_merge_id) {
+ // Case constructs must be structurally dominated by the OpSwitch.
+ // Since the successor is the merge/continue for another construct,
+ // merging the blocks would break that requirement.
+ return false;
+ }
+ }
+ }
+ }
+
return true;
}