Revert "Reland "[LTO][LLD] Prevent invalid LTO libfunc transforms (#164916)"" (#192741)

Reverts llvm/llvm-project#190642

A bisect shows this as the change leading to the link failure at
https://g-issues.fuchsia.dev/issues/503377901
This commit is contained in:
PiJoules
2026-04-17 15:23:48 -07:00
committed by GitHub
parent 12a9996192
commit 24154a55d6
25 changed files with 52 additions and 488 deletions

View File

@@ -1407,14 +1407,12 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
// FIXME: Both ExecuteAction and thinBackend set up optimization remarks for
// the same context.
// FIXME: This does not yet set the list of bitcode libfuncs that it isn't
// safe to call. This precludes bitcode libc in distributed ThinLTO.
finalizeLLVMOptimizationRemarks(M->getContext());
if (Error E = thinBackend(
Conf, -1, AddStream, *M, *CombinedIndex, ImportList,
ModuleToDefinedGVSummaries[M->getModuleIdentifier()],
/*ModuleMap=*/nullptr, Conf.CodeGenOnly, /*BitcodeLibFuncs=*/{},
/*IRAddStream=*/nullptr, CGOpts.CmdArgs)) {
if (Error E =
thinBackend(Conf, -1, AddStream, *M, *CombinedIndex, ImportList,
ModuleToDefinedGVSummaries[M->getModuleIdentifier()],
/*ModuleMap=*/nullptr, Conf.CodeGenOnly,
/*IRAddStream=*/nullptr, CGOpts.CmdArgs)) {
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
errs() << "Error running ThinLTO backend: " << EIB.message() << '\n';
});

View File

@@ -25,6 +25,7 @@
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/RuntimeLibcalls.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
@@ -1401,6 +1402,8 @@ void BitcodeFile::parse() {
// FIXME: Check nodeduplicate
comdat[i] =
symtab.addComdat(this, saver.save(obj->getComdatTable()[i].first));
Triple tt(obj->getTargetTriple());
RTLIB::RuntimeLibcallsInfo libcalls(tt);
for (const lto::InputFile::Symbol &objSym : obj->symbols()) {
StringRef symName = saver.save(objSym.getName());
int comdatIndex = objSym.getComdatIndex();
@@ -1450,7 +1453,7 @@ void BitcodeFile::parse() {
symtab.addRegular(this, symName, nullptr, fakeSC, 0, objSym.isWeak());
}
symbols.push_back(sym);
if (objSym.isUsed())
if (objSym.isUsed() || objSym.isLibcall(libcalls))
symtab.ctx.config.gcroot.push_back(sym);
}
directives = saver.save(obj->getCOFFLinkerOpts());

View File

@@ -288,7 +288,3 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
return ret;
}
void BitcodeCompiler::setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs) {
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
}

View File

@@ -45,7 +45,6 @@ public:
void add(BitcodeFile &f);
std::vector<InputFile *> compile();
void setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs);
private:
std::unique_ptr<llvm::lto::LTO> ltoObj;

View File

@@ -1473,37 +1473,13 @@ void SymbolTable::compileBitcodeFiles() {
if (bitcodeFileInstances.empty())
return;
// Collect the bitcode library functions that are not safe to call because
// they were not yet brought in the link. (Such symbols are lazy.)
llvm::BumpPtrAllocator alloc;
llvm::StringSaver saver(alloc);
SmallVector<StringRef> bitcodeLibFuncs;
// Triple must be captured before the bitcode is moved into the compiler.
// Note that the below assumes that the set of possible libfuncs is roughly
// equivalent for all bitcode translation units.
llvm::Triple tt =
llvm::Triple(bitcodeFileInstances.front()->obj->getTargetTriple());
for (StringRef libFunc : lto::LTO::getLibFuncSymbols(tt, saver)) {
if (Symbol *sym = find(libFunc)) {
if (auto *l = dyn_cast<LazyArchive>(sym)) {
if (isBitcode(l->getMemberBuffer()))
bitcodeLibFuncs.push_back(libFunc);
} else if (auto *o = dyn_cast<LazyObject>(sym)) {
if (isBitcode(o->file->mb))
bitcodeLibFuncs.push_back(libFunc);
}
}
}
ScopedTimer t(ctx.ltoTimer);
lto.reset(new BitcodeCompiler(ctx));
lto->setBitcodeLibFuncs(bitcodeLibFuncs);
{
llvm::TimeTraceScope addScope("Add bitcode file instances");
for (BitcodeFile *f : bitcodeFileInstances)
lto->add(*f);
}
for (InputFile *newObj : lto->compile()) {
ObjFile *obj = cast<ObjFile>(newObj);
obj->parse();

View File

@@ -2781,27 +2781,8 @@ static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) {
template <class ELFT>
void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
llvm::TimeTraceScope timeScope("LTO");
// Collect the bitcode library functions that are not safe to call because
// they were not yet brought in the link. (Such symbols are lazy.)
llvm::BumpPtrAllocator alloc;
llvm::StringSaver saver(alloc);
SmallVector<StringRef> bitcodeLibFuncs;
if (!ctx.bitcodeFiles.empty()) {
// Triple must be captured before the bitcode is moved into the compiler.
// Note that the below assumes that the set of possible libfuncs is roughly
// equivalent for all bitcode translation units.
llvm::Triple tt =
llvm::Triple(ctx.bitcodeFiles.front()->obj->getTargetTriple());
for (StringRef libFunc : lto::LTO::getLibFuncSymbols(tt, saver))
if (Symbol *sym = ctx.symtab->find(libFunc);
sym && sym->isLazy() && isa<BitcodeFile>(sym->file))
bitcodeLibFuncs.push_back(libFunc);
}
// Compile bitcode files and replace bitcode symbols.
lto.reset(new BitcodeCompiler(ctx));
lto->setBitcodeLibFuncs(bitcodeLibFuncs);
for (BitcodeFile *file : ctx.bitcodeFiles)
lto->add(*file);

View File

@@ -436,7 +436,3 @@ SmallVector<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {
}
return ret;
}
void BitcodeCompiler::setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs) {
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
}

View File

@@ -43,7 +43,6 @@ public:
void add(BitcodeFile &f);
SmallVector<std::unique_ptr<InputFile>, 0> compile();
void setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs);
private:
Ctx &ctx;

View File

@@ -1,51 +0,0 @@
; REQUIRES: x86
; RUN: rm -rf %t && split-file %s %t && cd %t
; RUN: llvm-as main.ll -o main.obj
; RUN: llvm-as puts.ll -o puts.obj
; RUN: llvm-mc -filetype=obj -triple=x86_64-pc-windows-msvc printf.s -o printf.obj
; RUN: llvm-ar rcs libc.lib puts.obj printf.obj
;; Ensure that no printf->puts translation occurs during LTO because puts is in
;; bitcode, but was not brought into the link. This would fail the link by
;; extracting bitcode after LTO.
; RUN: lld-link -out:out.exe -entry:main -subsystem:console -lldmap:- -nodefaultlib main.obj libc.lib | FileCheck %s
;; Test the same behavior with lazy objects.
; RUN: lld-link -out:out-lazy.exe -entry:main -subsystem:console -lldmap:- -nodefaultlib main.obj /start-lib puts.obj /end-lib printf.obj | FileCheck %s
;; Test that translation DOES occur when puts is extracted and brought into the link.
; RUN: lld-link -out:out-extracted.exe -entry:main -subsystem:console -lldmap:- -nodefaultlib main.obj puts.obj printf.obj | FileCheck %s --check-prefix=EXTRACTED
; CHECK-NOT: puts
; CHECK: printf
; EXTRACTED: printf
; EXTRACTED: puts
;--- puts.ll
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
define i32 @puts(ptr nocapture readonly %0) noinline {
call void asm sideeffect "", ""()
ret i32 0
}
;--- printf.s
.globl printf
printf:
ret
;--- main.ll
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
@str = constant [5 x i8] c"foo\0A\00"
define i32 @main() {
%call = call i32 (ptr, ...) @printf(ptr @str)
ret i32 0
}
declare i32 @printf(ptr, ...)

View File

@@ -1,54 +0,0 @@
; REQUIRES: x86
; RUN: rm -rf %t && split-file %s %t && cd %t
; RUN: llvm-as main.ll -o main.o
; RUN: llvm-as puts.ll -o puts.o
; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu printf.s -o printf.o
; RUN: llvm-ar rcs libc.a puts.o printf.o
;; Ensure that no printf->puts translation occurs during LTO because puts is in
;; bitcode, but was not brought into the link. This would fail the link by
;; extracting bitcode after LTO.
; RUN: ld.lld -o out main.o libc.a
; RUN: llvm-nm out | FileCheck %s
;; Test the same behavior with lazy objects.
; RUN: ld.lld -o out-lazy main.o --start-lib puts.o --end-lib printf.o
; RUN: llvm-nm out-lazy | FileCheck %s
;; Test that translation DOES occur when puts is extracted and brought into the link.
; RUN: ld.lld -o out-extracted main.o puts.o printf.o
; RUN: llvm-nm out-extracted | FileCheck %s --check-prefix=EXTRACTED
; CHECK-NOT: puts
; CHECK: printf
; EXTRACTED: printf
; EXTRACTED: puts
;--- puts.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
define i32 @puts(ptr nocapture readonly %0) noinline {
call void asm sideeffect "", ""()
ret i32 0
}
;--- printf.s
.globl printf
printf:
ret
;--- main.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@str = constant [5 x i8] c"foo\0A\00"
define i32 @_start() {
%call = call i32 (ptr, ...) @printf(ptr @str)
ret i32 0
}
declare i32 @printf(ptr, ...)

View File

@@ -1,56 +0,0 @@
; REQUIRES: x86
; RUN: rm -rf %t && split-file %s %t && cd %t
; RUN: llvm-as main.ll -o main.o
; RUN: llvm-as puts.ll -o puts.o
; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown printf.s -o printf.o
; RUN: llvm-ar rcs libc.a puts.o printf.o
;; Ensure that no printf->puts translation occurs during LTO because puts is in
;; bitcode, but was not brought into the link. This would fail the link by
;; extracting bitcode after LTO.
; RUN: wasm-ld -o out.wasm main.o libc.a
; RUN: obj2yaml out.wasm | FileCheck %s
;; Test the same behavior with lazy objects.
; RUN: wasm-ld -o out-lazy.wasm main.o --start-lib puts.o --end-lib printf.o
; RUN: obj2yaml out-lazy.wasm | FileCheck %s
;; Test that translation DOES occur when puts is extracted and brought into the link.
; RUN: wasm-ld -o out-extracted.wasm main.o puts.o printf.o
; RUN: obj2yaml out-extracted.wasm | FileCheck %s --check-prefix=EXTRACTED
; CHECK-NOT: Name: puts
; CHECK: Name: printf
; EXTRACTED: Name: puts
; EXTRACTED-NOT: Name: printf
;--- puts.ll
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-unknown"
define i32 @puts(ptr nocapture readonly %0) noinline {
call void asm sideeffect "", ""()
ret i32 0
}
;--- printf.s
.globl printf
printf:
.functype printf (i32, i32) -> (i32)
i32.const 0
end_function
;--- main.ll
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-unknown"
@str = constant [5 x i8] c"foo\0A\00"
define i32 @_start() {
%call = call i32 (ptr, ...) @printf(ptr @str)
ret i32 0
}
declare i32 @printf(ptr, ...)

View File

@@ -195,10 +195,6 @@ static void thinLTOCreateEmptyIndexFiles() {
}
}
void BitcodeCompiler::setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs) {
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
}
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
SmallVector<InputFile *, 0> BitcodeCompiler::compile() {

View File

@@ -46,7 +46,6 @@ public:
void add(BitcodeFile &f);
SmallVector<InputFile *, 0> compile();
void setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs);
private:
std::unique_ptr<llvm::lto::LTO> ltoObj;

View File

@@ -82,31 +82,8 @@ void SymbolTable::compileBitcodeFiles() {
// Prevent further LTO objects being included
BitcodeFile::doneLTO = true;
// Collect the bitcode library functions that are not safe to call because
// they were not yet brought in the link. (Such symbols are lazy.)
llvm::BumpPtrAllocator alloc;
llvm::StringSaver saver(alloc);
SmallVector<StringRef> bitcodeLibFuncs;
if (!ctx.bitcodeFiles.empty()) {
// Triple must be captured before the bitcode is moved into the compiler.
// Note that the below assumes that the set of possible libfuncs is
// equivalent for all bitcode translation units.
llvm::Triple tt =
llvm::Triple(ctx.bitcodeFiles.front()->obj->getTargetTriple());
for (StringRef libFunc : llvm::lto::LTO::getLibFuncSymbols(tt, saver)) {
if (Symbol *sym = find(libFunc)) {
if (auto *lazy = dyn_cast<LazySymbol>(sym)) {
if (isa<BitcodeFile>(lazy->getFile()))
bitcodeLibFuncs.push_back(libFunc);
}
}
}
}
// Compile bitcode files and replace bitcode symbols.
lto.reset(new BitcodeCompiler);
lto->setBitcodeLibFuncs(bitcodeLibFuncs);
for (BitcodeFile *f : ctx.bitcodeFiles)
lto->add(*f);

View File

@@ -101,13 +101,6 @@ Changes to LLVM infrastructure
this may fail if symlink permissions are not available.
* Added ``readlink``, which reads the target of a symbolic link.
* Bitcode libraries can now implement compiler-managed library functions
(libcalls) without causing incorrect API manipulation or undefined references
([#177046](https://github.com/llvm/llvm-project/pull/125687)). Note that
there are still issues with invalid compiler reasoning about some functions
in bitcode, e.g. `malloc`. Not yet supported on MachO or when using
distributed ThinLTO.
Changes to building LLVM
------------------------

View File

@@ -179,8 +179,7 @@ public:
// may emit references to. Such symbols must be considered external, as
// removing them or modifying their interfaces would invalidate the code
// generator's knowledge about them.
bool isLibcall(const TargetLibraryInfo &TLI,
const RTLIB::RuntimeLibcallsInfo &Libcalls) const;
bool isLibcall(const RTLIB::RuntimeLibcallsInfo &Libcalls) const;
};
/// A range over the symbols in this InputFile.
@@ -309,8 +308,7 @@ public:
using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
const Config &C, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
ArrayRef<StringRef> BitcodeLibFuncs)>;
AddStreamFn AddStream, FileCache Cache)>;
/// This type defines the behavior following the thin-link phase during ThinLTO.
/// It encapsulates a backend function and a strategy for thread pool
@@ -325,11 +323,10 @@ struct ThinBackend {
std::unique_ptr<ThinBackendProc> operator()(
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
ArrayRef<StringRef> BitcodeLibFuncs) {
AddStreamFn AddStream, FileCache Cache) {
assert(isValid() && "Invalid backend function");
return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
std::move(AddStream), std::move(Cache), BitcodeLibFuncs);
std::move(AddStream), std::move(Cache));
}
ThreadPoolStrategy getParallelism() const { return Parallelism; }
bool isValid() const { return static_cast<bool>(Func); }
@@ -449,11 +446,6 @@ public:
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
ArrayRef<SymbolResolution> Res);
/// Set the list of functions implemented in bitcode that were not extracted
/// from an archive. Such functions may not be referenced, as they have
/// lost their opportunity to be defined.
LLVM_ABI void setBitcodeLibFuncs(ArrayRef<StringRef> BitcodeLibFuncs);
/// Returns an upper bound on the number of tasks that the client may expect.
/// This may only be called after all IR object files have been added. For a
/// full description of tasks see LTOBackend.h.
@@ -474,14 +466,6 @@ public:
LLVM_ABI static SmallVector<const char *>
getRuntimeLibcallSymbols(const Triple &TT);
/// Static method that returns a list of library function symbols that can be
/// generated by LTO but might not be visible from bitcode symbol table.
/// Unlike the runtime libcalls, the linker can report to the code generator
/// which of these are actually available in the link, and the code generator
/// can then only reference that set of symbols.
LLVM_ABI static SmallVector<StringRef>
getLibFuncSymbols(const Triple &TT, llvm::StringSaver &Saver);
protected:
// Called at the start of run().
virtual Error serializeInputsForDistribution() { return Error::success(); }
@@ -673,11 +657,6 @@ private:
// Setup optimization remarks according to the provided configuration.
Error setupOptimizationRemarks();
// LibFuncs that were implemented in bitcode but were not extracted
// from their libraries. Such functions cannot safely be called, since
// they have lost their opportunity to be defined.
SmallVector<StringRef> BitcodeLibFuncs;
public:
/// Helper to emit an optimization remark during the LTO link when outside of
/// the standard optimization pass pipeline.

View File

@@ -39,15 +39,13 @@ LLVM_ABI bool opt(const Config &Conf, TargetMachine *TM, unsigned Task,
Module &Mod, bool IsThinLTO,
ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary,
const std::vector<uint8_t> &CmdArgs,
ArrayRef<StringRef> BitcodeLibFuncs);
const std::vector<uint8_t> &CmdArgs);
/// Runs a regular LTO backend. The regular LTO backend can also act as the
/// regular LTO phase of ThinLTO, which may need to access the combined index.
LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel, Module &M,
ModuleSummaryIndex &CombinedIndex,
ArrayRef<StringRef> BitcodeLibFuncs);
ModuleSummaryIndex &CombinedIndex);
/// Runs a ThinLTO backend.
/// If \p ModuleMap is not nullptr, all the module files to be imported have
@@ -58,14 +56,14 @@ LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream,
/// the backend will skip optimization and only perform code generation. If
/// \p IRAddStream is not nullptr, it will be called just before code generation
/// to serialize the optimized IR.
LLVM_ABI Error thinBackend(
const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
const ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
ArrayRef<StringRef> BitcodeLibFuncs, AddStreamFn IRAddStream = nullptr,
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
LLVM_ABI Error
thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
const ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
AddStreamFn IRAddStream = nullptr,
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
LLVM_ABI Error finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile);

View File

@@ -653,11 +653,7 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
}
bool InputFile::Symbol::isLibcall(
const TargetLibraryInfo &TLI,
const RTLIB::RuntimeLibcallsInfo &Libcalls) const {
LibFunc F;
if (TLI.getLibFunc(IRName, F) && TLI.has(F))
return true;
return Libcalls.getSupportedLibcallImpl(IRName) != RTLIB::Unsupported;
}
@@ -719,8 +715,6 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
auto *ResE = Res.end();
(void)ResE;
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
TargetLibraryInfoImpl TLII(TT);
TargetLibraryInfo TLI(TLII);
for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
@@ -763,7 +757,7 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
GlobalRes.VisibleOutsideSummary = true;
}
bool IsLibcall = Sym.isLibcall(TLI, Libcalls);
bool IsLibcall = Sym.isLibcall(Libcalls);
// Set the partition to external if we know it is re-defined by the linker
// with -defsym or -wrap options, used elsewhere, e.g. it is visible to a
@@ -850,12 +844,6 @@ Error LTO::add(std::unique_ptr<InputFile> InputPtr,
return Error::success();
}
void LTO::setBitcodeLibFuncs(ArrayRef<StringRef> BitcodeLibFuncs) {
assert(this->BitcodeLibFuncs.empty() &&
"bitcode libfuncs were set twice; maybe accidentally clobbered?");
this->BitcodeLibFuncs.append(BitcodeLibFuncs.begin(), BitcodeLibFuncs.end());
}
Expected<ArrayRef<SymbolResolution>>
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
unsigned ModI, ArrayRef<SymbolResolution> Res) {
@@ -1481,9 +1469,9 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
}
if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) {
if (Error Err = backend(
Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex, BitcodeLibFuncs))
if (Error Err =
backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex))
return Err;
}
@@ -1503,20 +1491,6 @@ SmallVector<const char *> LTO::getRuntimeLibcallSymbols(const Triple &TT) {
return LibcallSymbols;
}
SmallVector<StringRef> LTO::getLibFuncSymbols(const Triple &TT,
StringSaver &Saver) {
auto TLII = std::make_unique<TargetLibraryInfoImpl>(TT);
TargetLibraryInfo TLI(*TLII);
SmallVector<StringRef> LibFuncSymbols;
LibFuncSymbols.reserve(LibFunc::NumLibFuncs);
for (unsigned I = LibFunc::Begin_LibFunc; I != LibFunc::End_LibFunc; ++I) {
LibFunc F = static_cast<LibFunc>(I);
if (TLI.has(F))
LibFuncSymbols.push_back(Saver.save(TLI.getName(F)).data());
}
return LibFuncSymbols;
}
Error ThinBackendProc::emitFiles(
const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath,
const std::string &NewModulePath) const {
@@ -1594,7 +1568,6 @@ protected:
// generating directly into the returned output stream.
AddStreamFn AddStream;
FileCache Cache;
ArrayRef<StringRef> BitcodeLibFuncs;
public:
InProcessThinBackend(
@@ -1602,13 +1575,11 @@ public:
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite,
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
ArrayRef<StringRef> BitcodeLibFuncs)
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles)
: CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries, OnWrite,
ShouldEmitIndexFiles, ShouldEmitImportsFiles,
ThinLTOParallelism),
AddStream(std::move(AddStream)), Cache(std::move(Cache)),
BitcodeLibFuncs(BitcodeLibFuncs) {}
AddStream(std::move(AddStream)), Cache(std::move(Cache)) {}
virtual Error runThinLTOBackendThread(
AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM,
@@ -1629,7 +1600,7 @@ public:
return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
ImportList, DefinedGlobals, &ModuleMap,
Conf.CodeGenOnly, BitcodeLibFuncs);
Conf.CodeGenOnly);
};
if (ShouldEmitIndexFiles) {
if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str()))
@@ -1714,14 +1685,13 @@ public:
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn CGAddStream, FileCache CGCache,
ArrayRef<StringRef> BitcodeLibFuncs, AddStreamFn IRAddStream,
AddStreamFn CGAddStream, FileCache CGCache, AddStreamFn IRAddStream,
FileCache IRCache)
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
ModuleToDefinedGVSummaries, std::move(CGAddStream),
std::move(CGCache), /*OnWrite=*/nullptr,
/*ShouldEmitIndexFiles=*/false,
/*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs),
/*ShouldEmitImportsFiles=*/false),
IRAddStream(std::move(IRAddStream)), IRCache(std::move(IRCache)) {}
Error runThinLTOBackendThread(
@@ -1744,7 +1714,7 @@ public:
return thinBackend(Conf, Task, CGAddStream, **MOrErr, CombinedIndex,
ImportList, DefinedGlobals, &ModuleMap,
Conf.CodeGenOnly, BitcodeLibFuncs, IRAddStream);
Conf.CodeGenOnly, IRAddStream);
};
// Like InProcessThinBackend, we produce index files as needed for
// FirstRoundThinBackend. However, these files are not generated for
@@ -1811,7 +1781,6 @@ public:
ThreadPoolStrategy ThinLTOParallelism,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
ArrayRef<StringRef> BitcodeLibFuncs,
std::unique_ptr<SmallVector<StringRef>> IRFiles,
stable_hash CombinedCGDataHash)
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
@@ -1819,7 +1788,7 @@ public:
std::move(Cache),
/*OnWrite=*/nullptr,
/*ShouldEmitIndexFiles=*/false,
/*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs),
/*ShouldEmitImportsFiles=*/false),
IRFiles(std::move(IRFiles)), CombinedCGDataHash(CombinedCGDataHash) {}
Error runThinLTOBackendThread(
@@ -1840,7 +1809,7 @@ public:
return thinBackend(Conf, Task, AddStream, *LoadedModule, CombinedIndex,
ImportList, DefinedGlobals, &ModuleMap,
/*CodeGenOnly=*/true, BitcodeLibFuncs);
/*CodeGenOnly=*/true);
};
if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) ||
all_of(CombinedIndex.getModuleHash(ModuleID),
@@ -1879,12 +1848,11 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
ArrayRef<StringRef> BitcodeLibFuncs) {
AddStreamFn AddStream, FileCache Cache) {
return std::make_unique<InProcessThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
ShouldEmitImportsFiles, BitcodeLibFuncs);
ShouldEmitImportsFiles);
};
return ThinBackend(Func, Parallelism);
}
@@ -2001,8 +1969,7 @@ ThinBackend lto::createWriteIndexesThinBackend(
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn AddStream, FileCache Cache,
ArrayRef<StringRef> BitcodeLibFuncs) {
AddStreamFn AddStream, FileCache Cache) {
return std::make_unique<WriteIndexesThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
@@ -2255,7 +2222,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
if (!CodeGenDataThinLTOTwoRounds) {
std::unique_ptr<ThinBackendProc> BackendProc =
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
AddStream, Cache, BitcodeLibFuncs);
AddStream, Cache);
return RunBackends(BackendProc.get());
}
@@ -2278,7 +2245,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n");
auto FirstRoundLTO = std::make_unique<FirstRoundThinBackend>(
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
CG.AddStream, CG.Cache, BitcodeLibFuncs, IR.AddStream, IR.Cache);
CG.AddStream, CG.Cache, IR.AddStream, IR.Cache);
if (Error E = RunBackends(FirstRoundLTO.get()))
return E;
@@ -2294,7 +2261,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n");
auto SecondRoundLTO = std::make_unique<SecondRoundThinBackend>(
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
AddStream, Cache, BitcodeLibFuncs, IR.getResult(), CombinedHash);
AddStream, Cache, IR.getResult(), CombinedHash);
return RunBackends(SecondRoundLTO.get());
}
@@ -2801,7 +2768,7 @@ ThinBackend lto::createOutOfProcessThinBackend(
auto Func =
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
AddStreamFn, FileCache Cache, ArrayRef<StringRef> BitcodeLibFuncs) {
AddStreamFn, FileCache Cache) {
return std::make_unique<OutOfProcessThinBackend>(
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, Cache,
OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles,

View File

@@ -259,8 +259,7 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) {
static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
unsigned OptLevel, bool IsThinLTO,
ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary,
const DenseSet<StringRef> &BitcodeLibFuncs) {
const ModuleSummaryIndex *ImportSummary) {
std::optional<PGOOptions> PGOOpt;
if (!Conf.SampleProfile.empty())
PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping,
@@ -302,20 +301,6 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
new TargetLibraryInfoImpl(TM->getTargetTriple(), TM->Options.VecLib));
if (Conf.Freestanding)
TLII->disableAllFunctions();
// Determine whether or not its safe to emit calls to each libfunc. Libfuncs
// that might have been present in the current LTO unit, but are not, have
// lost their only opportunity to be defined, and calls must not be emitted to
// them.
// FIXME: BitcodeLibFuncs isn't yet set for distributed ThinLTO.
TargetLibraryInfo TLI(*TLII);
for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E;
++I) {
LibFunc F = static_cast<LibFunc>(I);
if (BitcodeLibFuncs.contains(TLI.getName(F)))
TLII->setUnavailable(F);
}
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
// Parse a custom AA pipeline if asked to.
@@ -399,8 +384,7 @@ static bool isEmptyModule(const Module &Mod) {
bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary,
const std::vector<uint8_t> &CmdArgs,
ArrayRef<StringRef> BitcodeLibFuncs) {
const std::vector<uint8_t> &CmdArgs) {
llvm::TimeTraceScope timeScope("opt");
if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) {
// FIXME: the motivation for capturing post-merge bitcode and command line
@@ -425,11 +409,9 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
// analysis in the case of a ThinLTO build where this might be an empty
// regular LTO combined module, with a large combined index from ThinLTO.
if (!isEmptyModule(Mod)) {
DenseSet<StringRef> BitcodeLibFuncsSet(BitcodeLibFuncs.begin(),
BitcodeLibFuncs.end());
// FIXME: Plumb the combined index into the new pass manager.
runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary,
ImportSummary, BitcodeLibFuncsSet);
ImportSummary);
}
return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
}
@@ -595,8 +577,7 @@ Error lto::finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile) {
Error lto::backend(const Config &C, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel, Module &Mod,
ModuleSummaryIndex &CombinedIndex,
ArrayRef<StringRef> BitcodeLibFuncs) {
ModuleSummaryIndex &CombinedIndex) {
llvm::TimeTraceScope timeScope("LTO backend");
Expected<const Target *> TOrErr = initAndLookupTarget(C, Mod);
if (!TOrErr)
@@ -608,7 +589,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream,
if (!C.CodeGenOnly) {
if (!opt(C, TM.get(), 0, Mod, /*IsThinLTO=*/false,
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
/*CmdArgs*/ std::vector<uint8_t>(), BitcodeLibFuncs))
/*CmdArgs*/ std::vector<uint8_t>()))
return Error::success();
}
@@ -648,8 +629,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> *ModuleMap,
bool CodeGenOnly, ArrayRef<StringRef> BitcodeLibFuncs,
AddStreamFn IRAddStream,
bool CodeGenOnly, AddStreamFn IRAddStream,
const std::vector<uint8_t> &CmdArgs) {
llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier());
Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
@@ -688,7 +668,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
// Perform optimization and code generation for ThinLTO.
if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true,
/*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex,
CmdArgs, BitcodeLibFuncs))
CmdArgs))
return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
// Save the current module before the first codegen round.

View File

@@ -614,7 +614,7 @@ bool LTOCodeGenerator::optimize() {
TargetMach = createTargetMachine();
if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false,
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
/*CmdArgs*/ std::vector<uint8_t>(), /*BitcodeLibFuncs=*/{})) {
/*CmdArgs*/ std::vector<uint8_t>())) {
emitError("LTO middle-end optimizations failed");
return false;
}
@@ -639,7 +639,7 @@ bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream,
Config.CodeGenOnly = true;
Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule,
CombinedIndex, /*BitcodeLibFuncs=*/{});
CombinedIndex);
assert(!Err && "unexpected code-generation failure");
(void)Err;

View File

@@ -292,10 +292,8 @@ addUsedSymbolToPreservedGUID(const lto::InputFile &File,
DenseSet<GlobalValue::GUID> &PreservedGUID) {
Triple TT(File.getTargetTriple());
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
TargetLibraryInfoImpl TLII(TT);
TargetLibraryInfo TLI(TLII);
for (const auto &Sym : File.symbols())
if (Sym.isUsed() || Sym.isLibcall(TLI, Libcalls))
if (Sym.isUsed() || Sym.isLibcall(Libcalls))
PreservedGUID.insert(
GlobalValue::getGUIDAssumingExternalLinkage(Sym.getIRName()));
}

View File

@@ -1,25 +0,0 @@
;; When a libcall was not brought into the link, it can be used iff it is
;; defined in native code, not bitcode.
; RUN: opt %s -o %t.o -mtriple x86_64-unknown-linux-musl
; RUN: llvm-lto2 run -o %t.bitcode.o \
; RUN: -r %t.o,foo,plx -r %t.o,memcmp,x -save-temps %t.o \
; RUN: --bitcode-libfuncs=bcmp
; RUN: llvm-dis %t.bitcode.o.0.4.opt.bc -o - | FileCheck --check-prefixes=CHECK,BITCODE %s
; RUN: llvm-lto2 run -o %t.native.o \
; RUN: -r %t.o,foo,plx -r %t.o,memcmp,x -save-temps %t.o
; RUN: llvm-dis %t.native.o.0.4.opt.bc -o - | FileCheck --check-prefixes=CHECK,NATIVE %s
define i1 @foo(ptr %0, ptr %1, i64 %2) {
; CHECK-LABEL: define{{.*}}i1 @foo
; BITCODE-NEXT: %cmp = {{.*}}call i32 @memcmp
; BITCODE-NEXT: %eq = icmp eq i32 %cmp, 0
; NATIVE-NEXT: %bcmp = {{.*}}call i32 @bcmp
; NATIVE-NEXT: %eq = icmp eq i32 %bcmp, 0
; CHECK-NEXT: ret i1 %eq
%cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
%eq = icmp eq i32 %cmp, 0
ret i1 %eq
}
declare i32 @memcmp(ptr, ptr, i64)

View File

@@ -1,35 +0,0 @@
;; If a libcall was extracted in a thin link, it can be used even if not
;; present in the current TU.
; RUN: rm -rf %t && split-file %s %t && cd %t
; RUN: opt foo.ll -o foo.o -module-summary -mtriple x86_64-unknown-linux-musl
; RUN: opt bcmp.ll -o bcmp.o -module-summary -mtriple x86_64-unknown-linux-musl
; RUN: llvm-lto2 run -o lto.o \
; RUN: -r foo.o,foo,plx \
; RUN: -r foo.o,memcmp,x \
; RUN: -r bcmp.o,bcmp,pl \
; RUN: -r bcmp.o,bcmp_impl,x foo.o bcmp.o -save-temps
; RUN: llvm-dis lto.o.1.4.opt.bc -o - | FileCheck %s
;--- foo.ll
define i1 @foo(ptr %0, ptr %1, i64 %2) {
; CHECK-LABEL: define{{.*}}i1 @foo
; CHECK-NEXT: %bcmp = {{.*}}call i32 @bcmp
; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0
; CHECK-NEXT: ret i1 %eq
%cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
%eq = icmp eq i32 %cmp, 0
ret i1 %eq
}
declare i32 @memcmp(ptr, ptr, i64)
;--- bcmp.ll
define i32 @bcmp(ptr %0, ptr %1, i64 %2) noinline {
%r = call i32 @bcmp_impl(ptr %0, ptr %1, i64 %2)
ret i32 %r
}
declare i32 @bcmp_impl(ptr, ptr, i64)

View File

@@ -1,34 +0,0 @@
;; This test comes from a real world scenario in LTO, where the definition of
;; bcmp was deleted because it has no uses, but later instcombine re-introduced
;; a call to bcmp() as part of SimplifyLibCalls. Such deletions must not be
;; allowed.
; RUN: opt %s -o %t.o -mtriple x86_64-unknown-linux-musl
; RUN: llvm-lto2 run -o %t.lto.o \
; RUN: -r %t.o,foo,plx \
; RUN: -r %t.o,memcmp,x \
; RUN: -r %t.o,bcmp,pl \
; RUN: -r %t.o,bcmp_impl,x %t.o -save-temps
; RUN: llvm-dis %t.lto.o.0.4.opt.bc -o - | FileCheck %s
define i1 @foo(ptr %0, ptr %1, i64 %2) {
; CHECK-LABEL: define{{.*}}i1 @foo
; CHECK-NEXT: %bcmp = {{.*}}call i32 @bcmp
; CHECK-NEXT: %eq = icmp eq i32 %bcmp, 0
; CHECK-NEXT: ret i1 %eq
%cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
%eq = icmp eq i32 %cmp, 0
ret i1 %eq
}
declare i32 @memcmp(ptr, ptr, i64)
declare i32 @bcmp_impl(ptr, ptr, i64)
;; Ensure bcmp is not removed from module because it is external.
; CHECK: define dso_local i32 @bcmp
define i32 @bcmp(ptr %0, ptr %1, i64 %2) noinline {
%r = call i32 @bcmp_impl(ptr %0, ptr %1, i64 %2)
ret i32 %r
}

View File

@@ -234,19 +234,6 @@ static cl::opt<bool>
AllVtablesHaveTypeInfos("all-vtables-have-type-infos", cl::Hidden,
cl::desc("All vtables have type infos"));
// Specifying a symbol here states that it is a library symbol that had a
// definition in bitcode, but was not extracted. Such symbols cannot safely
// be referenced, since they have already lost their opportunity to be defined.
//
// FIXME: Listing all bitcode libfunc symbols here is clunky. A higher-level way
// to indicate which TUs made it into the link might be better, but this would
// require more detailed tracking of the sources of constructs in the IR.
// Alternatively, there may be some other data structure that could hold this
// information.
static cl::list<std::string> BitcodeLibFuncs(
"bitcode-libfuncs", cl::Hidden,
cl::desc("set of unextracted libfuncs implemented in bitcode"));
static cl::opt<bool> TimeTrace("time-trace", cl::desc("Record time trace"));
static cl::opt<unsigned> TimeTraceGranularity(
@@ -527,9 +514,6 @@ static int run(int argc, char **argv) {
if (HasErrors)
return 1;
Lto.setBitcodeLibFuncs(
SmallVector<StringRef>(BitcodeLibFuncs.begin(), BitcodeLibFuncs.end()));
FileCache Cache;
if (!CacheDir.empty())
Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),