[lld] [lld-macho] Include ICF safe thunks in balanced partitioning (PR #212096)

Karim Alweheshy via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 26 00:34:11 PDT 2026


https://github.com/karim-alweheshy updated https://github.com/llvm/llvm-project/pull/212096

>From 693f3f76939e1ce6456fca650f285043b4e20614 Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at gmail.com>
Date: Sun, 26 Jul 2026 09:29:46 +0200
Subject: [PATCH 1/2] [lld-macho] Include ICF safe thunks in balanced
 partitioning

---
 lld/MachO/BPSectionOrderer.cpp                | 55 +++++++++-------
 .../MachO/bp-section-orderer-safe-thunks.s    | 62 +++++++++++++++++++
 2 files changed, 94 insertions(+), 23 deletions(-)
 create mode 100644 lld/test/MachO/bp-section-orderer-safe-thunks.s

diff --git a/lld/MachO/BPSectionOrderer.cpp b/lld/MachO/BPSectionOrderer.cpp
index edc92d40f2a96..4289045b1ff05 100644
--- a/lld/MachO/BPSectionOrderer.cpp
+++ b/lld/MachO/BPSectionOrderer.cpp
@@ -13,6 +13,7 @@
 #include "Symbols.h"
 #include "lld/Common/BPSectionOrdererBase.inc"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StableHashing.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/xxhash.h"
@@ -120,36 +121,44 @@ DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(
   // Collect candidate sections and associated symbols.
   SmallVector<InputSection *> sections;
   DenseMap<CachedHashStringRef, std::set<unsigned>> rootSymbolToSectionIdxs;
+  DenseSet<InputSection *> seenSections;
+  auto addSection = [&](InputSection *isec) {
+    if (!isec || isec->data.empty() || !isec->data.data())
+      return;
+    // CString section order is handled by
+    // {Deduplicated}CStringSection::finalizeContents()
+    if (isa<CStringInputSection>(isec) || isec->isFinal)
+      return;
+    // ConcatInputSections are entirely live or dead, so the offset is
+    // irrelevant.
+    if (isa<ConcatInputSection>(isec) && !isec->isLive(0))
+      return;
+    if (!seenSections.insert(isec).second)
+      return;
+    size_t idx = sections.size();
+    sections.emplace_back(isec);
+    for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {
+      auto rootName = lld::utils::getRootSymbol(sym->getName());
+      rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);
+      if (auto linkageName =
+              BPOrdererMachO::getResolvedLinkageName(rootName))
+        rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(idx);
+    }
+  };
   for (const auto *file : inputFiles) {
     for (auto *sec : file->sections) {
       if (sec->name == section_names::ehFrame &&
           sec->segname == segment_names::text)
         continue;
-      for (auto &subsec : sec->subsections) {
-        auto *isec = subsec.isec;
-        if (!isec || isec->data.empty() || !isec->data.data())
-          continue;
-        // CString section order is handled by
-        // {Deduplicated}CStringSection::finalizeContents()
-        if (isa<CStringInputSection>(isec) || isec->isFinal)
-          continue;
-        // ConcatInputSections are entirely live or dead, so the offset is
-        // irrelevant.
-        if (isa<ConcatInputSection>(isec) && !isec->isLive(0))
-          continue;
-        size_t idx = sections.size();
-        sections.emplace_back(isec);
-        for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {
-          auto rootName = lld::utils::getRootSymbol(sym->getName());
-          rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);
-          if (auto linkageName =
-                  BPOrdererMachO::getResolvedLinkageName(rootName))
-            rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(
-                idx);
-        }
-      }
+      for (auto &subsec : sec->subsections)
+        addSection(subsec.isec);
     }
   }
+  // ICF safe thunks are linker-created after the input-file section graph is
+  // built. Include them (and any other synthetic concat sections) so temporal
+  // profile names resolve to the sections that are actually emitted.
+  for (auto *isec : inputSections)
+    addSection(isec);
 
   auto result = BPOrdererMachO().computeOrder(
       profilePath, compressionSortSpecs, forFunctionCompression,
diff --git a/lld/test/MachO/bp-section-orderer-safe-thunks.s b/lld/test/MachO/bp-section-orderer-safe-thunks.s
new file mode 100644
index 0000000000000..70c279c23a8a4
--- /dev/null
+++ b/lld/test/MachO/bp-section-orderer-safe-thunks.s
@@ -0,0 +1,62 @@
+# REQUIRES: aarch64
+
+# RUN: rm -rf %t && split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=arm64-apple-darwin %t/input.s -o %t/input.o
+# RUN: llvm-profdata merge %t/profile.proftext -o %t/profile.profdata
+
+## The temporal profile names _hot_b, whose input section becomes a
+## linker-created ICF thunk. Balanced partitioning must order that thunk.
+# RUN: %lld -arch arm64 -lSystem -e _main -o %t/out %t/input.o --icf=safe_thunks --irpgo-profile=%t/profile.profdata --bp-startup-sort=function --bp-compression-sort=none --verbose-bp-section-orderer 2>&1 | FileCheck %s --check-prefix=VERBOSE
+# VERBOSE: Ordered 1 sections (4 bytes) using balanced partitioning
+# VERBOSE: Functions for startup: 1 (4 bytes)
+
+# RUN: %lld -arch arm64 -lSystem -e _main -o - %t/input.o --icf=safe_thunks --irpgo-profile=%t/profile.profdata --bp-startup-sort=function --bp-compression-sort=none | llvm-nm --numeric-sort --format=just-symbols - | FileCheck %s --check-prefix=ORDER
+# ORDER: _hot_b
+# ORDER-NEXT: _main
+# ORDER-NEXT: _hot_a
+# ORDER-NEXT: _cold
+
+#--- input.s
+.subsections_via_symbols
+
+.addrsig
+.addrsig_sym _hot_a
+.addrsig_sym _hot_b
+
+.text
+.globl _main
+_main:
+  ret
+
+.globl _hot_a
+_hot_a:
+  mov w0, #42
+  ret
+
+.globl _hot_b
+_hot_b:
+  mov w0, #42
+  ret
+
+.globl _cold
+_cold:
+  mov w0, #1
+  ret
+
+#--- profile.proftext
+:ir
+:temporal_prof_traces
+# Num Traces
+1
+# Trace Stream Size:
+1
+# Weight
+1
+hot_b
+
+hot_b
+# Func Hash:
+1111
+# Num Counters:
+1
+# Counter Values:

>From fcbe33bd5ff149d2d0c5c72abe112a37fa6a5885 Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at gmail.com>
Date: Sun, 26 Jul 2026 09:34:02 +0200
Subject: [PATCH 2/2] Apply clang-format

---
 lld/MachO/BPSectionOrderer.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lld/MachO/BPSectionOrderer.cpp b/lld/MachO/BPSectionOrderer.cpp
index 4289045b1ff05..1b86ca7f16755 100644
--- a/lld/MachO/BPSectionOrderer.cpp
+++ b/lld/MachO/BPSectionOrderer.cpp
@@ -140,8 +140,7 @@ DenseMap<const InputSection *, int> lld::macho::runBalancedPartitioning(
     for (auto *sym : BPOrdererMachO::getSymbols(*isec)) {
       auto rootName = lld::utils::getRootSymbol(sym->getName());
       rootSymbolToSectionIdxs[CachedHashStringRef(rootName)].insert(idx);
-      if (auto linkageName =
-              BPOrdererMachO::getResolvedLinkageName(rootName))
+      if (auto linkageName = BPOrdererMachO::getResolvedLinkageName(rootName))
         rootSymbolToSectionIdxs[CachedHashStringRef(*linkageName)].insert(idx);
     }
   };



More information about the llvm-commits mailing list