diff options
Diffstat (limited to 'source/opt/block_merge_util.cpp')
-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; } |