[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