[llvm] [SimplifyCFG] Enable MergeBlockIntoPredecessor with two successors (PR #143766)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 12 10:57:21 PDT 2025
https://github.com/HighW4y2H3ll updated https://github.com/llvm/llvm-project/pull/143766
>From fd6f81531b3e16906024a6b69ae69a99c0620dca Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Tue, 10 Jun 2025 15:41:26 -0700
Subject: [PATCH 1/3] [SimplifyCFG] Enable MergeBlockIntoPredecessor with two
successors
---
llvm/lib/Transforms/Utils/BasicBlockUtils.cpp | 34 +++++++++++
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 2 +-
.../SimplifyCFG/two-succ-merge-block.ll | 58 +++++++++++++++++++
3 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll
diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index 6608515e1cbbc..473aaa90962be 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -207,6 +207,10 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU,
if (PredecessorWithTwoSuccessors) {
if (!(PredBB_BI = dyn_cast<BranchInst>(PTI)))
return false;
+ // Can't merge if any of the instructions has side effects
+ for (Instruction &candid : *BB)
+ if (candid.mayHaveSideEffects())
+ return false;
BranchInst *BB_JmpI = dyn_cast<BranchInst>(BB->getTerminator());
if (!BB_JmpI || !BB_JmpI->isUnconditional())
return false;
@@ -283,6 +287,36 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU,
if (MSSAU)
MSSAU->moveAllAfterMergeBlocks(BB, PredBB, Start);
+ // PHI nodes that references the Pred shall be replaced with a SelectInst
+ for (BasicBlock *Succ : successors(PTI)) {
+ if (Succ == BB)
+ continue;
+ for (PHINode &PhiSucc : Succ->phis()) {
+ if (llvm::is_contained(PhiSucc.blocks(), PredBB)) {
+ if (PredBB_BI->isConditional()) {
+ Value *Cond = PredBB_BI->getCondition();
+ Value *OrigPhi0 = PhiSucc.removeIncomingValue(PredBB, false);
+ Value *newPhi = OrigPhi0;
+
+ if (PhiSucc.getNumOperands() > 0) {
+ if (llvm::is_contained(PhiSucc.blocks(), BB)) {
+ Value *OrigPhi1 = PhiSucc.removeIncomingValue(BB, false);
+ // Swap branch given the conditions
+ if (PredBB_BI->getSuccessor(0) == Succ) {
+ newPhi = SelectInst::Create(Cond, OrigPhi0, OrigPhi1, "", PTI->getIterator());
+ } else {
+ newPhi = SelectInst::Create(Cond, OrigPhi1, OrigPhi0, "", PTI->getIterator());
+ }
+ PhiSucc.addIncoming(newPhi, PredBB);
+ }
+ }
+
+ PhiSucc.addIncoming(newPhi, PredBB);
+ }
+ }
+ }
+ }
+
// Make all PHI nodes that referred to BB now refer to Pred as their
// source...
BB->replaceAllUsesWith(PredBB);
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 975ce3bef5176..47f7a2449cb0b 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -8339,7 +8339,7 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) {
// Merge basic blocks into their predecessor if there is only one distinct
// pred, and if there is only one distinct successor of the predecessor, and
// if there are no PHI nodes.
- if (MergeBlockIntoPredecessor(BB, DTU))
+ if (MergeBlockIntoPredecessor(BB, DTU, nullptr, nullptr, nullptr, true))
return true;
if (SinkCommon && Options.SinkCommonInsts)
diff --git a/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll b/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll
new file mode 100644
index 0000000000000..eb8ac774b6e5b
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --tool ./opt --version 5
+; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s
+
+define i1 @_Z7compareRK1SS1_(ptr %a, ptr %b) {
+; CHECK-LABEL: @_Z7compareRK1SS1_(
+; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: %0 = load i32, ptr %a, align 4, !tbaa !3
+; CHECK-NEXT: %1 = load i32, ptr %b, align 4, !tbaa !3
+; CHECK-NEXT: %cmp.i = icmp slt i32 %0, %1
+; CHECK-NEXT: %cmp.i19 = icmp eq i32 %0, %1
+; CHECK-NEXT: %y = getelementptr inbounds nuw i8, ptr %a, i64 4
+; CHECK-NEXT: %2 = load i32, ptr %y, align 4, !tbaa !8
+; CHECK-NEXT: %y14 = getelementptr inbounds nuw i8, ptr %b, i64 4
+; CHECK-NEXT: %3 = load i32, ptr %y14, align 4, !tbaa !8
+; CHECK-NEXT: %cmp = icmp slt i32 %2, %3
+; CHECK-NEXT: %4 = select i1 %cmp.i19, i1 %cmp, i1 false
+; CHECK-NEXT: %5 = select i1 %cmp.i, i1 true, i1 %4
+; CHECK-NEXT: br label %lor.end
+; CHECK-EMPTY:
+; CHECK-NEXT: lor.end: ; preds = %entry
+; CHECK-NEXT: ret i1 %5
+entry:
+ %0 = load i32, ptr %a, align 4, !tbaa !3
+ %1 = load i32, ptr %b, align 4, !tbaa !3
+ %cmp.i = icmp slt i32 %0, %1
+ br i1 %cmp.i, label %lor.end, label %lor.rhs
+
+lor.rhs: ; preds = %entry
+ %cmp.i19 = icmp eq i32 %0, %1
+ br i1 %cmp.i19, label %land.rhs, label %lor.end
+
+land.rhs: ; preds = %lor.rhs
+ %y = getelementptr inbounds nuw i8, ptr %a, i64 4
+ %2 = load i32, ptr %y, align 4, !tbaa !8
+ %y14 = getelementptr inbounds nuw i8, ptr %b, i64 4
+ %3 = load i32, ptr %y14, align 4, !tbaa !8
+ %cmp = icmp slt i32 %2, %3
+ br label %lor.end
+
+lor.end: ; preds = %lor.rhs, %land.rhs, %entry
+ %4 = phi i1 [ true, %entry ], [ false, %lor.rhs ], [ %cmp, %land.rhs ]
+ ret i1 %4
+}
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 7, !"uwtable", i32 2}
+!2 = !{!"clang"}
+!3 = !{!4, !5, i64 0}
+!4 = !{!"_ZTS1S", !5, i64 0, !5, i64 4}
+!5 = !{!"int", !6, i64 0}
+!6 = !{!"omnipotent char", !7, i64 0}
+!7 = !{!"Simple C++ TBAA"}
+!8 = !{!4, !5, i64 4}
+!9 = !{!5, !5, i64 0}
>From d912e14c4aac9eae8bafec749c663d35b914ee7c Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Wed, 11 Jun 2025 19:28:32 -0700
Subject: [PATCH 2/3] Patch simplifyCFG back to merge one successor and check
for compatibility
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 47f7a2449cb0b..975ce3bef5176 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -8339,7 +8339,7 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) {
// Merge basic blocks into their predecessor if there is only one distinct
// pred, and if there is only one distinct successor of the predecessor, and
// if there are no PHI nodes.
- if (MergeBlockIntoPredecessor(BB, DTU, nullptr, nullptr, nullptr, true))
+ if (MergeBlockIntoPredecessor(BB, DTU))
return true;
if (SinkCommon && Options.SinkCommonInsts)
>From 3432037d4cfc384f529064da5b82ae14fee44ef9 Mon Sep 17 00:00:00 2001
From: h2h <h2h at meta.com>
Date: Thu, 12 Jun 2025 10:57:03 -0700
Subject: [PATCH 3/3] Add cmdline option to apply more aggressive cfg merging
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 6 +++++-
llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 975ce3bef5176..b9e8a55d97383 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -198,6 +198,10 @@ static cl::opt<unsigned> MaxSwitchCasesPerResult(
"max-switch-cases-per-result", cl::Hidden, cl::init(16),
cl::desc("Limit cases to analyze when converting a switch to select"));
+static cl::opt<bool> MergeBlockIntoPredecessorWithTwoSuccessor(
+ "simplifycfg-merge-into-pred-with-two-succ", cl::Hidden, cl::init(false),
+ cl::desc("Allow SimplifyCFG to merge blocks into predecessor even when the predecessor has two successors"));
+
STATISTIC(NumBitMaps, "Number of switch instructions turned into bitmaps");
STATISTIC(NumLinearMaps,
"Number of switch instructions turned into linear mapping");
@@ -8339,7 +8343,7 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) {
// Merge basic blocks into their predecessor if there is only one distinct
// pred, and if there is only one distinct successor of the predecessor, and
// if there are no PHI nodes.
- if (MergeBlockIntoPredecessor(BB, DTU))
+ if (MergeBlockIntoPredecessor(BB, DTU, nullptr, nullptr, nullptr, MergeBlockIntoPredecessorWithTwoSuccessor))
return true;
if (SinkCommon && Options.SinkCommonInsts)
diff --git a/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll b/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll
index eb8ac774b6e5b..70f615f738f9f 100644
--- a/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll
+++ b/llvm/test/Transforms/SimplifyCFG/two-succ-merge-block.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --tool ./opt --version 5
-; RUN: opt < %s -passes=simplifycfg -S | FileCheck %s
+; RUN: opt < %s -passes=simplifycfg -simplifycfg-merge-into-pred-with-two-succ -S | FileCheck %s
define i1 @_Z7compareRK1SS1_(ptr %a, ptr %b) {
; CHECK-LABEL: @_Z7compareRK1SS1_(
More information about the llvm-commits
mailing list