[llvm] [llvm-reduce] Add a pass to replace unconditinal branches with returns (PR #180993)
Juan Manuel Martinez CaamaƱo via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 17 03:54:25 PST 2026
https://github.com/jmmartinez updated https://github.com/llvm/llvm-project/pull/180993
>From bf4635f4bdbc8d85f3d20ab4dbac6d9effc3f6fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
<jmartinezcaamao at gmail.com>
Date: Wed, 11 Feb 2026 19:42:52 +0100
Subject: [PATCH 1/2] [llvm-reduce] Add a pass to replace unconditinal branches
with returns
Unconditional branches could end up in infinite loops in the reduced code,
while the code could have been reduce furter.
This patch implements a simple pass that replaces unconditional branches
with returns.
---
llvm/test/tools/llvm-reduce/reduce-invoke.ll | 4 +-
.../tools/llvm-reduce/unconditional-br.ll | 40 +++++++++++++++++++
llvm/tools/llvm-reduce/DeltaPasses.def | 2 +
.../deltas/ReduceUsingSimplifyCFG.cpp | 37 +++++++++++++++++
.../deltas/ReduceUsingSimplifyCFG.h | 1 +
5 files changed, 82 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/tools/llvm-reduce/unconditional-br.ll
diff --git a/llvm/test/tools/llvm-reduce/reduce-invoke.ll b/llvm/test/tools/llvm-reduce/reduce-invoke.ll
index 73917a6b3c73c..6e1610573ca6d 100644
--- a/llvm/test/tools/llvm-reduce/reduce-invoke.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-invoke.ll
@@ -23,7 +23,7 @@ declare void @thrown()
; RESULT-SINGLE-NEXT: br label %bb3
; RESULT-FULL: %i0 = call i32 @maybe_throwing_callee()
-; RESULT-FULL-NEXT: br label %bb4
+; RESULT-FULL-NEXT: ret void
; RESULT-SINGLE: bb1: ; No predecessors!
@@ -94,7 +94,7 @@ bb:
%i0 = invoke i32 @maybe_throwing_callee(i32 %arg)
to label %bb3 unwind label %bb1, !some.metadata !0
-; RESULT: bb1: ; preds = %bb4
+; RESULT: bb1:
; RESULT-NEXT: %landing = landingpad { ptr, i32 }
; RESULT-NEXT: catch ptr null
bb1: ; preds = %bb
diff --git a/llvm/test/tools/llvm-reduce/unconditional-br.ll b/llvm/test/tools/llvm-reduce/unconditional-br.ll
new file mode 100644
index 0000000000000..25d5f5f2d2f5f
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/unconditional-br.ll
@@ -0,0 +1,40 @@
+; RUN: llvm-reduce -abort-on-invalid-reduction --delta-passes=simplify-unconditional-branch --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefix=RESULT %s < %t
+
+; CHECK_INTERESTINGNESS-LABEL: define void @test_void
+; CHECK-INTERESTINGNESS: %A = alloca i32
+; CHECK-INTERESTINGNESS: store i32 %V, ptr %A
+
+; RESULT-LABEL: define void @test_void
+; RESULT: entry:
+; RESULT-NEXT: %A = alloca i32
+; RESULT-NEXT: store i32 %V, ptr %A
+; RESULT-NEXT: ret void
+
+define void @test_void(i32 %V) {
+entry:
+ %A = alloca i32
+ br label %loop.body
+loop.body:
+ store i32 %V, ptr %A
+ br label %loop.body
+}
+
+; CHECK_INTERESTINGNESS-LABEL: define float @test_float
+; CHECK-INTERESTINGNESS: %A = alloca float
+; CHECK-INTERESTINGNESS: store float %V, ptr %A
+
+; RESULT-LABEL: define float @test_float
+; RESULT: entry:
+; RESULT-NEXT: %A = alloca float
+; RESULT-NEXT: store float %V, ptr %A
+; RESULT-NEXT: ret float 0
+
+define float @test_float(float %V) {
+entry:
+ %A = alloca float
+ br label %loop.body
+loop.body:
+ store float %V, ptr %A
+ br label %loop.body
+}
diff --git a/llvm/tools/llvm-reduce/DeltaPasses.def b/llvm/tools/llvm-reduce/DeltaPasses.def
index 1ec73544343e0..6fe4d23956afc 100644
--- a/llvm/tools/llvm-reduce/DeltaPasses.def
+++ b/llvm/tools/llvm-reduce/DeltaPasses.def
@@ -19,6 +19,8 @@ DELTA_PASS_IR("ifuncs", reduceIFuncsDeltaPass, "Reducing Ifuncs")
DELTA_PASS_IR("simplify-conditionals-true", reduceConditionalsTrueDeltaPass, "Reducing conditional branches to true")
DELTA_PASS_IR("simplify-conditionals-false",
reduceConditionalsFalseDeltaPass, "Reducing conditional branches to false")
+DELTA_PASS_IR("simplify-unconditional-branch",
+ reduceUnconditionalBranchDeltaPass, "Replace unconditional by return")
DELTA_PASS_IR("invokes", reduceInvokesDeltaPass, "Reducing Invokes")
DELTA_PASS_IR("unreachable-basic-blocks",
reduceUnreachableBasicBlocksDeltaPass, "Removing Unreachable Basic Blocks")
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
index a982524af4cf6..9a457d3550989 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
@@ -74,3 +74,40 @@ void llvm::reduceConditionalsFalseDeltaPass(Oracle &O,
ReducerWorkItem &WorkItem) {
reduceConditionals(O, WorkItem, false);
}
+
+void llvm::reduceUnconditionalBranchDeltaPass(Oracle &O,
+ ReducerWorkItem &WorkItem) {
+ Module &M = WorkItem.getModule();
+ LLVMContext &Ctx = M.getContext();
+
+ for (Function &F : M) {
+ if (F.isDeclaration())
+ continue;
+
+ SmallVector<BasicBlock *, 16> ToSimplify;
+
+ Type *RetTy = F.getReturnType();
+
+ for (auto &BB : F) {
+ auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
+ if (!BR || !BR->isUnconditional())
+ continue;
+
+ if (O.shouldKeep())
+ continue;
+
+ BasicBlock *Succ = BR->getSuccessor(0);
+ Succ->removePredecessor(&BB, true);
+ BR->eraseFromParent();
+ ToSimplify.push_back(&BB);
+
+ if (RetTy->isVoidTy())
+ ReturnInst::Create(Ctx, &BB);
+ else
+ ReturnInst::Create(Ctx, getDefaultValue(RetTy), &BB);
+ }
+
+ if (!ToSimplify.empty())
+ simpleSimplifyCFG(F, ToSimplify);
+ }
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h
index 48dce275574e9..4bcc86455b9cb 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h
+++ b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.h
@@ -20,6 +20,7 @@ namespace llvm {
void reduceUsingSimplifyCFGDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
void reduceConditionalsTrueDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
void reduceConditionalsFalseDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
+void reduceUnconditionalBranchDeltaPass(Oracle &O, ReducerWorkItem &WorkItem);
} // namespace llvm
#endif
>From fe532d095cb08a2d4ce7dde41422bc663cb5cac1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Juan=20Manuel=20Martinez=20Caama=C3=B1o?=
<jmartinezcaamao at gmail.com>
Date: Wed, 11 Feb 2026 20:36:36 +0100
Subject: [PATCH 2/2] [review] Add test case with phi-nodes and switch
---
.../tools/llvm-reduce/unconditional-br-phi.ll | 89 +++++++++++++++++++
.../deltas/ReduceUsingSimplifyCFG.cpp | 2 +-
2 files changed, 90 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/tools/llvm-reduce/unconditional-br-phi.ll
diff --git a/llvm/test/tools/llvm-reduce/unconditional-br-phi.ll b/llvm/test/tools/llvm-reduce/unconditional-br-phi.ll
new file mode 100644
index 0000000000000..24e9f7975ca7a
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/unconditional-br-phi.ll
@@ -0,0 +1,89 @@
+; RUN: llvm-reduce -abort-on-invalid-reduction --delta-passes=simplify-unconditional-branch --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefix=RESULT %s < %t
+
+; CHECK_INTERESTINGNESS-LABEL: define void @test_phi1
+; CHECK-INTERESTINGNESS: %A = alloca i32
+; CHECK-INTERESTINGNESS: store i32 %{{P|V}}, ptr %A
+
+; RESULT-LABEL: define void @test_phi1
+; RESULT: entry:
+; RESULT-NEXT: %A = alloca i32
+; RESULT-NEXT: store i32 %V, ptr %A
+; RESULT-NEXT: ret void
+
+define void @test_phi1(i32 %V) {
+entry:
+ %A = alloca i32
+ br label %loop.body
+loop.body:
+ %P = phi i32 [ %V, %entry ], [ %P, %loop.body ]
+ store i32 %P, ptr %A
+ br label %loop.body
+}
+
+; CHECK_INTERESTINGNESS-LABEL: define void @test_phi2
+; CHECK-INTERESTINGNESS: %A = alloca i32
+; CHECK-INTERESTINGNESS: store i32 %{{P|V}}, ptr %A
+
+; RESULT-LABEL: define void @test_phi2
+; RESULT: entry:
+; RESULT-NEXT: %A = alloca i32
+; RESULT-NEXT: br i1 %C, label %loop.body, label %load
+; RESULT: load:
+; RESULT-NEXT: %L = load i32, ptr %A
+; RESULT-NEXT: ret void
+; RESULT: loop.body:
+; RESULT-NEXT: %P = phi i32 [ %V, %entry ]
+; RESULT-NEXT: store i32 %P, ptr %A
+; RESULT-NEXT: ret void
+
+define void @test_phi2(i1 %C, i32 %V) {
+entry:
+ %A = alloca i32
+ br i1 %C, label %loop.body, label %load
+load:
+ %L = load i32, ptr %A
+ br label %loop.body
+loop.body:
+ %P = phi i32 [ %V, %entry ], [ %P, %loop.body ], [ %L, %load ]
+ store i32 %P, ptr %A
+ br label %loop.body
+}
+
+; CHECK_INTERESTINGNESS-LABEL: define void @test_phi3
+; CHECK-INTERESTINGNESS: %A = alloca i32
+; CHECK-INTERESTINGNESS: store i32 %{{P|V}}, ptr %A
+
+; RESULT-LABEL: define void @test_phi3
+; RESULT: entry:
+; RESULT-NEXT: %A = alloca i32
+; RESULT-NEXT: switch i32 %S, label %loop.body [
+; RESULT-NEXT: i32 1, label %loop.body
+; RESULT-NEXT: i32 2, label %loop.body
+; RESULT-NEXT: i32 3, label %load
+; RESULT-NEXT: ]
+; RESULT: load:
+; RESULT-NEXT: %L = load i32, ptr %A
+; RESULT-NEXT: ret void
+; RESULT: loop.body:
+; RESULT-NEXT: %P = phi i32 [ %V, %entry ], [ %V, %entry ], [ %V, %entry ]
+; RESULT-NEXT: store i32 %P, ptr %A
+; RESULT-NEXT: ret void
+
+
+define void @test_phi3(i32 %S, i32 %V) {
+entry:
+ %A = alloca i32
+ switch i32 %S, label %loop.body [
+ i32 1, label %loop.body
+ i32 2, label %loop.body
+ i32 3, label %load
+ ]
+load:
+ %L = load i32, ptr %A
+ br label %loop.body
+loop.body:
+ %P = phi i32 [ %V, %entry ], [ %P, %loop.body ], [ %V, %entry ], [ %V, %entry ], [ %L, %load ]
+ store i32 %P, ptr %A
+ br label %loop.body
+}
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
index 9a457d3550989..7dc6323c21f67 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
@@ -97,7 +97,7 @@ void llvm::reduceUnconditionalBranchDeltaPass(Oracle &O,
continue;
BasicBlock *Succ = BR->getSuccessor(0);
- Succ->removePredecessor(&BB, true);
+ Succ->removePredecessor(&BB, /*KeepOneInputPHIs=*/true);
BR->eraseFromParent();
ToSimplify.push_back(&BB);
More information about the llvm-commits
mailing list