[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