[llvm] f1daa4c - [CodeGen][BranchFolding] Add options to control common hoisting and block reordering (#205704)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 9 19:52:02 PDT 2026


Author: Hongjune Kim
Date: 2026-07-09T19:51:57-07:00
New Revision: f1daa4cd537799edcd2984b09ab59e0f9e00e2bf

URL: https://github.com/llvm/llvm-project/commit/f1daa4cd537799edcd2984b09ab59e0f9e00e2bf
DIFF: https://github.com/llvm/llvm-project/commit/f1daa4cd537799edcd2984b09ab59e0f9e00e2bf.diff

LOG: [CodeGen][BranchFolding] Add options to control common hoisting and block reordering (#205704)

The BranchFolder pass performs several independent optimizations: tail
 merging, common-code hoisting, and branch optimization (which includes
 basic-block reordering). Currently only tail merging is individually
controllable -- it is disabled for targets that require a structured
CFG,
because tail merging can make the CFG irreducible. Common-code hoisting
and
 basic-block reordering always run whenever the pass executes.

 Those two sub-phases do not change CFG edges (so they cannot affect
 reducibility); they only change block layout. A target whose register
 allocation is sensitive to the final block layout may need the rest of
 branch folding while suppressing reordering and/or hoisting. This is a
 layout / register-allocation concern, distinct from the structured-CFG
 (reducibility) concern that gates tail merging.

 This change makes common-code hoisting and basic-block reordering
 individually controllable:

  - BranchFolder gains an EnableBasicBlockReordering flag (with a
setBasicBlockReordering() setter) that gates the two block-reordering
    transforms in OptimizeBlock.
- BranchFolderLegacy gains constructor parameters for both sub-phases,
and a
createBranchFolder(EnableCommonHoist, EnableBasicBlockReordering)
factory
is exposed so a target can request a safe subset from its pass pipeline.
  - Two hidden command-line flags, -branch-folder-hoist-common-code and
-branch-folder-reorder-blocks, override the configured values at the
start
    of OptimizeFunction (mirroring -enable-tail-merge).

Defaults enable both sub-phases, so existing behavior is unchanged for
all
 in-tree targets.

 New MIR tests exercise each flag via -run-pass=branch-folder.

 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply at anthropic.com>

Added: 
    llvm/test/CodeGen/AArch64/branch-folder-hoist-disable.mir
    llvm/test/CodeGen/AArch64/branch-folder-reorder-disable.mir

Modified: 
    llvm/include/llvm/CodeGen/Passes.h
    llvm/lib/CodeGen/BranchFolding.cpp
    llvm/lib/CodeGen/BranchFolding.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 34ba2a2cae897..86bf5aea7b23a 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -279,6 +279,13 @@ LLVM_ABI extern char &PostRASchedulerID;
 /// branches.
 LLVM_ABI extern char &BranchFolderPassID;
 
+/// createBranchFolder - Create the BranchFolder pass, optionally disabling the
+/// common-code hoisting and/or basic-block reordering sub-phases. Default
+/// enables both (full BranchFolding behavior).
+LLVM_ABI FunctionPass *
+createBranchFolder(bool EnableCommonHoist = true,
+                   bool EnableBasicBlockReordering = true);
+
 /// BranchRelaxation - This pass replaces branches that need to jump further
 /// than is supported by a branch instruction.
 LLVM_ABI extern char &BranchRelaxationPassID;

diff  --git a/llvm/lib/CodeGen/BranchFolding.cpp b/llvm/lib/CodeGen/BranchFolding.cpp
index 2fdd766102a7f..79fd1e833a4c5 100644
--- a/llvm/lib/CodeGen/BranchFolding.cpp
+++ b/llvm/lib/CodeGen/BranchFolding.cpp
@@ -78,6 +78,20 @@ static cl::opt<cl::boolOrDefault>
     FlagEnableTailMerge("enable-tail-merge",
                         cl::init(cl::boolOrDefault::BOU_UNSET), cl::Hidden);
 
+// Override the common-code hoisting sub-phase of BranchFolding. Unset by
+// default, in which case the value configured by the caller is used.
+static cl::opt<cl::boolOrDefault> FlagEnableHoistCommonCode(
+    "branch-folder-hoist-common-code", cl::init(cl::boolOrDefault::BOU_UNSET),
+    cl::Hidden,
+    cl::desc("Override common-code hoisting in the BranchFolding pass"));
+
+// Override the basic-block reordering sub-phase of BranchFolding. Unset by
+// default, in which case the value configured by the caller is used.
+static cl::opt<cl::boolOrDefault> FlagEnableBlockReordering(
+    "branch-folder-reorder-blocks", cl::init(cl::boolOrDefault::BOU_UNSET),
+    cl::Hidden,
+    cl::desc("Override basic-block reordering in the BranchFolding pass"));
+
 // Throttle for huge numbers of predecessors (compile speed problems)
 static cl::opt<unsigned>
 TailMergeThreshold("tail-merge-threshold",
@@ -94,10 +108,16 @@ namespace {
 
   /// BranchFolderPass - Wrap branch folder in a machine function pass.
 class BranchFolderLegacy : public MachineFunctionPass {
+  bool EnableCommonHoist;
+  bool EnableBasicBlockReordering;
+
 public:
   static char ID;
 
-  explicit BranchFolderLegacy() : MachineFunctionPass(ID) {}
+  explicit BranchFolderLegacy(bool EnableCommonHoist = true,
+                              bool EnableBasicBlockReordering = true)
+      : MachineFunctionPass(ID), EnableCommonHoist(EnableCommonHoist),
+        EnableBasicBlockReordering(EnableBasicBlockReordering) {}
 
   bool runOnMachineFunction(MachineFunction &MF) override;
 
@@ -141,6 +161,7 @@ PreservedAnalyses BranchFolderPass::run(MachineFunction &MF,
   MBFIWrapper MBBFreqInfo(MBFI);
   BranchFolder Folder(EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo, MBPI,
                       PSI);
+  Folder.setBasicBlockReordering(true);
   if (Folder.OptimizeFunction(MF, MF.getSubtarget().getInstrInfo(),
                               MF.getSubtarget().getRegisterInfo()))
     return getMachineFunctionPassPreservedAnalyses();
@@ -160,9 +181,10 @@ bool BranchFolderLegacy::runOnMachineFunction(MachineFunction &MF) {
   MBFIWrapper MBBFreqInfo(
       getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI());
   BranchFolder Folder(
-      EnableTailMerge, /*CommonHoist=*/true, MBBFreqInfo,
+      EnableTailMerge, EnableCommonHoist, MBBFreqInfo,
       getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI(),
       &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI());
+  Folder.setBasicBlockReordering(EnableBasicBlockReordering);
   return Folder.OptimizeFunction(MF, MF.getSubtarget().getInstrInfo(),
                                  MF.getSubtarget().getRegisterInfo());
 }
@@ -171,8 +193,9 @@ BranchFolder::BranchFolder(bool DefaultEnableTailMerge, bool CommonHoist,
                            MBFIWrapper &FreqInfo,
                            const MachineBranchProbabilityInfo &ProbInfo,
                            ProfileSummaryInfo *PSI, unsigned MinTailLength)
-    : EnableHoistCommonCode(CommonHoist), MinCommonTailLength(MinTailLength),
-      MBBFreqInfo(FreqInfo), MBPI(ProbInfo), PSI(PSI) {
+    : EnableHoistCommonCode(CommonHoist), EnableBasicBlockReordering(true),
+      MinCommonTailLength(MinTailLength), MBBFreqInfo(FreqInfo), MBPI(ProbInfo),
+      PSI(PSI) {
   switch (FlagEnableTailMerge) {
   case cl::boolOrDefault::BOU_UNSET:
     EnableTailMerge = DefaultEnableTailMerge;
@@ -235,6 +258,16 @@ bool BranchFolder::OptimizeFunction(MachineFunction &MF,
   if (!UpdateLiveIns)
     MRI.invalidateLiveness();
 
+  // Command-line flags take final precedence over the caller-configured values,
+  // letting individual BranchFolding sub-phases be toggled (for tests and for
+  // targets that only want a safe subset of the optimization).
+  if (FlagEnableHoistCommonCode != cl::boolOrDefault::BOU_UNSET)
+    EnableHoistCommonCode =
+        FlagEnableHoistCommonCode == cl::boolOrDefault::BOU_TRUE;
+  if (FlagEnableBlockReordering != cl::boolOrDefault::BOU_UNSET)
+    EnableBasicBlockReordering =
+        FlagEnableBlockReordering == cl::boolOrDefault::BOU_TRUE;
+
   bool MadeChange = false;
 
   // Recalculate EH scope membership.
@@ -1526,8 +1559,8 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) {
     // We consider it more likely that execution will stay in the function (e.g.
     // due to loops) than it is to exit it.  This asserts in loops etc, moving
     // the assert condition out of the loop body.
-    if (MBB->succ_empty() && !PriorCond.empty() && !PriorFBB &&
-        MachineFunction::iterator(PriorTBB) == FallThrough &&
+    if (EnableBasicBlockReordering && MBB->succ_empty() && !PriorCond.empty() &&
+        !PriorFBB && MachineFunction::iterator(PriorTBB) == FallThrough &&
         !MBB->canFallThrough()) {
       bool DoTransform = true;
 
@@ -1723,7 +1756,7 @@ bool BranchFolder::OptimizeBlock(MachineBasicBlock *MBB) {
   // If the prior block doesn't fall through into this block, and if this
   // block doesn't fall through into some other block, see if we can find a
   // place to move this block where a fall-through will happen.
-  if (!PrevBB.canFallThrough()) {
+  if (EnableBasicBlockReordering && !PrevBB.canFallThrough()) {
     // Now we know that there was no fall-through into this block, check to
     // see if it has a fall-through into its successor.
     bool CurFallsThru = MBB->canFallThrough();
@@ -2182,3 +2215,8 @@ bool BranchFolder::HoistCommonCodeInSuccs(MachineBasicBlock *MBB) {
   ++NumHoist;
   return true;
 }
+
+FunctionPass *llvm::createBranchFolder(bool EnableCommonHoist,
+                                       bool EnableBasicBlockReordering) {
+  return new BranchFolderLegacy(EnableCommonHoist, EnableBasicBlockReordering);
+}

diff  --git a/llvm/lib/CodeGen/BranchFolding.h b/llvm/lib/CodeGen/BranchFolding.h
index ff2bbe06c0488..f57211a34b0bc 100644
--- a/llvm/lib/CodeGen/BranchFolding.h
+++ b/llvm/lib/CodeGen/BranchFolding.h
@@ -46,6 +46,13 @@ class TargetRegisterInfo;
                           MachineLoopInfo *mli = nullptr,
                           bool AfterPlacement = false);
 
+    /// Enable or disable the basic-block reordering sub-phase of branch
+    /// optimization. Enabled by default; targets sensitive to block layout
+    /// (e.g. those with structured-CFG register allocation) can disable it.
+    void setBasicBlockReordering(bool Enable) {
+      EnableBasicBlockReordering = Enable;
+    }
+
   private:
     class MergePotentialsElt {
       unsigned Hash;
@@ -119,6 +126,7 @@ class TargetRegisterInfo;
     bool AfterBlockPlacement = false;
     bool EnableTailMerge = false;
     bool EnableHoistCommonCode = false;
+    bool EnableBasicBlockReordering = false;
     bool UpdateLiveIns = false;
     unsigned MinCommonTailLength;
     const TargetInstrInfo *TII = nullptr;

diff  --git a/llvm/test/CodeGen/AArch64/branch-folder-hoist-disable.mir b/llvm/test/CodeGen/AArch64/branch-folder-hoist-disable.mir
new file mode 100644
index 0000000000000..4ae1d9ac04320
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/branch-folder-hoist-disable.mir
@@ -0,0 +1,46 @@
+# RUN: llc -o - %s -mtriple=aarch64 -run-pass branch-folder -verify-machineinstrs | FileCheck %s --check-prefix=HOIST
+# RUN: llc -o - %s -mtriple=aarch64 -run-pass branch-folder -branch-folder-hoist-common-code=false -verify-machineinstrs | FileCheck %s --check-prefix=NOHOIST
+
+# Check that -branch-folder-hoist-common-code=false disables the common-code
+# hoisting sub-phase of BranchFolding. With hoisting enabled (default) the
+# common "ADDXri $x0, 1, 0" is hoisted from both successors into bb.0; with
+# hoisting disabled it must remain duplicated in bb.1 and bb.2.
+
+name: func
+tracksRegLiveness: true
+body: |
+  bb.0:
+    ; HOIST-LABEL: name: func
+    ; HOIST-LABEL: bb.0:
+    ; HOIST: $x0 = ADDXri $x0, 1, 0
+    ; HOIST: CBZX $x1, %bb.2
+    ;
+    ; NOHOIST-LABEL: name: func
+    ; NOHOIST-LABEL: bb.0:
+    ; NOHOIST-NOT: $x0 = ADDXri $x0, 1, 0
+    ; NOHOIST: CBZX $x1, %bb.2
+    liveins: $x0, $x1
+    CBZX $x1, %bb.2
+
+  bb.1:
+    ; HOIST-LABEL: bb.1:
+    ; HOIST-NOT: $x0 = ADDXri $x0, 1, 0
+    ;
+    ; NOHOIST-LABEL: bb.1:
+    ; NOHOIST: $x0 = ADDXri $x0, 1, 0
+    liveins: $x0
+    $x0 = ADDXri $x0, 1, 0
+    $x0 = ADDXri $x0, 2, 0
+    RET_ReallyLR implicit $x0
+
+  bb.2:
+    ; HOIST-LABEL: bb.2:
+    ; HOIST-NOT: $x0 = ADDXri $x0, 1, 0
+    ;
+    ; NOHOIST-LABEL: bb.2:
+    ; NOHOIST: $x0 = ADDXri $x0, 1, 0
+    liveins: $x0
+    $x0 = ADDXri $x0, 1, 0
+    $x0 = ADDXri $x0, 3, 0
+    RET_ReallyLR implicit $x0
+...

diff  --git a/llvm/test/CodeGen/AArch64/branch-folder-reorder-disable.mir b/llvm/test/CodeGen/AArch64/branch-folder-reorder-disable.mir
new file mode 100644
index 0000000000000..d868d642e04aa
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/branch-folder-reorder-disable.mir
@@ -0,0 +1,55 @@
+# RUN: llc -o - %s -mtriple=aarch64 -run-pass branch-folder -verify-machineinstrs | FileCheck %s --check-prefix=REORDER
+# RUN: llc -o - %s -mtriple=aarch64 -run-pass branch-folder -branch-folder-reorder-blocks=false -verify-machineinstrs | FileCheck %s --check-prefix=NOREORDER
+
+# Check that -branch-folder-reorder-blocks=false disables the basic-block
+# reordering sub-phase of branch optimization. bb.1 is a non-fall-through return
+# block sitting between the conditional branch in bb.0 and its taken target bb.2.
+#
+# With reordering enabled (default) BranchFolding reverses the bb.0 condition
+# (CBZX -> CBNZX) so it can fall through, and relocates the blocks. With
+# reordering disabled the original layout (CBZX; bb.1 is the return block) is
+# preserved.
+
+# REORDER-LABEL: name: func
+# REORDER: bb.0:
+# REORDER: CBNZX $x1, %bb.2
+# REORDER: bb.1:
+# REORDER: $x0 = ADDXri $x0, 1, 0
+# REORDER: $x0 = ADDXri $x0, 2, 0
+# REORDER: bb.2:
+# REORDER-NOT: ADDXri
+# REORDER: RET_ReallyLR implicit $x0
+
+# NOREORDER-LABEL: name: func
+# NOREORDER: bb.0:
+# NOREORDER: CBZX $x1, %bb.2
+# NOREORDER: bb.1:
+# NOREORDER: RET_ReallyLR implicit $x0
+# NOREORDER: bb.2:
+# NOREORDER: $x0 = ADDXri $x0, 1, 0
+# NOREORDER: $x0 = ADDXri $x0, 2, 0
+# NOREORDER: RET_ReallyLR implicit $x0
+
+name: func
+tracksRegLiveness: true
+body: |
+  bb.0:
+    successors: %bb.1, %bb.2
+    liveins: $x0, $x1
+    CBZX $x1, %bb.2
+
+  bb.1:
+    liveins: $x0
+    RET_ReallyLR implicit $x0
+
+  bb.2:
+    successors: %bb.3
+    liveins: $x0
+    $x0 = ADDXri $x0, 1, 0
+    B %bb.3
+
+  bb.3:
+    liveins: $x0
+    $x0 = ADDXri $x0, 2, 0
+    RET_ReallyLR implicit $x0
+...


        


More information about the llvm-commits mailing list