[lld] [llvm] [LTO] Move section names from symbol table to module summary. (PR #210856)
Eli Friedman via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 22 12:57:08 PDT 2026
https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/210856
>From 9a1b9b1e93eea27134a481ed7f4c4a849bf48b17 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Tue, 7 Jul 2026 18:31:35 -0700
Subject: [PATCH 1/2] [LTO] Move section names from symbol table to module
summary.
Section names don't logically belong in the symbol table; they're a
property of the data, not the symbol itself. Move the section name
information from the symbol table into the ThinLTO summary.
As discussed on
https://discourse.llvm.org/t/rfc-lto-lld-lto-with-linker-scripts-implemented/91089
. Splitting this part off to make it easier to review; it basically
stands on its own.
The OutputSectionName is currently unused, but will be used as part of
the full implementation of LTO with linker scripts.
---
lld/ELF/LTO.cpp | 10 ++-
lld/test/ELF/lto/section-name.ll | 5 ++
llvm/include/llvm/AsmParser/LLParser.h | 10 +--
llvm/include/llvm/AsmParser/LLToken.h | 5 ++
llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 +
llvm/include/llvm/IR/ModuleSummaryIndex.h | 18 +++++
llvm/include/llvm/LTO/LTO.h | 40 +++++++----
llvm/include/llvm/Object/IRSymtab.h | 13 +---
llvm/lib/Analysis/ModuleSummaryAnalysis.cpp | 9 +++
llvm/lib/AsmParser/LLLexer.cpp | 4 ++
llvm/lib/AsmParser/LLParser.cpp | 77 +++++++++++++++++++--
llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 15 ++++
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 22 ++++++
llvm/lib/IR/AsmWriter.cpp | 6 ++
llvm/lib/LTO/LTO.cpp | 64 +++++++++++++++--
llvm/lib/Object/IRSymtab.cpp | 4 --
llvm/test/Assembler/thinlto-sectioninfo.ll | 24 +++++++
llvm/tools/gold/gold-plugin.cpp | 18 ++---
llvm/tools/llvm-lto2/llvm-lto2.cpp | 3 -
19 files changed, 286 insertions(+), 62 deletions(-)
create mode 100644 llvm/test/Assembler/thinlto-sectioninfo.ll
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index e40575bffec62..791410785a810 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -265,8 +265,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// 5) Symbols that will be referenced after linker wrapping is performed.
r.VisibleToRegularObj = ctx.arg.relocatable || sym->isUsedInRegularObj ||
sym->referencedAfterWrap ||
- (r.Prevailing && sym->isExported) ||
- usedStartStop.contains(objSym.getSectionName());
+ (r.Prevailing && sym->isExported);
// Identify symbols exported dynamically, and that therefore could be
// referenced by a shared library not visible to the linker.
r.ExportDynamic = sym->computeBinding(ctx) != STB_LOCAL &&
@@ -292,7 +291,12 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// their values are still not final.
r.LinkerRedefined = sym->scriptDefined;
}
- checkError(ctx.e, ltoObj->add(std::move(f.obj), resols));
+ auto resolver = [this](StringRef sectionName) {
+ lto::SectionResolution r;
+ r.Keep = usedStartStop.contains(sectionName);
+ return r;
+ };
+ checkError(ctx.e, ltoObj->add(std::move(f.obj), resols, std::move(resolver)));
}
// If LazyObjFile has not been added to link, emit empty index files.
diff --git a/lld/test/ELF/lto/section-name.ll b/lld/test/ELF/lto/section-name.ll
index a91537d5004b7..6149f8c9b2d0f 100644
--- a/lld/test/ELF/lto/section-name.ll
+++ b/lld/test/ELF/lto/section-name.ll
@@ -4,6 +4,11 @@
; RUN: llvm-readelf -S %t.so | FileCheck %s
; RUN: ld.lld %t.o -o %t.so -shared --gc-sections -z nostart-stop-gc
; RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=GC %s
+; RUN: opt -module-summary %s -o %t.o
+; RUN: ld.lld %t.o -o %t.so -shared
+; RUN: llvm-readelf -S %t.so | FileCheck %s
+; RUN: ld.lld %t.o -o %t.so -shared --gc-sections -z nostart-stop-gc
+; RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=GC %s
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index 788b56cb78f08..23e4c4eb30171 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -426,9 +426,11 @@ namespace llvm {
bool parseSummaryIndexFlags();
bool parseBlockCount();
bool parseGVEntry(unsigned ID);
- bool parseFunctionSummary(std::string Name, GlobalValue::GUID, unsigned ID);
- bool parseVariableSummary(std::string Name, GlobalValue::GUID, unsigned ID);
- bool parseAliasSummary(std::string Name, GlobalValue::GUID, unsigned ID);
+ bool parseFunctionSummary(std::string Name, GlobalValue::GUID &,
+ unsigned ID);
+ bool parseVariableSummary(std::string Name, GlobalValue::GUID &,
+ unsigned ID);
+ bool parseAliasSummary(std::string Name, GlobalValue::GUID &, unsigned ID);
bool parseGVFlags(GlobalValueSummary::GVFlags &GVFlags);
bool parseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags);
bool parseOptionalFFlags(FunctionSummary::FFlags &FFlags);
@@ -469,7 +471,7 @@ namespace llvm {
std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>
&ResByArg);
bool parseArgs(std::vector<uint64_t> &Args);
- bool addGlobalValueToIndex(std::string Name, GlobalValue::GUID,
+ bool addGlobalValueToIndex(std::string Name, GlobalValue::GUID &,
GlobalValue::LinkageTypes Linkage, unsigned ID,
std::unique_ptr<GlobalValueSummary> Summary,
LocTy Loc);
diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h
index d2766a05ce9ba..0a2a13c633287 100644
--- a/llvm/include/llvm/AsmParser/LLToken.h
+++ b/llvm/include/llvm/AsmParser/LLToken.h
@@ -482,6 +482,11 @@ enum Kind {
kw_versions,
kw_memProf,
kw_notcold,
+ // sectionInfo keywords.
+ kw_sectionInfo,
+ kw_sectionName,
+ kw_outputSectionName,
+ kw_keep,
// GV's with __attribute__((no_sanitize("address"))), or things in
// -fsanitize-ignorelist when built with ASan.
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 358f9a65a80af..c18c1582028fc 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -348,6 +348,7 @@ enum GlobalValueSummarySymtabCodes {
// nummib x alloc type,
// numver x version]
FS_COMBINED_ALLOC_INFO_NO_CONTEXT = 33,
+ FS_SECTION_INFO = 34,
};
enum MetadataCodes {
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h
index f4c5e9b40796b..2c21b47a14988 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndex.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h
@@ -17,6 +17,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -1597,6 +1598,16 @@ class ModuleSummaryIndex {
CfiFunctionIndex CfiFunctionDefs;
CfiFunctionIndex CfiFunctionDecls;
+public:
+ struct SectionInfo {
+ StringRef SectionName;
+ StringRef OutputSectionName;
+ bool Keep = false;
+ };
+
+private:
+ MapVector<GlobalValue::GUID, SectionInfo> SectionInfos;
+
// Used in cases where we want to record the name of a global, but
// don't have the string owned elsewhere (e.g. the Strtab on a module).
BumpPtrAllocator Alloc;
@@ -1695,6 +1706,13 @@ class ModuleSummaryIndex {
StackIds.shrink_to_fit();
}
+ const MapVector<GlobalValue::GUID, SectionInfo> §ionInfos() const {
+ return SectionInfos;
+ }
+ MapVector<GlobalValue::GUID, SectionInfo> §ionInfos() {
+ return SectionInfos;
+ }
+
/// Convenience function for doing a DFS on a ValueInfo. Marks the function in
/// the FunctionHasParent map.
static void discoverNodes(ValueInfo V,
diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index 32aa671183890..828b0e1cc972b 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -22,6 +22,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/LTO/Config.h"
@@ -110,6 +111,13 @@ LLVM_ABI std::vector<int> generateModulesOrdering(ArrayRef<BitcodeModule *> R);
class LTO;
struct SymbolResolution;
+struct SectionResolution {
+ bool Keep = false;
+};
+
+using SectionResolverFn =
+ llvm::function_ref<SectionResolution(StringRef SectionName)>;
+
/// An input file. This is a symbol table wrapper that only exposes the
/// information that an LTO client should need in order to do symbol resolution.
class InputFile {
@@ -159,22 +167,21 @@ class InputFile {
public:
Symbol(const irsymtab::Symbol &S) : irsymtab::Symbol(S) {}
- using irsymtab::Symbol::isUndefined;
- using irsymtab::Symbol::isCommon;
- using irsymtab::Symbol::isWeak;
- using irsymtab::Symbol::isIndirect;
- using irsymtab::Symbol::getName;
- using irsymtab::Symbol::getIRName;
- using irsymtab::Symbol::getVisibility;
using irsymtab::Symbol::canBeOmittedFromSymbolTable;
- using irsymtab::Symbol::isTLS;
+ using irsymtab::Symbol::getCOFFWeakExternalFallback;
using irsymtab::Symbol::getComdatIndex;
- using irsymtab::Symbol::getCommonSize;
using irsymtab::Symbol::getCommonAlignment;
- using irsymtab::Symbol::getCOFFWeakExternalFallback;
- using irsymtab::Symbol::getSectionName;
+ using irsymtab::Symbol::getCommonSize;
+ using irsymtab::Symbol::getIRName;
+ using irsymtab::Symbol::getName;
+ using irsymtab::Symbol::getVisibility;
+ using irsymtab::Symbol::isCommon;
using irsymtab::Symbol::isExecutable;
+ using irsymtab::Symbol::isIndirect;
+ using irsymtab::Symbol::isTLS;
+ using irsymtab::Symbol::isUndefined;
using irsymtab::Symbol::isUsed;
+ using irsymtab::Symbol::isWeak;
// Returns whether this symbol is a library call that LTO code generation
// may emit references to. Such symbols must be considered external, as
@@ -417,7 +424,8 @@ class LLVM_ABI LTO {
/// Add an input file to the LTO link, using the provided symbol resolutions.
/// The symbol resolutions must appear in the enumeration order given by
/// InputFile::symbols().
- Error add(std::unique_ptr<InputFile> Obj, ArrayRef<SymbolResolution> Res);
+ Error add(std::unique_ptr<InputFile> Obj, ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver = {});
/// Set the list of functions implemented in bitcode that were not extracted
/// from an archive. Such functions may not be referenced, as they have
@@ -613,18 +621,20 @@ class LLVM_ABI LTO {
// to the resolutions for the remaining modules in the InputFile.
Expected<ArrayRef<SymbolResolution>>
addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
- unsigned ModI, ArrayRef<SymbolResolution> Res);
+ unsigned ModI, ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver);
Expected<std::pair<RegularLTOState::AddedModule, ArrayRef<SymbolResolution>>>
addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
- ArrayRef<SymbolResolution> Res);
+ ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver);
Error linkRegularLTO(RegularLTOState::AddedModule Mod,
bool LivenessFromIndex);
Expected<ArrayRef<SymbolResolution>>
addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
- ArrayRef<SymbolResolution> Res);
+ ArrayRef<SymbolResolution> Res, SectionResolverFn SectionResolver);
Error runRegularLTO(AddStreamFn AddStream);
Error runThinLTO(AddStreamFn AddStream, FileCache Cache,
diff --git a/llvm/include/llvm/Object/IRSymtab.h b/llvm/include/llvm/Object/IRSymtab.h
index f59ad293d61ae..5f3080d2a54f2 100644
--- a/llvm/include/llvm/Object/IRSymtab.h
+++ b/llvm/include/llvm/Object/IRSymtab.h
@@ -127,9 +127,6 @@ struct Uncommon {
/// COFF-specific: the name of the symbol that a weak external resolves to
/// if not defined.
Str COFFWeakExternFallbackName;
-
- /// Specified section name, if any.
- Str SectionName;
};
@@ -138,7 +135,7 @@ struct Header {
/// when the format changes, but it does not need to be incremented if a
/// change to LLVM would cause it to create a different symbol table.
Word Version;
- enum { kCurrentVersion = 4 };
+ enum { kCurrentVersion = 5 };
/// The producer's version string (LLVM_VERSION_STRING " " LLVM_REVISION).
/// Consumers should rebuild the symbol table from IR if the producer's
@@ -181,7 +178,6 @@ struct Symbol {
uint64_t CommonSize;
uint32_t CommonAlign;
StringRef COFFWeakExternFallbackName;
- StringRef SectionName;
/// Returns the mangled symbol name.
StringRef getName() const { return Name; }
@@ -232,8 +228,6 @@ struct Symbol {
assert(isWeak() && isIndirect());
return COFFWeakExternFallbackName;
}
-
- StringRef getSectionName() const { return SectionName; }
};
/// This class can be used to read a Symtab and Strtab produced by
@@ -333,10 +327,7 @@ class Reader::SymbolRef : public Symbol {
CommonSize = UncI->CommonSize;
CommonAlign = UncI->CommonAlign;
COFFWeakExternFallbackName = R->str(UncI->COFFWeakExternFallbackName);
- SectionName = R->str(UncI->SectionName);
- } else
- // Reset this field so it can be queried unconditionally for all symbols.
- SectionName = "";
+ }
}
public:
diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
index 33caa268b1c6e..0626770681e65 100644
--- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
+++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
@@ -1171,6 +1171,15 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
Index.exportToDot(OSDot, {});
}
+ for (const GlobalObject &GO : M.global_objects()) {
+ if (GO.isDeclaration() || GO.getName().starts_with("llvm."))
+ continue;
+ if (GO.hasSection()) {
+ auto &Entry = Index.sectionInfos()[GO.getGUID()];
+ Entry.SectionName = Index.saveString(GO.getSection());
+ }
+ }
+
return Index;
}
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index 069a180056488..e50e91e09310a 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -900,6 +900,10 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(versions);
KEYWORD(memProf);
KEYWORD(notcold);
+ KEYWORD(sectionInfo);
+ KEYWORD(sectionName);
+ KEYWORD(outputSectionName);
+ KEYWORD(keep);
#undef KEYWORD
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index c58b109b5ff9b..9ded64007ef58 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -10001,8 +10001,9 @@ static void resolveFwdRef(ValueInfo *Fwd, ValueInfo &Resolved) {
/// Stores the given Name/GUID and associated summary into the Index.
/// Also updates any forward references to the associated entry ID.
bool LLParser::addGlobalValueToIndex(
- std::string Name, GlobalValue::GUID GUID, GlobalValue::LinkageTypes Linkage,
- unsigned ID, std::unique_ptr<GlobalValueSummary> Summary, LocTy Loc) {
+ std::string Name, GlobalValue::GUID &GUID,
+ GlobalValue::LinkageTypes Linkage, unsigned ID,
+ std::unique_ptr<GlobalValueSummary> Summary, LocTy Loc) {
// First create the ValueInfo utilizing the Name or GUID.
ValueInfo VI;
if (GUID != 0) {
@@ -10172,8 +10173,70 @@ bool LLParser::parseGVEntry(unsigned ID) {
}
} while (EatIfPresent(lltok::comma));
- if (parseToken(lltok::rparen, "expected ')' here") ||
- parseToken(lltok::rparen, "expected ')' here"))
+ if (parseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ if (EatIfPresent(lltok::comma)) {
+ if (parseToken(lltok::kw_sectionInfo, "expected 'sectioninfo' here") ||
+ parseToken(lltok::colon, "expected ':' here") ||
+ parseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ ModuleSummaryIndex::SectionInfo Info;
+ do {
+ switch (Lex.getKind()) {
+ case lltok::kw_sectionName: {
+ Lex.Lex();
+ if (parseToken(lltok::colon, "expected ':' here"))
+ return true;
+ std::string SectionName;
+ if (parseStringConstant(SectionName))
+ return true;
+ Info.SectionName = Index->saveString(SectionName);
+ break;
+ }
+ case lltok::kw_outputSectionName: {
+ Lex.Lex();
+ if (parseToken(lltok::colon, "expected ':' here"))
+ return true;
+ std::string OutputSectionName;
+ if (parseStringConstant(OutputSectionName))
+ return true;
+ Info.OutputSectionName = Index->saveString(OutputSectionName);
+ break;
+ }
+ case lltok::kw_keep: {
+ Lex.Lex();
+ if (parseToken(lltok::colon, "expected ':' here"))
+ return true;
+ switch (Lex.getKind()) {
+ case lltok::kw_true:
+ Lex.Lex();
+ Info.Keep = true;
+ break;
+ case lltok::kw_false:
+ Lex.Lex();
+ Info.Keep = false;
+ break;
+ default:
+ return error(Lex.getLoc(), "expected 'true' or 'false'");
+ }
+ break;
+ }
+ default:
+ return error(Lex.getLoc(), "expected sectionInfo field");
+ }
+ } while (EatIfPresent(lltok::comma));
+
+ if (parseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ if (!GUID)
+ return error(Lex.getLoc(), "missing GUID parsing sectionInfo");
+ Index->sectionInfos().insert_or_assign(GUID, Info);
+ }
+
+ if (parseToken(lltok::rparen, "expected ')' here"))
return true;
return false;
@@ -10184,7 +10247,7 @@ bool LLParser::parseGVEntry(unsigned ID) {
/// ',' 'insts' ':' UInt32 [',' OptionalFFlags]? [',' OptionalCalls]?
/// [',' OptionalTypeIdInfo]? [',' OptionalParamAccesses]?
/// [',' OptionalRefs]? ')'
-bool LLParser::parseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
+bool LLParser::parseFunctionSummary(std::string Name, GlobalValue::GUID &GUID,
unsigned ID) {
LocTy Loc = Lex.getLoc();
assert(Lex.getKind() == lltok::kw_function);
@@ -10272,7 +10335,7 @@ bool LLParser::parseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
/// VariableSummary
/// ::= 'variable' ':' '(' 'module' ':' ModuleReference ',' GVFlags
/// [',' OptionalRefs]? ')'
-bool LLParser::parseVariableSummary(std::string Name, GlobalValue::GUID GUID,
+bool LLParser::parseVariableSummary(std::string Name, GlobalValue::GUID &GUID,
unsigned ID) {
LocTy Loc = Lex.getLoc();
assert(Lex.getKind() == lltok::kw_variable);
@@ -10331,7 +10394,7 @@ bool LLParser::parseVariableSummary(std::string Name, GlobalValue::GUID GUID,
/// AliasSummary
/// ::= 'alias' ':' '(' 'module' ':' ModuleReference ',' GVFlags ','
/// 'aliasee' ':' GVReference ')'
-bool LLParser::parseAliasSummary(std::string Name, GlobalValue::GUID GUID,
+bool LLParser::parseAliasSummary(std::string Name, GlobalValue::GUID &GUID,
unsigned ID) {
assert(Lex.getKind() == lltok::kw_alias);
LocTy Loc = Lex.getLoc();
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index ac61ede6395af..7058d04a3d40a 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -8325,6 +8325,21 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
break;
}
+ case bitc::FS_SECTION_INFO: {
+ if (Record.size() < 6)
+ return error("Invalid record");
+ uint64_t GUID = Record[0];
+ StringRef SectionName(Strtab.data() + Record[1], Record[2]);
+ StringRef OutputSectionName(Strtab.data() + Record[3], Record[4]);
+ bool Keep = Record[5] != 0;
+
+ auto &Entry = TheIndex.sectionInfos()[GUID];
+ Entry.SectionName = TheIndex.saveString(SectionName);
+ Entry.OutputSectionName = TheIndex.saveString(OutputSectionName);
+ Entry.Keep = Keep;
+ break;
+ }
+
case bitc::FS_STACK_IDS: { // [n x stackid]
// Save stack ids in the reader to consult when adding stack ids from the
// lists in the stack node and alloc node entries.
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 571336c217797..db1bec8adc19d 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -5010,6 +5010,17 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
Stream.EmitRecord(bitc::FS_BLOCK_COUNT,
ArrayRef<uint64_t>{Index->getBlockCount()});
+ for (const auto &Entry : Index->sectionInfos()) {
+ NameVals.push_back(Entry.first); // GUID
+ NameVals.push_back(StrtabBuilder.add(Entry.second.SectionName));
+ NameVals.push_back(Entry.second.SectionName.size());
+ NameVals.push_back(StrtabBuilder.add(Entry.second.OutputSectionName));
+ NameVals.push_back(Entry.second.OutputSectionName.size());
+ NameVals.push_back(Entry.second.Keep);
+ Stream.EmitRecord(bitc::FS_SECTION_INFO, NameVals);
+ NameVals.clear();
+ }
+
Stream.ExitBlock();
}
@@ -5431,6 +5442,17 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
Stream.EmitRecord(bitc::FS_BLOCK_COUNT,
ArrayRef<uint64_t>{Index.getBlockCount()});
+ for (const auto &Entry : Index.sectionInfos()) {
+ NameVals.push_back(Entry.first); // GUID
+ NameVals.push_back(StrtabBuilder.add(Entry.second.SectionName));
+ NameVals.push_back(Entry.second.SectionName.size());
+ NameVals.push_back(StrtabBuilder.add(Entry.second.OutputSectionName));
+ NameVals.push_back(Entry.second.OutputSectionName.size());
+ NameVals.push_back(Entry.second.Keep);
+ Stream.EmitRecord(bitc::FS_SECTION_INFO, NameVals);
+ NameVals.clear();
+ }
+
Stream.ExitBlock();
}
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index cad4f17b0db91..6616d662287cd 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -3809,6 +3809,12 @@ void AssemblyWriter::printSummaryInfo(unsigned Slot, const ValueInfo &VI) {
}
Out << ")";
}
+ if (auto I = TheIndex->sectionInfos().find(VI.getGUID());
+ I != TheIndex->sectionInfos().end()) {
+ Out << ", sectionInfo: (sectionName: \"" << I->second.SectionName
+ << "\", outputSectionName: \"" << I->second.OutputSectionName
+ << "\", keep: " << (I->second.Keep ? "true" : "false") << ")";
+ }
Out << ")";
if (VI.hasName() && !VI.name().empty())
Out << " ; guid = " << VI.getGUID();
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index c8c5b0880819a..9a93a84699cbb 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -61,6 +61,7 @@
#include "llvm/Transforms/IPO/MemProfContextDisambiguation.h"
#include "llvm/Transforms/IPO/WholeProgramDevirt.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
#include "llvm/Transforms/Utils/SplitModule.h"
#include <optional>
@@ -827,7 +828,8 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input,
}
Error LTO::add(std::unique_ptr<InputFile> InputPtr,
- ArrayRef<SymbolResolution> Res) {
+ ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver) {
llvm::TimeTraceScope timeScope("LTO add input", InputPtr->getName());
assert(!CalledGetMaxTasks);
@@ -849,7 +851,8 @@ Error LTO::add(std::unique_ptr<InputFile> InputPtr,
ArrayRef<SymbolResolution> InputRes = Res;
for (unsigned I = 0; I != Input->Mods.size(); ++I) {
- if (auto Err = addModule(*Input, InputRes, I, Res).moveInto(Res))
+ if (auto Err =
+ addModule(*Input, InputRes, I, Res, SectionResolver).moveInto(Res))
return Err;
}
@@ -865,7 +868,8 @@ void LTO::setBitcodeLibFuncs(ArrayRef<StringRef> BitcodeLibFuncs) {
Expected<ArrayRef<SymbolResolution>>
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
- unsigned ModI, ArrayRef<SymbolResolution> Res) {
+ unsigned ModI, ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver) {
llvm::TimeTraceScope timeScope("LTO add module", Input.getName());
Expected<BitcodeLTOInfo> LTOInfo = Input.Mods[ModI].getLTOInfo();
if (!LTOInfo)
@@ -904,10 +908,11 @@ LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
LTOInfo->HasSummary, Triple(Input.getTargetTriple()));
if (IsThinLTO)
- return addThinLTO(BM, ModSyms, Res);
+ return addThinLTO(BM, ModSyms, Res, SectionResolver);
RegularLTO.EmptyCombinedModule = false;
- auto ModOrErr = addRegularLTO(Input, InputRes, BM, ModSyms, Res);
+ auto ModOrErr =
+ addRegularLTO(Input, InputRes, BM, ModSyms, Res, SectionResolver);
if (!ModOrErr)
return ModOrErr.takeError();
Res = ModOrErr->second;
@@ -964,7 +969,8 @@ Expected<
std::pair<LTO::RegularLTOState::AddedModule, ArrayRef<SymbolResolution>>>
LTO::addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
- ArrayRef<SymbolResolution> Res) {
+ ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver) {
llvm::TimeTraceScope timeScope("LTO add regular LTO");
RegularLTOState::AddedModule Mod;
Expected<std::unique_ptr<Module>> MOrErr =
@@ -978,6 +984,21 @@ LTO::addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
if (Error Err = M.materializeMetadata())
return std::move(Err);
+ if (SectionResolver) {
+ SmallVector<GlobalValue *, 4> Keep;
+ for (GlobalObject &GO : M.global_objects()) {
+ if (GO.isDeclaration() || GO.getName().starts_with("llvm."))
+ continue;
+ if (GO.hasSection()) {
+ auto Res = SectionResolver(GO.getSection());
+ if (Res.Keep)
+ Keep.push_back(&GO);
+ }
+ }
+ if (!Keep.empty())
+ appendToCompilerUsed(M, Keep);
+ }
+
if (LTOMode == LTOK_UnifiedRegular) {
// cfi.functions metadata is intended to be used with ThinLTO and may
// trigger invalid IR transformations if they are present when doing regular
@@ -1181,7 +1202,8 @@ Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod,
// Add a ThinLTO module to the link.
Expected<ArrayRef<SymbolResolution>>
LTO::addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
- ArrayRef<SymbolResolution> Res) {
+ ArrayRef<SymbolResolution> Res,
+ SectionResolverFn SectionResolver) {
llvm::TimeTraceScope timeScope("LTO add thin LTO");
const auto BMID = BM.getModuleIdentifier();
ArrayRef<SymbolResolution> ResTmp = Res;
@@ -1209,6 +1231,23 @@ LTO::addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
}
}))
return Err;
+
+ if (SectionResolver) {
+ for (auto &Entry : ThinLTO.CombinedIndex.sectionInfos()) {
+ GlobalValue::GUID GUID = Entry.first;
+ ValueInfo VI = ThinLTO.CombinedIndex.getValueInfo(GUID);
+ if (VI) {
+ for (const auto &Summary : VI.getSummaryList()) {
+ if (Summary->modulePath() == BMID) {
+ auto Res = SectionResolver(Entry.second.SectionName);
+ Entry.second.Keep = Res.Keep;
+ break;
+ }
+ }
+ }
+ }
+ }
+
LLVM_DEBUG(dbgs() << "Module " << BMID << "\n");
for (const InputFile::Symbol &Sym : Syms) {
@@ -1339,6 +1378,13 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) {
if (Res.second.VisibleOutsideSummary && Res.second.Prevailing)
GUIDPreservedSymbols.insert(GUID);
+ auto It = ThinLTO.CombinedIndex.sectionInfos().find(GUID);
+ if (It != ThinLTO.CombinedIndex.sectionInfos().end() && It->second.Keep &&
+ Res.second.Prevailing) {
+ Res.second.Partition = GlobalResolution::External;
+ Res.second.VisibleOutsideSummary = true;
+ }
+
if (Res.second.ExportDynamic)
DynamicExportSymbols.insert(GUID);
@@ -1346,6 +1392,10 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) {
Res.second.Prevailing ? PrevailingType::Yes : PrevailingType::No;
}
+ for (const auto &Entry : ThinLTO.CombinedIndex.sectionInfos())
+ if (Entry.second.Keep)
+ GUIDPreservedSymbols.insert(Entry.first);
+
auto isPrevailing = [&](GlobalValue::GUID G) {
auto It = GUIDPrevailingResolutions.find(G);
if (It == GUIDPrevailingResolutions.end())
diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp
index 0f404be9bd4a8..b56ae10dcf7fb 100644
--- a/llvm/lib/Object/IRSymtab.cpp
+++ b/llvm/lib/Object/IRSymtab.cpp
@@ -220,7 +220,6 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab,
Unc = &Uncommons.back();
*Unc = {};
setStr(Unc->COFFWeakExternFallbackName, "");
- setStr(Unc->SectionName, "");
return *Unc;
};
@@ -311,9 +310,6 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab,
}
}
- if (!GO->getSection().empty())
- setStr(Uncommon().SectionName, Saver.save(GO->getSection()));
-
return Error::success();
}
diff --git a/llvm/test/Assembler/thinlto-sectioninfo.ll b/llvm/test/Assembler/thinlto-sectioninfo.ll
new file mode 100644
index 0000000000000..0457ba72718f0
--- /dev/null
+++ b/llvm/test/Assembler/thinlto-sectioninfo.ll
@@ -0,0 +1,24 @@
+; Test sectionInfo parsing
+; RUN: llvm-as %s -o - | llvm-dis -o - | FileCheck %s
+
+ at a = internal global i32 0, section ".foodata", align 4, !guid !0
+ at b = dso_local global ptr @a, section ".foodata", align 8, !guid !1
+
+define dso_local void @g() section ".footext" !guid !8 {
+entry:
+ ret void
+}
+
+!0 = !{i64 -4514776715853495485}
+!1 = !{i64 -1427730249719747694}
+!8 = !{i64 -5300342847281564238}
+
+^0 = module: (path: "[Regular LTO]", hash: (0, 0, 0, 0, 0))
+^1 = gv: (name: "g", summaries: (function: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 0, live: 0, dsoLocal: 1, canAutoHide: 0, importType: definition, noRenameOnPromotion: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 0, noRecurse: 0, returnDoesNotAlias: 0, noInline: 1, alwaysInline: 0, noUnwind: 1, mayThrow: 0, hasUnknownCall: 0, mustBeUnreachable: 0))), sectionInfo: (sectionName: ".footext", outputSectionName: "", keep: false)) ; guid = 13146401226427987378
+^2 = gv: (name: "a", summaries: (variable: (module: ^0, flags: (linkage: internal, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0, importType: definition, noRenameOnPromotion: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0))), sectionInfo: (sectionName: ".foodata", outputSectionName: "", keep: false)) ; guid = 13931967357856056131
+^3 = gv: (name: "b", summaries: (variable: (module: ^0, flags: (linkage: external, visibility: default, notEligibleToImport: 1, live: 0, dsoLocal: 1, canAutoHide: 0, importType: definition, noRenameOnPromotion: 0), varFlags: (readonly: 1, writeonly: 1, constant: 0), refs: (^2))), sectionInfo: (sectionName: ".foodata", outputSectionName: "", keep: false)) ; guid = 17019013823989803922
+^4 = blockcount: 0
+
+; CHECK: sectionInfo: (sectionName: ".footext", outputSectionName: "", keep: false)
+; CHECK: sectionInfo: (sectionName: ".foodata", outputSectionName: "", keep: false)
+; CHECK: sectionInfo: (sectionName: ".foodata", outputSectionName: "", keep: false)
diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
index 98aafd635651d..d1e97129ee02e 100644
--- a/llvm/tools/gold/gold-plugin.cpp
+++ b/llvm/tools/gold/gold-plugin.cpp
@@ -799,13 +799,6 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View,
break;
}
- // If the symbol has a C identifier section name, we need to mark
- // it as visible to a regular object so that LTO will keep it around
- // to ensure the linker generates special __start_<secname> and
- // __stop_<secname> symbols which may be used elsewhere.
- if (isValidCIdentifier(InpSym.getSectionName()))
- R.VisibleToRegularObj = true;
-
if (Resolution != LDPR_RESOLVED_DYN && Resolution != LDPR_UNDEF &&
(IsExecutable || !Res.DefaultVisibility))
R.FinalDefinitionInLinkageUnit = true;
@@ -819,7 +812,16 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View,
freeSymName(Sym);
}
- check(Lto.add(std::move(Input), Resols),
+ auto resolver = [this, &f](StringRef sectionName) {
+ // If the symbol has a C identifier section name, we need to mark
+ // it as visible to a regular object so that LTO will keep it around
+ // to ensure the linker generates special __start_<secname> and
+ // __stop_<secname> symbols which may be used elsewhere.
+ lto::SectionResolution r;
+ r.Keep = isValidCIdentifier(sectionName);
+ return r;
+ };
+ check(Lto.add(std::move(Input), Resols, resolver),
std::string("Failed to link module ") + F.name);
}
diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp
index 4bcf04df89ac9..a37ba2ad16acd 100644
--- a/llvm/tools/llvm-lto2/llvm-lto2.cpp
+++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp
@@ -633,9 +633,6 @@ static int dumpSymtab(int argc, char **argv) {
if (TT.isOSBinFormatCOFF() && Sym.isWeak() && Sym.isIndirect())
outs() << " fallback " << Sym.getCOFFWeakExternalFallback()
<< '\n';
-
- if (!Sym.getSectionName().empty())
- outs() << " section " << Sym.getSectionName() << "\n";
}
outs() << '\n';
>From 19739ce58a9a0ff81d55b8fa40ef7cade2f8705f Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at qti.qualcomm.com>
Date: Wed, 22 Jul 2026 12:56:47 -0700
Subject: [PATCH 2/2] Fix gold plugin.
---
llvm/tools/gold/gold-plugin.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp
index d1e97129ee02e..3b9fdd11e26a7 100644
--- a/llvm/tools/gold/gold-plugin.cpp
+++ b/llvm/tools/gold/gold-plugin.cpp
@@ -757,7 +757,6 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View,
assert(InputFileSyms.size() == F.syms.size());
std::vector<SymbolResolution> Resols(F.syms.size());
for (ld_plugin_symbol &Sym : F.syms) {
- const InputFile::Symbol &InpSym = InputFileSyms[SymNum];
SymbolResolution &R = Resols[SymNum++];
ld_plugin_symbol_resolution Resolution =
@@ -812,7 +811,7 @@ static void addModule(LTO &Lto, claimed_file &F, const void *View,
freeSymName(Sym);
}
- auto resolver = [this, &f](StringRef sectionName) {
+ auto resolver = [](StringRef sectionName) {
// If the symbol has a C identifier section name, we need to mark
// it as visible to a regular object so that LTO will keep it around
// to ensure the linker generates special __start_<secname> and
More information about the llvm-commits
mailing list