[llvm] [UnifyFunctionExitNodes] remove the pass (PR #205519)
Arda Serdar Pektezol via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 24 03:02:54 PDT 2026
https://github.com/pektezol created https://github.com/llvm/llvm-project/pull/205519
The mergereturn pass is not used by anything, so we can go ahead and delete it.
>From f678e6aa0064b3a879100f2a86a23b774407fd0e Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Wed, 24 Jun 2026 13:01:02 +0300
Subject: [PATCH] [UnifyFunctionExitNodes] remove the pass
---
llvm/docs/Passes.md | 5 -
.../Transforms/Utils/UnifyFunctionExitNodes.h | 30 ------
llvm/lib/Passes/PassBuilder.cpp | 1 -
llvm/lib/Passes/PassRegistry.def | 1 -
llvm/lib/Transforms/Utils/CMakeLists.txt | 1 -
.../Utils/UnifyFunctionExitNodes.cpp | 94 -------------------
.../unreachable-blocks-status.ll | 67 -------------
7 files changed, 199 deletions(-)
delete mode 100644 llvm/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h
delete mode 100644 llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp
delete mode 100644 llvm/test/Transforms/UnifyFunctionExitNodes/unreachable-blocks-status.ll
diff --git a/llvm/docs/Passes.md b/llvm/docs/Passes.md
index 28ea11eb994d9..36159ff0c5206 100644
--- a/llvm/docs/Passes.md
+++ b/llvm/docs/Passes.md
@@ -745,11 +745,6 @@ Read
{doc}`this <MergeFunctions>`
article for more details.
-### `mergereturn`: Unify function exit nodes
-
-Ensure that functions have at most one `ret` instruction in them.
-Additionally, it keeps track of which node is the new exit node of the CFG.
-
### `partial-inliner`: Partial Inliner
This pass performs partial inlining, typically by inlining an `if` statement
diff --git a/llvm/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h b/llvm/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h
deleted file mode 100644
index 92df7b480ff5d..0000000000000
--- a/llvm/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h
+++ /dev/null
@@ -1,30 +0,0 @@
-//===-- UnifyFunctionExitNodes.h - Ensure fn's have one return --*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This pass is used to ensure that functions have at most one return and one
-// unreachable instruction in them.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TRANSFORMS_UTILS_UNIFYFUNCTIONEXITNODES_H
-#define LLVM_TRANSFORMS_UTILS_UNIFYFUNCTIONEXITNODES_H
-
-#include "llvm/IR/PassManager.h"
-#include "llvm/Pass.h"
-
-namespace llvm {
-
-class UnifyFunctionExitNodesPass
- : public OptionalPassInfoMixin<UnifyFunctionExitNodesPass> {
-public:
- LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
-};
-
-} // end namespace llvm
-
-#endif // LLVM_TRANSFORMS_UTILS_UNIFYFUNCTIONEXITNODES_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index de32ed34a3df4..68ea19332ec33 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -391,7 +391,6 @@
#include "llvm/Transforms/Utils/StripNonLineTableDebugInfo.h"
#include "llvm/Transforms/Utils/SymbolRewriter.h"
#include "llvm/Transforms/Utils/TriggerCrashPass.h"
-#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Transforms/Utils/UnifyLoopExits.h"
#include "llvm/Transforms/Vectorize/LoadStoreVectorizer.h"
#include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 370106e225a9b..84804c3e9d2a8 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -493,7 +493,6 @@ FUNCTION_PASS("mem2reg", PromotePass())
FUNCTION_PASS("memcpyopt", MemCpyOptPass())
FUNCTION_PASS("memprof", MemProfilerPass())
FUNCTION_PASS("mergeicmps", MergeICmpsPass())
-FUNCTION_PASS("mergereturn", UnifyFunctionExitNodesPass())
FUNCTION_PASS("move-auto-init", MoveAutoInitPass())
FUNCTION_PASS("nary-reassociate", NaryReassociatePass())
FUNCTION_PASS("newgvn", NewGVNPass())
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 0088d439e6895..ebff5af0dd7f3 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -92,7 +92,6 @@ add_llvm_component_library(LLVMTransformUtils
StripNonLineTableDebugInfo.cpp
SymbolRewriter.cpp
TriggerCrashPass.cpp
- UnifyFunctionExitNodes.cpp
UnifyLoopExits.cpp
Utils.cpp
ValueMapper.cpp
diff --git a/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp b/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp
deleted file mode 100644
index 17fa30e436c2f..0000000000000
--- a/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-//===- UnifyFunctionExitNodes.cpp - Make all functions have a single exit -===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This pass is used to ensure that functions have at most one return and one
-// unreachable instruction in them.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Type.h"
-using namespace llvm;
-
-namespace {
-
-bool unifyUnreachableBlocks(Function &F) {
- std::vector<BasicBlock *> UnreachableBlocks;
-
- for (BasicBlock &I : F)
- if (isa<UnreachableInst>(I.getTerminator()))
- UnreachableBlocks.push_back(&I);
-
- if (UnreachableBlocks.size() <= 1)
- return false;
-
- BasicBlock *UnreachableBlock =
- BasicBlock::Create(F.getContext(), "UnifiedUnreachableBlock", &F);
- new UnreachableInst(F.getContext(), UnreachableBlock);
-
- for (BasicBlock *BB : UnreachableBlocks) {
- BB->back().eraseFromParent(); // Remove the unreachable inst.
- UncondBrInst::Create(UnreachableBlock, BB);
- }
-
- return true;
-}
-
-bool unifyReturnBlocks(Function &F) {
- std::vector<BasicBlock *> ReturningBlocks;
-
- for (BasicBlock &I : F)
- if (isa<ReturnInst>(I.getTerminator()))
- ReturningBlocks.push_back(&I);
-
- if (ReturningBlocks.size() <= 1)
- return false;
-
- // Insert a new basic block into the function, add PHI nodes (if the function
- // returns values), and convert all of the return instructions into
- // unconditional branches.
- BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(),
- "UnifiedReturnBlock", &F);
-
- PHINode *PN = nullptr;
- if (F.getReturnType()->isVoidTy()) {
- ReturnInst::Create(F.getContext(), nullptr, NewRetBlock);
- } else {
- // If the function doesn't return void... add a PHI node to the block...
- PN = PHINode::Create(F.getReturnType(), ReturningBlocks.size(),
- "UnifiedRetVal");
- PN->insertInto(NewRetBlock, NewRetBlock->end());
- ReturnInst::Create(F.getContext(), PN, NewRetBlock);
- }
-
- // Loop over all of the blocks, replacing the return instruction with an
- // unconditional branch.
- for (BasicBlock *BB : ReturningBlocks) {
- // Add an incoming element to the PHI node for every return instruction that
- // is merging into this new block...
- if (PN)
- PN->addIncoming(BB->getTerminator()->getOperand(0), BB);
-
- BB->back().eraseFromParent(); // Remove the return insn
- UncondBrInst::Create(NewRetBlock, BB);
- }
-
- return true;
-}
-} // namespace
-
-PreservedAnalyses UnifyFunctionExitNodesPass::run(Function &F,
- FunctionAnalysisManager &AM) {
- bool Changed = false;
- Changed |= unifyUnreachableBlocks(F);
- Changed |= unifyReturnBlocks(F);
- return Changed ? PreservedAnalyses() : PreservedAnalyses::all();
-}
diff --git a/llvm/test/Transforms/UnifyFunctionExitNodes/unreachable-blocks-status.ll b/llvm/test/Transforms/UnifyFunctionExitNodes/unreachable-blocks-status.ll
deleted file mode 100644
index a6832c79dad43..0000000000000
--- a/llvm/test/Transforms/UnifyFunctionExitNodes/unreachable-blocks-status.ll
+++ /dev/null
@@ -1,67 +0,0 @@
-; RUN: opt -passes='break-crit-edges,lower-switch,mergereturn' -S < %s | FileCheck %s
-
-; The pass did previously not report the correct Modified status in the case
-; where a function had at most one return block, and an unified unreachable
-; block was created. This was caught by the pass return status check that is
-; hidden under EXPENSIVE_CHECKS.
-
-; CHECK: for.foo.body2:
-; CHECK-NEXT: br label %UnifiedUnreachableBlock
-
-; CHECK: for.foo.end:
-; CHECK-NEXT: br label %UnifiedUnreachableBlock
-
-; CHECK: UnifiedUnreachableBlock:
-; CHECK-NEXT: unreachable
-
-define i32 @foo() {
-entry:
- br label %for.foo.cond
-
-for.foo.cond: ; preds = %entry
- br i1 false, label %for.foo.body, label %for.foo.end3
-
-for.foo.body: ; preds = %for.foo.cond
- br label %for.foo.cond1
-
-for.foo.cond1: ; preds = %for.foo.body
- br i1 false, label %for.foo.body2, label %for.foo.end
-
-for.foo.body2: ; preds = %for.foo.cond1
- unreachable
-
-for.foo.end: ; preds = %for.foo.cond1
- unreachable
-
-for.foo.end3: ; preds = %for.foo.cond
- ret i32 undef
-}
-
-; CHECK: for.bar.body2:
-; CHECK-NEXT: br label %UnifiedUnreachableBlock
-
-; CHECK: for.bar.end:
-; CHECK-NEXT: br label %UnifiedUnreachableBlock
-
-; CHECK: UnifiedUnreachableBlock:
-; CHECK-NEXT: unreachable
-
-define void @bar() {
-entry:
- br label %for.bar.cond
-
-for.bar.cond: ; preds = %entry
- br i1 false, label %for.bar.body, label %for.bar.end
-
-for.bar.body: ; preds = %for.bar.cond
- br label %for.bar.cond1
-
-for.bar.cond1: ; preds = %for.bar.body
- br i1 false, label %for.bar.body2, label %for.bar.end
-
-for.bar.body2: ; preds = %for.bar.cond1
- unreachable
-
-for.bar.end: ; preds = %for.bar.cond1
- unreachable
-}
More information about the llvm-commits
mailing list