Skip to content

[LLD][COFF] Process bitcode files separately for each symbol table on ARM64X #123194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lld/COFF/COFFLinkerContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ class COFFLinkerContext : public CommonLinkerContext {
std::vector<ObjFile *> objFileInstances;
std::map<std::string, PDBInputFile *> pdbInputFileInstances;
std::vector<ImportFile *> importFileInstances;
std::vector<BitcodeFile *> bitcodeFileInstances;

MergeChunk *mergeChunkInstances[Log2MaxSectionAlignment + 1] = {};

Expand Down
41 changes: 22 additions & 19 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ void LinkerDriver::addFile(InputFile *file) {
<< " linked in after "
"doing LTO compilation.";
}
ctx.bitcodeFileInstances.push_back(f);
f->symtab.bitcodeFileInstances.push_back(f);
} else if (auto *f = dyn_cast<ImportFile>(file)) {
ctx.importFileInstances.push_back(f);
}
Expand Down Expand Up @@ -285,7 +285,7 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
addFile(make<ArchiveFile>(ctx, mbref));
break;
case file_magic::bitcode:
addFile(make<BitcodeFile>(ctx, mbref, "", 0, lazy));
addFile(BitcodeFile::create(ctx, mbref, "", 0, lazy));
break;
case file_magic::coff_object:
case file_magic::coff_import_library:
Expand Down Expand Up @@ -374,8 +374,8 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
if (magic == file_magic::coff_object) {
obj = ObjFile::create(ctx, mb);
} else if (magic == file_magic::bitcode) {
obj =
make<BitcodeFile>(ctx, mb, parentName, offsetInArchive, /*lazy=*/false);
obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive,
/*lazy=*/false);
} else if (magic == file_magic::coff_cl_gl_object) {
Err(ctx) << mb.getBufferIdentifier()
<< ": is not a native COFF file. Recompile without /GL?";
Expand Down Expand Up @@ -2571,19 +2571,19 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
}
}

// If any inputs are bitcode files, the LTO code generator may create
// references to library functions that are not explicit in the bitcode
// file's symbol table. If any of those library functions are defined in a
// bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
if (!ctx.bitcodeFileInstances.empty()) {
llvm::Triple TT(
ctx.bitcodeFileInstances.front()->obj->getTargetTriple());
for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))
ctx.symtab.addLibcall(s);
}

ctx.forEachSymtab([&](SymbolTable &symtab) {
// If any inputs are bitcode files, the LTO code generator may create
// references to library functions that are not explicit in the bitcode
// file's symbol table. If any of those library functions are defined in
// a bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
if (!symtab.bitcodeFileInstances.empty()) {
llvm::Triple TT(
symtab.bitcodeFileInstances.front()->obj->getTargetTriple());
for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))
symtab.addLibcall(s);
}

// Windows specific -- if __load_config_used can be resolved, resolve
// it.
if (symtab.findUnderscore("_load_config_used"))
Expand Down Expand Up @@ -2639,8 +2639,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// If we are going to do codegen for link-time optimization, check for
// unresolvable symbols first, so we don't spend time generating code that
// will fail to link anyway.
if (!ctx.bitcodeFileInstances.empty() && !config->forceUnresolved)
ctx.symtab.reportUnresolvable();
if (!config->forceUnresolved)
ctx.forEachSymtab([](SymbolTable &symtab) {
if (!symtab.bitcodeFileInstances.empty())
symtab.reportUnresolvable();
});
if (errorCount())
return;

Expand All @@ -2655,7 +2658,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// link those files (unless -thinlto-index-only was given, in which case we
// resolve symbols and write indices, but don't generate native code or link).
ltoCompilationDone = true;
ctx.symtab.compileBitcodeFiles();
ctx.forEachSymtab([](SymbolTable &symtab) { symtab.compileBitcodeFiles(); });

if (Defined *d =
dyn_cast_or_null<Defined>(ctx.symtab.findUnderscore("_tls_used")))
Expand Down
19 changes: 13 additions & 6 deletions lld/COFF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,10 +1229,15 @@ void ImportFile::parse() {
}
}

BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
StringRef archiveName, uint64_t offsetInArchive,
bool lazy)
: InputFile(ctx.symtab, BitcodeKind, mb, lazy) {
BitcodeFile::BitcodeFile(SymbolTable &symtab, MemoryBufferRef mb,
std::unique_ptr<lto::InputFile> &o, bool lazy)
: InputFile(symtab, BitcodeKind, mb, lazy) {
obj.swap(o);
}

BitcodeFile *BitcodeFile::create(COFFLinkerContext &ctx, MemoryBufferRef mb,
StringRef archiveName,
uint64_t offsetInArchive, bool lazy) {
std::string path = mb.getBufferIdentifier().str();
if (ctx.config.thinLTOIndexOnly)
path = replaceThinLTOSuffix(mb.getBufferIdentifier(),
Expand All @@ -1252,7 +1257,9 @@ BitcodeFile::BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
sys::path::filename(path) +
utostr(offsetInArchive)));

obj = check(lto::InputFile::create(mbref));
std::unique_ptr<lto::InputFile> obj = check(lto::InputFile::create(mbref));
return make<BitcodeFile>(ctx.getSymtab(getMachineType(obj.get())), mb, obj,
lazy);
}

BitcodeFile::~BitcodeFile() = default;
Expand Down Expand Up @@ -1329,7 +1336,7 @@ void BitcodeFile::parseLazy() {
}
}

MachineTypes BitcodeFile::getMachineType() const {
MachineTypes BitcodeFile::getMachineType(const llvm::lto::InputFile *obj) {
Triple t(obj->getTargetTriple());
switch (t.getArch()) {
case Triple::x86_64:
Expand Down
14 changes: 10 additions & 4 deletions lld/COFF/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,13 +386,19 @@ class ImportFile : public InputFile {
// Used for LTO.
class BitcodeFile : public InputFile {
public:
explicit BitcodeFile(COFFLinkerContext &ctx, MemoryBufferRef mb,
StringRef archiveName, uint64_t offsetInArchive,
bool lazy);
explicit BitcodeFile(SymbolTable &symtab, MemoryBufferRef mb,
std::unique_ptr<llvm::lto::InputFile> &obj, bool lazy);
~BitcodeFile();

static BitcodeFile *create(COFFLinkerContext &ctx, MemoryBufferRef mb,
StringRef archiveName, uint64_t offsetInArchive,
bool lazy);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
MachineTypes getMachineType() const override;
MachineTypes getMachineType() const override {
return getMachineType(obj.get());
}
static MachineTypes getMachineType(const llvm::lto::InputFile *obj);
void parseLazy();
std::unique_ptr<llvm::lto::InputFile> obj;

Expand Down
17 changes: 8 additions & 9 deletions lld/COFF/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ bool SymbolTable::handleMinGWAutomaticImport(Symbol *sym, StringRef name) {
/// defined symbol imported" diagnostic for symbols in localImports.
/// objFiles and bitcodeFiles (if not nullptr) are used to report where
/// undefined symbols are referenced.
static void reportProblemSymbols(
COFFLinkerContext &ctx, const SmallPtrSetImpl<Symbol *> &undefs,
void SymbolTable::reportProblemSymbols(
const SmallPtrSetImpl<Symbol *> &undefs,
const DenseMap<Symbol *, Symbol *> *localImports, bool needBitcodeFiles) {
// Return early if there is nothing to report (which should be
// the common case).
Expand Down Expand Up @@ -392,7 +392,7 @@ static void reportProblemSymbols(
processFile(file, file->getSymbols());

if (needBitcodeFiles)
for (BitcodeFile *file : ctx.bitcodeFileInstances)
for (BitcodeFile *file : bitcodeFileInstances)
processFile(file, file->getSymbols());

for (const UndefinedDiag &undefDiag : undefDiags)
Expand Down Expand Up @@ -423,8 +423,7 @@ void SymbolTable::reportUnresolvable() {
undefs.insert(sym);
}

reportProblemSymbols(ctx, undefs,
/* localImports */ nullptr, true);
reportProblemSymbols(undefs, /*localImports=*/nullptr, true);
}

bool SymbolTable::resolveRemainingUndefines() {
Expand Down Expand Up @@ -506,8 +505,8 @@ bool SymbolTable::resolveRemainingUndefines() {
}

reportProblemSymbols(
ctx, undefs,
ctx.config.warnLocallyDefinedImported ? &localImports : nullptr, false);
undefs, ctx.config.warnLocallyDefinedImported ? &localImports : nullptr,
false);
return foundLazy;
}

Expand Down Expand Up @@ -1124,13 +1123,13 @@ Symbol *SymbolTable::addUndefined(StringRef name) {
}

void SymbolTable::compileBitcodeFiles() {
if (ctx.bitcodeFileInstances.empty())
if (bitcodeFileInstances.empty())
return;

llvm::TimeTraceScope timeScope("Compile bitcode");
ScopedTimer t(ctx.ltoTimer);
lto.reset(new BitcodeCompiler(ctx));
for (BitcodeFile *f : ctx.bitcodeFileInstances)
for (BitcodeFile *f : bitcodeFileInstances)
lto->add(*f);
for (InputFile *newObj : lto->compile()) {
ObjFile *obj = cast<ObjFile>(newObj);
Expand Down
8 changes: 8 additions & 0 deletions lld/COFF/SymbolTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/raw_ostream.h"

namespace llvm {
Expand Down Expand Up @@ -155,6 +156,8 @@ class SymbolTable {
callback(pair.second);
}

std::vector<BitcodeFile *> bitcodeFileInstances;

DefinedRegular *loadConfigSym = nullptr;
uint32_t loadConfigSize = 0;
void initializeLoadConfig();
Expand All @@ -175,6 +178,11 @@ class SymbolTable {
std::unique_ptr<BitcodeCompiler> lto;
std::vector<std::pair<Symbol *, Symbol *>> entryThunks;
llvm::DenseMap<Symbol *, Symbol *> exitThunks;

void
reportProblemSymbols(const llvm::SmallPtrSetImpl<Symbol *> &undefs,
const llvm::DenseMap<Symbol *, Symbol *> *localImports,
bool needBitcodeFiles);
};

std::vector<std::string> getSymbolLocations(ObjFile *file, uint32_t symIndex);
Expand Down
47 changes: 47 additions & 0 deletions lld/test/COFF/lto-arm64x.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
; REQUIRES: aarch64, x86
; RUN: split-file %s %t.dir && cd %t.dir

; RUN: llvm-as arm64ec.ll -o arm64ec.obj
; RUN: llvm-as aarch64.ll -o aarch64.obj
; RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj
; RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj

; RUN: lld-link -machine:arm64x aarch64.obj arm64ec.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -out:out.exe -subsystem:console
; RUN: llvm-objdump -d out.exe | FileCheck %s

; CHECK: 0000000140001000 <.text>:
; CHECK-NEXT: 140001000: 52800020 mov w0, #0x1 // =1
; CHECK-NEXT: 140001004: d65f03c0 ret
; CHECK-NEXT: ...
; CHECK-NEXT: 140002000: 00000009 udf #0x9
; CHECK-NEXT: 140002004: 52800040 mov w0, #0x2 // =2
; CHECK-NEXT: 140002008: d65f03c0 ret

; CHECK: 0000000140003000 <.hexpthk>:
; CHECK-NEXT: 140003000: 48 8b c4 movq %rsp, %rax
; CHECK-NEXT: 140003003: 48 89 58 20 movq %rbx, 0x20(%rax)
; CHECK-NEXT: 140003007: 55 pushq %rbp
; CHECK-NEXT: 140003008: 5d popq %rbp
; CHECK-NEXT: 140003009: e9 f6 ef ff ff jmp 0x140002004 <.text+0x1004>
; CHECK-NEXT: 14000300e: cc int3
; CHECK-NEXT: 14000300f: cc int3

#--- arm64ec.ll

target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "arm64ec-unknown-windows-msvc"

define dso_local i32 @mainCRTStartup() {
entry:
ret i32 2
}

#--- aarch64.ll

target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
target triple = "aarch64-unknown-windows-msvc"

define dso_local i32 @mainCRTStartup() {
entry:
ret i32 1
}
Loading