diff options
author | alan-baker <alanbaker@google.com> | 2022-10-28 21:13:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-28 21:13:20 +0300 |
commit | a52de681dd17f8b545ecd9ea2138f72b39bf449a (patch) | |
tree | 541daceceb71316ee32acd6e87fba0eafbee0545 /source | |
parent | 4563d9093426fd8c5b461a8df338c500ae708d4c (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.cpp | 20 |
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; } |