[lld] bcc1e58 - [ELF] Allow --symbol-ordering-file and call graph profile to be used together
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 5 17:13:28 PST 2025
Author: Fangrui Song
Date: 2025-01-05T17:13:23-08:00
New Revision: bcc1e584483c8246b651290b0c2d696bd57006a9
URL: https://github.com/llvm/llvm-project/commit/bcc1e584483c8246b651290b0c2d696bd57006a9
DIFF: https://github.com/llvm/llvm-project/commit/bcc1e584483c8246b651290b0c2d696bd57006a9.diff
LOG: [ELF] Allow --symbol-ordering-file and call graph profile to be used together
Port https://reviews.llvm.org/D117354 from the MachO port.
If both --symbol-ordering-file and call graph profile are present, the
--symbol-ordering-file takes precedence, but the call graph profile is
still used for symbols that don't appear in the order file.
In addition, call graph profile described sections are now ordered
before other sections.
Added:
lld/test/ELF/cgprofile-orderfile.s
Modified:
lld/ELF/CallGraphSort.cpp
lld/ELF/Driver.cpp
lld/ELF/Writer.cpp
Removed:
################################################################################
diff --git a/lld/ELF/CallGraphSort.cpp b/lld/ELF/CallGraphSort.cpp
index 0b1b4196de37be..9caba5c316ea10 100644
--- a/lld/ELF/CallGraphSort.cpp
+++ b/lld/ELF/CallGraphSort.cpp
@@ -235,7 +235,7 @@ DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
});
DenseMap<const InputSectionBase *, int> orderMap;
- int curOrder = 1;
+ int curOrder = -clusters.size();
for (int leader : sorted) {
for (int i = leader;;) {
orderMap[sections[i]] = curOrder++;
@@ -328,7 +328,7 @@ computeCacheDirectedSortOrder(Ctx &ctx) {
// Create the final order.
DenseMap<const InputSectionBase *, int> orderMap;
- int curOrder = 1;
+ int curOrder = -sortedSections.size();
for (uint64_t secIdx : sortedSections)
orderMap[sections[secIdx]] = curOrder++;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index e8e99fa874b5d5..13e8f8ce6df207 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1746,13 +1746,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) {
if (args.hasArg(OPT_call_graph_ordering_file))
ErrAlways(ctx) << "--symbol-ordering-file and --call-graph-order-file "
"may not be used together";
- if (std::optional<MemoryBufferRef> buffer =
- readFile(ctx, arg->getValue())) {
+ if (auto buffer = readFile(ctx, arg->getValue()))
ctx.arg.symbolOrderingFile = getSymbolOrderingFile(ctx, *buffer);
- // Also need to disable CallGraphProfileSort to prevent
- // LLD order symbols with CGProfile
- ctx.arg.callGraphProfileSort = CGProfileSortKind::None;
- }
}
assert(ctx.arg.versionDefinitions.empty());
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 0ea2e60d8482ff..fe4a0a15ae835d 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1080,11 +1080,14 @@ static void maybeShuffle(Ctx &ctx,
}
}
-// Builds section order for handling --symbol-ordering-file.
+// Return section order within an InputSectionDescription.
+// If both --symbol-ordering-file and call graph profile are present, the order
+// file takes precedence, but the call graph profile is still used for symbols
+// that don't appear in the order file.
static DenseMap<const InputSectionBase *, int> buildSectionOrder(Ctx &ctx) {
DenseMap<const InputSectionBase *, int> sectionOrder;
if (!ctx.arg.callGraphProfile.empty())
- return computeCallGraphProfileOrder(ctx);
+ sectionOrder = computeCallGraphProfileOrder(ctx);
if (ctx.arg.symbolOrderingFile.empty())
return sectionOrder;
@@ -1098,7 +1101,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder(Ctx &ctx) {
// appear in the symbol ordering file have the lowest priority 0.
// All explicitly mentioned symbols have negative (higher) priorities.
DenseMap<CachedHashStringRef, SymbolOrderEntry> symbolOrder;
- int priority = -ctx.arg.symbolOrderingFile.size();
+ int priority = -sectionOrder.size() - ctx.arg.symbolOrderingFile.size();
for (StringRef s : ctx.arg.symbolOrderingFile)
symbolOrder.insert({CachedHashStringRef(s), {priority++, false}});
@@ -1254,11 +1257,11 @@ static void sortSection(Ctx &ctx, OutputSection &osec,
}
}
-// If no layout was provided by linker script, we want to apply default
-// sorting for special input sections. This also handles --symbol-ordering-file.
+// Sort sections within each InputSectionDescription.
template <class ELFT> void Writer<ELFT>::sortInputSections() {
- // Build the order once since it is expensive.
+ // Assign negative priorities.
DenseMap<const InputSectionBase *, int> order = buildSectionOrder(ctx);
+ // Assign non-negative priorities due to --shuffle-sections.
maybeShuffle(ctx, order);
for (SectionCommand *cmd : ctx.script->sectionCommands)
if (auto *osd = dyn_cast<OutputDesc>(cmd))
diff --git a/lld/test/ELF/cgprofile-orderfile.s b/lld/test/ELF/cgprofile-orderfile.s
new file mode 100644
index 00000000000000..584b2ecbe293af
--- /dev/null
+++ b/lld/test/ELF/cgprofile-orderfile.s
@@ -0,0 +1,41 @@
+# REQUIRES: x86
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o
+
+# RUN: ld.lld -e A a.o --symbol-ordering-file=order --call-graph-profile-sort=hfsort -o out
+# RUN: llvm-nm --numeric-sort out | FileCheck %s
+# RUN: ld.lld -e A a.o --call-graph-profile-sort=hfsort -o out1
+# RUN: llvm-nm --numeric-sort out1 | FileCheck %s --check-prefix=ONLY-CG
+
+#--- order
+B
+A
+
+#--- a.s
+.section .text.D,"ax"; .globl D; D:
+ retq
+
+.section .text.C,"ax"; .globl C; C:
+ call D
+
+.section .text.B,"ax"; .globl B; B:
+ retq
+
+.section .text.A,"ax"; .globl A; A:
+ call B
+ call C
+
+.cg_profile A, B, 100
+.cg_profile A, C, 40
+.cg_profile C, D, 61
+
+# CHECK: T B
+# CHECK-NEXT: T A
+# CHECK-NEXT: T C
+# CHECK-NEXT: T D
+
+# ONLY-CG: T A
+# ONLY-CG-NEXT: T B
+# ONLY-CG-NEXT: T C
+# ONLY-CG-NEXT: T D
More information about the llvm-commits
mailing list