[llvm] [CodeGen] Add an option to sink unsplittable blocks to the end in BB sections (PR #228173)

Rahman Lavaee via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 1 10:57:11 PDT 2026


https://github.com/rlavaee created https://github.com/llvm/llvm-project/pull/228173

With a basic block sections profile, a block which is not in the profile but is not safe to split (TargetInstrInfo::isMBBSafeToSplitToCold) stays in the default section, which is cluster 0's section. The comparator uses FuncClusterInfo.lookup(), which returns PositionInCluster 0 for such blocks, so they are placed right after the entry block, in the middle of the hot cluster.

Add -bbsections-sink-unsplittable-blocks-to-end, which uses find() in the comparator instead, so that blocks without cluster information are placed after all the blocks of the cluster, in their original order. The option is off by default so that the two layouts can be compared before changing the default; with it off, the layout is unchanged.

>From ac1cf0f1abd1f190518123125e8e8667746c0c74 Mon Sep 17 00:00:00 2001
From: Rahman Lavaee <rahmanl at google.com>
Date: Wed, 30 Sep 2026 23:48:57 +0000
Subject: [PATCH] [CodeGen] Add an option to sink unsplittable blocks to the
 end in BB sections

With a basic block sections profile, a block which is not in the profile but
is not safe to split (TargetInstrInfo::isMBBSafeToSplitToCold) stays in the
default section, which is cluster 0's section. The comparator uses
FuncClusterInfo.lookup(), which returns PositionInCluster 0 for such blocks,
so they are placed right after the entry block, in the middle of the hot
cluster.

Add -bbsections-sink-unsplittable-blocks-to-end, which uses find() in the
comparator instead, so that blocks without cluster information are placed
after all the blocks of the cluster, in their original order. The option is
off by default so that the two layouts can be compared before changing the
default; with it off, the layout is unchanged.
---
 llvm/lib/CodeGen/BasicBlockSections.cpp       | 38 ++++++++++++++++---
 .../AArch64/basic-block-sections-unsafe.ll    | 35 +++++++++++++----
 2 files changed, 61 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp
index 9972d431aae8b..c68aa46361f8b 100644
--- a/llvm/lib/CodeGen/BasicBlockSections.cpp
+++ b/llvm/lib/CodeGen/BasicBlockSections.cpp
@@ -96,6 +96,17 @@ cl::opt<std::string> llvm::BBSectionsColdTextPrefix(
     cl::desc("The text prefix to use for cold basic block clusters"),
     cl::init(".text.split."), cl::Hidden);
 
+// Basic blocks which are not in the profile but are not safe to split stay in
+// the default section. By default, they are ordered as if they were the first
+// block of the cluster, i.e., right after the entry block. With this flag, they
+// are placed after all the profiled blocks of the section.
+static cl::opt<bool> BBSectionsSinkUnsplittableBlocksToEnd(
+    "bbsections-sink-unsplittable-blocks-to-end",
+    cl::desc("Place basic blocks which are not in the basic block sections "
+             "profile but are not safe to split after all the profiled basic "
+             "blocks of their section"),
+    cl::init(false), cl::Hidden);
+
 static cl::opt<bool> BBSectionsDetectSourceDrift(
     "bbsections-detect-source-drift",
     cl::desc("This checks if there is a fdo instr. profile hash "
@@ -286,6 +297,10 @@ assignSections(MachineFunction &MF,
           // BB goes into the special cold section if it is not specified in the
           // cluster info map.
           MBB.setSectionID(MBBSectionID::ColdSectionID);
+        } else if (BBSectionsSinkUnsplittableBlocksToEnd) {
+          // Otherwise, it stays in the default section, after all the profiled
+          // basic blocks of that section.
+          MBB.setSectionID(MBBSectionID(0));
         }
       }
     }
@@ -441,11 +456,24 @@ bool BasicBlockSections::handleBBSections(MachineFunction &MF) {
     // Make sure that the entry block is placed at the beginning.
     if (&X == &EntryBB || &Y == &EntryBB)
       return &X == &EntryBB;
-    // If the two basic block are in the same section, the order is decided by
-    // their position within the section.
-    if (XSectionID.Type == MBBSectionID::SectionType::Default)
-      return FuncClusterInfo.lookup(*X.getBBID()).PositionInCluster <
-             FuncClusterInfo.lookup(*Y.getBBID()).PositionInCluster;
+    // If the two basic blocks are in the same section, the order is decided by
+    // their position within the section. Basic blocks which are not in any
+    // cluster (those which are not safe to split) are treated as being at
+    // position 0, unless -bbsections-sink-unsplittable-blocks-to-end is given,
+    // in which case they come last, in their original order.
+    if (XSectionID.Type == MBBSectionID::SectionType::Default) {
+      if (!BBSectionsSinkUnsplittableBlocksToEnd)
+        return FuncClusterInfo.lookup(*X.getBBID()).PositionInCluster <
+               FuncClusterInfo.lookup(*Y.getBBID()).PositionInCluster;
+      auto XI = FuncClusterInfo.find(*X.getBBID());
+      auto YI = FuncClusterInfo.find(*Y.getBBID());
+      bool XInCluster = XI != FuncClusterInfo.end();
+      bool YInCluster = YI != FuncClusterInfo.end();
+      if (XInCluster != YInCluster)
+        return XInCluster;
+      if (XInCluster)
+        return XI->second.PositionInCluster < YI->second.PositionInCluster;
+    }
     return X.getNumber() < Y.getNumber();
   };
 
diff --git a/llvm/test/CodeGen/AArch64/basic-block-sections-unsafe.ll b/llvm/test/CodeGen/AArch64/basic-block-sections-unsafe.ll
index a83a47c9c129c..a4ca28a100986 100644
--- a/llvm/test/CodeGen/AArch64/basic-block-sections-unsafe.ll
+++ b/llvm/test/CodeGen/AArch64/basic-block-sections-unsafe.ll
@@ -4,25 +4,46 @@
 ;; Profile for version 0.
 ; RUN: echo 'v1' > %t1
 ; RUN: echo 'f _Z3asm_goto' >> %t1
-; RUN: echo 'c 0' >> %t1
+; RUN: echo 'c 0 3' >> %t1
 ; RUN: echo 'f _Z3jump_table' >> %t1
 ; RUN: echo 'c 0' >> %t1
 ; RUN: echo 'f _Z3red_zone' >> %t1
 ; RUN: echo 'c 0' >> %t1
 ;;
 ; RUN: llc < %s -mtriple=aarch64 -function-sections -basic-block-sections=%t1 -unique-basic-block-section-names -bbsections-cold-text-prefix=".text.unlikely." | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64 -function-sections -basic-block-sections=%t1 -unique-basic-block-section-names -bbsections-cold-text-prefix=".text.unlikely." -bbsections-sink-unsplittable-blocks-to-end | FileCheck %s -check-prefix=SINK
 ; RUN: llc < %s -mtriple=aarch64 -function-sections -aarch64-min-jump-table-entries=4 -basic-block-sections=%t1 -unique-basic-block-section-names -bbsections-cold-text-prefix=".text.unlikely." | FileCheck %s -check-prefix=JUMP-TABLES
 ; RUN: llc < %s -mtriple=aarch64 -function-sections -basic-block-sections=%t1 -unique-basic-block-section-names -bbsections-cold-text-prefix=".text.unlikely." | FileCheck %s -check-prefix=RED-ZONE
 
 define void @_Z3asm_goto(i1 zeroext %0, i1 zeroext %1) nounwind {
-  ;; Check that blocks containing or targeted by asm goto aren't split.
-  ; CHECK-LABEL:  _Z3asm_goto
+  ;; Check that blocks containing or targeted by asm goto aren't split. By
+  ;; default, they are placed right after the entry block.
+  ; CHECK-LABEL:  _Z3asm_goto:
+  ; CHECK-NOT:    .section
+  ; CHECK:          bl bar
+  ; CHECK:          nop
+  ; CHECK:        // Inline asm indirect target
+  ; CHECK:          bl bar
+  ; CHECK:          bl bam
   ; CHECK:        .section	.text.unlikely._Z3asm_goto,"ax", at progbits
   ; CHECK-NEXT:     _Z3asm_goto.cold:
-  ; CHECK-NEXT:       bl bam
-  ; CHECK:          .LBB0_4:
-  ; CHECK:            ret
-  ; CHECK:          .LBB_END0_4:
+  ; CHECK-NEXT:       ldp
+  ; CHECK-NEXT:       ret
+
+  ;; With -bbsections-sink-unsplittable-blocks-to-end, they are placed after
+  ;; all the blocks of the hot cluster.
+  ; SINK-LABEL:  _Z3asm_goto:
+  ; SINK-NOT:    .section
+  ; SINK:          bl bam
+  ; SINK-NOT:    .section
+  ; SINK:          bl bar
+  ; SINK:          nop
+  ; SINK:        // Inline asm indirect target
+  ; SINK:          bl bar
+  ; SINK:        .section	.text.unlikely._Z3asm_goto,"ax", at progbits
+  ; SINK-NEXT:     _Z3asm_goto.cold:
+  ; SINK-NEXT:       ldp
+  ; SINK-NEXT:       ret
 
   br i1 %0, label %3, label %5
 



More information about the llvm-commits mailing list