This reverts commit 1ec7e86b3a779df2a0af3f37e58c8f5b3a398d7f after issue #190072 was fixed.
This commit is contained in:
parent
412d6941e3
commit
fecf609998
@ -1410,12 +1410,14 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
|
|||||||
|
|
||||||
// FIXME: Both ExecuteAction and thinBackend set up optimization remarks for
|
// FIXME: Both ExecuteAction and thinBackend set up optimization remarks for
|
||||||
// the same context.
|
// 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());
|
finalizeLLVMOptimizationRemarks(M->getContext());
|
||||||
if (Error E =
|
if (Error E = thinBackend(
|
||||||
thinBackend(Conf, -1, AddStream, *M, *CombinedIndex, ImportList,
|
Conf, -1, AddStream, *M, *CombinedIndex, ImportList,
|
||||||
ModuleToDefinedGVSummaries[M->getModuleIdentifier()],
|
ModuleToDefinedGVSummaries[M->getModuleIdentifier()],
|
||||||
/*ModuleMap=*/nullptr, Conf.CodeGenOnly,
|
/*ModuleMap=*/nullptr, Conf.CodeGenOnly, /*BitcodeLibFuncs=*/{},
|
||||||
/*IRAddStream=*/nullptr, CGOpts.CmdArgs)) {
|
/*IRAddStream=*/nullptr, CGOpts.CmdArgs)) {
|
||||||
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
|
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) {
|
||||||
errs() << "Error running ThinLTO backend: " << EIB.message() << '\n';
|
errs() << "Error running ThinLTO backend: " << EIB.message() << '\n';
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||||
#include "llvm/IR/Mangler.h"
|
#include "llvm/IR/Mangler.h"
|
||||||
#include "llvm/IR/RuntimeLibcalls.h"
|
|
||||||
#include "llvm/LTO/LTO.h"
|
#include "llvm/LTO/LTO.h"
|
||||||
#include "llvm/Object/Binary.h"
|
#include "llvm/Object/Binary.h"
|
||||||
#include "llvm/Object/COFF.h"
|
#include "llvm/Object/COFF.h"
|
||||||
@ -1394,8 +1393,6 @@ void BitcodeFile::parse() {
|
|||||||
// FIXME: Check nodeduplicate
|
// FIXME: Check nodeduplicate
|
||||||
comdat[i] =
|
comdat[i] =
|
||||||
symtab.addComdat(this, saver.save(obj->getComdatTable()[i].first));
|
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()) {
|
for (const lto::InputFile::Symbol &objSym : obj->symbols()) {
|
||||||
StringRef symName = saver.save(objSym.getName());
|
StringRef symName = saver.save(objSym.getName());
|
||||||
int comdatIndex = objSym.getComdatIndex();
|
int comdatIndex = objSym.getComdatIndex();
|
||||||
@ -1445,7 +1442,7 @@ void BitcodeFile::parse() {
|
|||||||
symtab.addRegular(this, symName, nullptr, fakeSC, 0, objSym.isWeak());
|
symtab.addRegular(this, symName, nullptr, fakeSC, 0, objSym.isWeak());
|
||||||
}
|
}
|
||||||
symbols.push_back(sym);
|
symbols.push_back(sym);
|
||||||
if (objSym.isUsed() || objSym.isLibcall(libcalls))
|
if (objSym.isUsed())
|
||||||
symtab.ctx.config.gcroot.push_back(sym);
|
symtab.ctx.config.gcroot.push_back(sym);
|
||||||
}
|
}
|
||||||
directives = saver.save(obj->getCOFFLinkerOpts());
|
directives = saver.save(obj->getCOFFLinkerOpts());
|
||||||
|
|||||||
@ -288,3 +288,7 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BitcodeCompiler::setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs) {
|
||||||
|
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
|
||||||
|
}
|
||||||
|
|||||||
@ -45,6 +45,7 @@ public:
|
|||||||
|
|
||||||
void add(BitcodeFile &f);
|
void add(BitcodeFile &f);
|
||||||
std::vector<InputFile *> compile();
|
std::vector<InputFile *> compile();
|
||||||
|
void setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<llvm::lto::LTO> ltoObj;
|
std::unique_ptr<llvm::lto::LTO> ltoObj;
|
||||||
|
|||||||
@ -1437,13 +1437,37 @@ void SymbolTable::compileBitcodeFiles() {
|
|||||||
if (bitcodeFileInstances.empty())
|
if (bitcodeFileInstances.empty())
|
||||||
return;
|
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);
|
ScopedTimer t(ctx.ltoTimer);
|
||||||
lto.reset(new BitcodeCompiler(ctx));
|
lto.reset(new BitcodeCompiler(ctx));
|
||||||
|
lto->setBitcodeLibFuncs(bitcodeLibFuncs);
|
||||||
{
|
{
|
||||||
llvm::TimeTraceScope addScope("Add bitcode file instances");
|
llvm::TimeTraceScope addScope("Add bitcode file instances");
|
||||||
for (BitcodeFile *f : bitcodeFileInstances)
|
for (BitcodeFile *f : bitcodeFileInstances)
|
||||||
lto->add(*f);
|
lto->add(*f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (InputFile *newObj : lto->compile()) {
|
for (InputFile *newObj : lto->compile()) {
|
||||||
ObjFile *obj = cast<ObjFile>(newObj);
|
ObjFile *obj = cast<ObjFile>(newObj);
|
||||||
obj->parse();
|
obj->parse();
|
||||||
|
|||||||
@ -2774,8 +2774,27 @@ static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) {
|
|||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
|
void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
|
||||||
llvm::TimeTraceScope timeScope("LTO");
|
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.
|
// Compile bitcode files and replace bitcode symbols.
|
||||||
lto.reset(new BitcodeCompiler(ctx));
|
lto.reset(new BitcodeCompiler(ctx));
|
||||||
|
lto->setBitcodeLibFuncs(bitcodeLibFuncs);
|
||||||
for (BitcodeFile *file : ctx.bitcodeFiles)
|
for (BitcodeFile *file : ctx.bitcodeFiles)
|
||||||
lto->add(*file);
|
lto->add(*file);
|
||||||
|
|
||||||
|
|||||||
@ -436,3 +436,7 @@ SmallVector<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BitcodeCompiler::setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs) {
|
||||||
|
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
|
||||||
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ public:
|
|||||||
|
|
||||||
void add(BitcodeFile &f);
|
void add(BitcodeFile &f);
|
||||||
SmallVector<std::unique_ptr<InputFile>, 0> compile();
|
SmallVector<std::unique_ptr<InputFile>, 0> compile();
|
||||||
|
void setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ctx &ctx;
|
Ctx &ctx;
|
||||||
|
|||||||
51
lld/test/COFF/lto-libcall-archive-bitcode.test
Normal file
51
lld/test/COFF/lto-libcall-archive-bitcode.test
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
; 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, ...)
|
||||||
54
lld/test/ELF/lto/libcall-archive-bitcode.test
Normal file
54
lld/test/ELF/lto/libcall-archive-bitcode.test
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
; 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, ...)
|
||||||
56
lld/test/wasm/lto/libcall-archive-bitcode.ll
Normal file
56
lld/test/wasm/lto/libcall-archive-bitcode.ll
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
; 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, ...)
|
||||||
@ -195,6 +195,10 @@ static void thinLTOCreateEmptyIndexFiles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BitcodeCompiler::setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs) {
|
||||||
|
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
|
||||||
|
}
|
||||||
|
|
||||||
// Merge all the bitcode files we have seen, codegen the result
|
// Merge all the bitcode files we have seen, codegen the result
|
||||||
// and return the resulting objects.
|
// and return the resulting objects.
|
||||||
SmallVector<InputFile *, 0> BitcodeCompiler::compile() {
|
SmallVector<InputFile *, 0> BitcodeCompiler::compile() {
|
||||||
|
|||||||
@ -46,6 +46,7 @@ public:
|
|||||||
|
|
||||||
void add(BitcodeFile &f);
|
void add(BitcodeFile &f);
|
||||||
SmallVector<InputFile *, 0> compile();
|
SmallVector<InputFile *, 0> compile();
|
||||||
|
void setBitcodeLibFuncs(ArrayRef<StringRef> bitcodeLibFuncs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<llvm::lto::LTO> ltoObj;
|
std::unique_ptr<llvm::lto::LTO> ltoObj;
|
||||||
|
|||||||
@ -82,8 +82,31 @@ void SymbolTable::compileBitcodeFiles() {
|
|||||||
// Prevent further LTO objects being included
|
// Prevent further LTO objects being included
|
||||||
BitcodeFile::doneLTO = true;
|
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.
|
// Compile bitcode files and replace bitcode symbols.
|
||||||
lto.reset(new BitcodeCompiler);
|
lto.reset(new BitcodeCompiler);
|
||||||
|
lto->setBitcodeLibFuncs(bitcodeLibFuncs);
|
||||||
|
|
||||||
for (BitcodeFile *f : ctx.bitcodeFiles)
|
for (BitcodeFile *f : ctx.bitcodeFiles)
|
||||||
lto->add(*f);
|
lto->add(*f);
|
||||||
|
|
||||||
|
|||||||
@ -101,6 +101,13 @@ Changes to LLVM infrastructure
|
|||||||
this may fail if symlink permissions are not available.
|
this may fail if symlink permissions are not available.
|
||||||
* Added ``readlink``, which reads the target of a symbolic link.
|
* 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
|
Changes to building LLVM
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|||||||
@ -179,7 +179,8 @@ public:
|
|||||||
// may emit references to. Such symbols must be considered external, as
|
// may emit references to. Such symbols must be considered external, as
|
||||||
// removing them or modifying their interfaces would invalidate the code
|
// removing them or modifying their interfaces would invalidate the code
|
||||||
// generator's knowledge about them.
|
// generator's knowledge about them.
|
||||||
bool isLibcall(const RTLIB::RuntimeLibcallsInfo &Libcalls) const;
|
bool isLibcall(const TargetLibraryInfo &TLI,
|
||||||
|
const RTLIB::RuntimeLibcallsInfo &Libcalls) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A range over the symbols in this InputFile.
|
/// A range over the symbols in this InputFile.
|
||||||
@ -308,7 +309,8 @@ public:
|
|||||||
using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
|
using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
|
||||||
const Config &C, ModuleSummaryIndex &CombinedIndex,
|
const Config &C, ModuleSummaryIndex &CombinedIndex,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn AddStream, FileCache Cache)>;
|
AddStreamFn AddStream, FileCache Cache,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs)>;
|
||||||
|
|
||||||
/// This type defines the behavior following the thin-link phase during ThinLTO.
|
/// This type defines the behavior following the thin-link phase during ThinLTO.
|
||||||
/// It encapsulates a backend function and a strategy for thread pool
|
/// It encapsulates a backend function and a strategy for thread pool
|
||||||
@ -323,10 +325,11 @@ struct ThinBackend {
|
|||||||
std::unique_ptr<ThinBackendProc> operator()(
|
std::unique_ptr<ThinBackendProc> operator()(
|
||||||
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn AddStream, FileCache Cache) {
|
AddStreamFn AddStream, FileCache Cache,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs) {
|
||||||
assert(isValid() && "Invalid backend function");
|
assert(isValid() && "Invalid backend function");
|
||||||
return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
|
return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
|
||||||
std::move(AddStream), std::move(Cache));
|
std::move(AddStream), std::move(Cache), BitcodeLibFuncs);
|
||||||
}
|
}
|
||||||
ThreadPoolStrategy getParallelism() const { return Parallelism; }
|
ThreadPoolStrategy getParallelism() const { return Parallelism; }
|
||||||
bool isValid() const { return static_cast<bool>(Func); }
|
bool isValid() const { return static_cast<bool>(Func); }
|
||||||
@ -446,6 +449,11 @@ public:
|
|||||||
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
|
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
|
||||||
ArrayRef<SymbolResolution> Res);
|
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.
|
/// 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
|
/// This may only be called after all IR object files have been added. For a
|
||||||
/// full description of tasks see LTOBackend.h.
|
/// full description of tasks see LTOBackend.h.
|
||||||
@ -466,6 +474,14 @@ public:
|
|||||||
LLVM_ABI static SmallVector<const char *>
|
LLVM_ABI static SmallVector<const char *>
|
||||||
getRuntimeLibcallSymbols(const Triple &TT);
|
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:
|
protected:
|
||||||
// Called at the start of run().
|
// Called at the start of run().
|
||||||
virtual Error serializeInputsForDistribution() { return Error::success(); }
|
virtual Error serializeInputsForDistribution() { return Error::success(); }
|
||||||
@ -657,6 +673,11 @@ private:
|
|||||||
// Setup optimization remarks according to the provided configuration.
|
// Setup optimization remarks according to the provided configuration.
|
||||||
Error setupOptimizationRemarks();
|
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:
|
public:
|
||||||
/// Helper to emit an optimization remark during the LTO link when outside of
|
/// Helper to emit an optimization remark during the LTO link when outside of
|
||||||
/// the standard optimization pass pipeline.
|
/// the standard optimization pass pipeline.
|
||||||
|
|||||||
@ -39,13 +39,15 @@ LLVM_ABI bool opt(const Config &Conf, TargetMachine *TM, unsigned Task,
|
|||||||
Module &Mod, bool IsThinLTO,
|
Module &Mod, bool IsThinLTO,
|
||||||
ModuleSummaryIndex *ExportSummary,
|
ModuleSummaryIndex *ExportSummary,
|
||||||
const ModuleSummaryIndex *ImportSummary,
|
const ModuleSummaryIndex *ImportSummary,
|
||||||
const std::vector<uint8_t> &CmdArgs);
|
const std::vector<uint8_t> &CmdArgs,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs);
|
||||||
|
|
||||||
/// Runs a regular LTO backend. The regular LTO backend can also act as the
|
/// 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.
|
/// regular LTO phase of ThinLTO, which may need to access the combined index.
|
||||||
LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream,
|
LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream,
|
||||||
unsigned ParallelCodeGenParallelismLevel, Module &M,
|
unsigned ParallelCodeGenParallelismLevel, Module &M,
|
||||||
ModuleSummaryIndex &CombinedIndex);
|
ModuleSummaryIndex &CombinedIndex,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs);
|
||||||
|
|
||||||
/// Runs a ThinLTO backend.
|
/// Runs a ThinLTO backend.
|
||||||
/// If \p ModuleMap is not nullptr, all the module files to be imported have
|
/// If \p ModuleMap is not nullptr, all the module files to be imported have
|
||||||
@ -56,14 +58,14 @@ LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream,
|
|||||||
/// the backend will skip optimization and only perform code generation. If
|
/// the backend will skip optimization and only perform code generation. If
|
||||||
/// \p IRAddStream is not nullptr, it will be called just before code generation
|
/// \p IRAddStream is not nullptr, it will be called just before code generation
|
||||||
/// to serialize the optimized IR.
|
/// to serialize the optimized IR.
|
||||||
LLVM_ABI Error
|
LLVM_ABI Error thinBackend(
|
||||||
thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
|
const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
|
||||||
const ModuleSummaryIndex &CombinedIndex,
|
const ModuleSummaryIndex &CombinedIndex,
|
||||||
const FunctionImporter::ImportMapTy &ImportList,
|
const FunctionImporter::ImportMapTy &ImportList,
|
||||||
const GVSummaryMapTy &DefinedGlobals,
|
const GVSummaryMapTy &DefinedGlobals,
|
||||||
MapVector<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
|
MapVector<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
|
||||||
AddStreamFn IRAddStream = nullptr,
|
ArrayRef<StringRef> BitcodeLibFuncs, AddStreamFn IRAddStream = nullptr,
|
||||||
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
|
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
|
||||||
|
|
||||||
LLVM_ABI Error finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile);
|
LLVM_ABI Error finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile);
|
||||||
|
|
||||||
|
|||||||
@ -653,7 +653,11 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool InputFile::Symbol::isLibcall(
|
bool InputFile::Symbol::isLibcall(
|
||||||
|
const TargetLibraryInfo &TLI,
|
||||||
const RTLIB::RuntimeLibcallsInfo &Libcalls) const {
|
const RTLIB::RuntimeLibcallsInfo &Libcalls) const {
|
||||||
|
LibFunc F;
|
||||||
|
if (TLI.getLibFunc(IRName, F) && TLI.has(F))
|
||||||
|
return true;
|
||||||
return Libcalls.getSupportedLibcallImpl(IRName) != RTLIB::Unsupported;
|
return Libcalls.getSupportedLibcallImpl(IRName) != RTLIB::Unsupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,6 +719,8 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
|
|||||||
auto *ResE = Res.end();
|
auto *ResE = Res.end();
|
||||||
(void)ResE;
|
(void)ResE;
|
||||||
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
|
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
|
||||||
|
TargetLibraryInfoImpl TLII(TT);
|
||||||
|
TargetLibraryInfo TLI(TLII);
|
||||||
for (const InputFile::Symbol &Sym : Syms) {
|
for (const InputFile::Symbol &Sym : Syms) {
|
||||||
assert(ResI != ResE);
|
assert(ResI != ResE);
|
||||||
SymbolResolution Res = *ResI++;
|
SymbolResolution Res = *ResI++;
|
||||||
@ -757,7 +763,7 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
|
|||||||
GlobalRes.VisibleOutsideSummary = true;
|
GlobalRes.VisibleOutsideSummary = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsLibcall = Sym.isLibcall(Libcalls);
|
bool IsLibcall = Sym.isLibcall(TLI, Libcalls);
|
||||||
|
|
||||||
// Set the partition to external if we know it is re-defined by the linker
|
// 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
|
// with -defsym or -wrap options, used elsewhere, e.g. it is visible to a
|
||||||
@ -844,6 +850,12 @@ Error LTO::add(std::unique_ptr<InputFile> InputPtr,
|
|||||||
return Error::success();
|
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>>
|
Expected<ArrayRef<SymbolResolution>>
|
||||||
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
|
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
|
||||||
unsigned ModI, ArrayRef<SymbolResolution> Res) {
|
unsigned ModI, ArrayRef<SymbolResolution> Res) {
|
||||||
@ -1469,9 +1481,9 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) {
|
if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) {
|
||||||
if (Error Err =
|
if (Error Err = backend(
|
||||||
backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
|
Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
|
||||||
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex))
|
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex, BitcodeLibFuncs))
|
||||||
return Err;
|
return Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1491,6 +1503,20 @@ SmallVector<const char *> LTO::getRuntimeLibcallSymbols(const Triple &TT) {
|
|||||||
return LibcallSymbols;
|
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(
|
Error ThinBackendProc::emitFiles(
|
||||||
const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath,
|
const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath,
|
||||||
const std::string &NewModulePath) const {
|
const std::string &NewModulePath) const {
|
||||||
@ -1568,6 +1594,7 @@ protected:
|
|||||||
// generating directly into the returned output stream.
|
// generating directly into the returned output stream.
|
||||||
AddStreamFn AddStream;
|
AddStreamFn AddStream;
|
||||||
FileCache Cache;
|
FileCache Cache;
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InProcessThinBackend(
|
InProcessThinBackend(
|
||||||
@ -1575,11 +1602,13 @@ public:
|
|||||||
ThreadPoolStrategy ThinLTOParallelism,
|
ThreadPoolStrategy ThinLTOParallelism,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite,
|
AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite,
|
||||||
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles)
|
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs)
|
||||||
: CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries, OnWrite,
|
: CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries, OnWrite,
|
||||||
ShouldEmitIndexFiles, ShouldEmitImportsFiles,
|
ShouldEmitIndexFiles, ShouldEmitImportsFiles,
|
||||||
ThinLTOParallelism),
|
ThinLTOParallelism),
|
||||||
AddStream(std::move(AddStream)), Cache(std::move(Cache)) {}
|
AddStream(std::move(AddStream)), Cache(std::move(Cache)),
|
||||||
|
BitcodeLibFuncs(BitcodeLibFuncs) {}
|
||||||
|
|
||||||
virtual Error runThinLTOBackendThread(
|
virtual Error runThinLTOBackendThread(
|
||||||
AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM,
|
AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM,
|
||||||
@ -1600,7 +1629,7 @@ public:
|
|||||||
|
|
||||||
return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
|
return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
|
||||||
ImportList, DefinedGlobals, &ModuleMap,
|
ImportList, DefinedGlobals, &ModuleMap,
|
||||||
Conf.CodeGenOnly);
|
Conf.CodeGenOnly, BitcodeLibFuncs);
|
||||||
};
|
};
|
||||||
if (ShouldEmitIndexFiles) {
|
if (ShouldEmitIndexFiles) {
|
||||||
if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str()))
|
if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str()))
|
||||||
@ -1685,13 +1714,14 @@ public:
|
|||||||
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
||||||
ThreadPoolStrategy ThinLTOParallelism,
|
ThreadPoolStrategy ThinLTOParallelism,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn CGAddStream, FileCache CGCache, AddStreamFn IRAddStream,
|
AddStreamFn CGAddStream, FileCache CGCache,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs, AddStreamFn IRAddStream,
|
||||||
FileCache IRCache)
|
FileCache IRCache)
|
||||||
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
|
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
|
||||||
ModuleToDefinedGVSummaries, std::move(CGAddStream),
|
ModuleToDefinedGVSummaries, std::move(CGAddStream),
|
||||||
std::move(CGCache), /*OnWrite=*/nullptr,
|
std::move(CGCache), /*OnWrite=*/nullptr,
|
||||||
/*ShouldEmitIndexFiles=*/false,
|
/*ShouldEmitIndexFiles=*/false,
|
||||||
/*ShouldEmitImportsFiles=*/false),
|
/*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs),
|
||||||
IRAddStream(std::move(IRAddStream)), IRCache(std::move(IRCache)) {}
|
IRAddStream(std::move(IRAddStream)), IRCache(std::move(IRCache)) {}
|
||||||
|
|
||||||
Error runThinLTOBackendThread(
|
Error runThinLTOBackendThread(
|
||||||
@ -1714,7 +1744,7 @@ public:
|
|||||||
|
|
||||||
return thinBackend(Conf, Task, CGAddStream, **MOrErr, CombinedIndex,
|
return thinBackend(Conf, Task, CGAddStream, **MOrErr, CombinedIndex,
|
||||||
ImportList, DefinedGlobals, &ModuleMap,
|
ImportList, DefinedGlobals, &ModuleMap,
|
||||||
Conf.CodeGenOnly, IRAddStream);
|
Conf.CodeGenOnly, BitcodeLibFuncs, IRAddStream);
|
||||||
};
|
};
|
||||||
// Like InProcessThinBackend, we produce index files as needed for
|
// Like InProcessThinBackend, we produce index files as needed for
|
||||||
// FirstRoundThinBackend. However, these files are not generated for
|
// FirstRoundThinBackend. However, these files are not generated for
|
||||||
@ -1781,6 +1811,7 @@ public:
|
|||||||
ThreadPoolStrategy ThinLTOParallelism,
|
ThreadPoolStrategy ThinLTOParallelism,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn AddStream, FileCache Cache,
|
AddStreamFn AddStream, FileCache Cache,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs,
|
||||||
std::unique_ptr<SmallVector<StringRef>> IRFiles,
|
std::unique_ptr<SmallVector<StringRef>> IRFiles,
|
||||||
stable_hash CombinedCGDataHash)
|
stable_hash CombinedCGDataHash)
|
||||||
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
|
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
|
||||||
@ -1788,7 +1819,7 @@ public:
|
|||||||
std::move(Cache),
|
std::move(Cache),
|
||||||
/*OnWrite=*/nullptr,
|
/*OnWrite=*/nullptr,
|
||||||
/*ShouldEmitIndexFiles=*/false,
|
/*ShouldEmitIndexFiles=*/false,
|
||||||
/*ShouldEmitImportsFiles=*/false),
|
/*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs),
|
||||||
IRFiles(std::move(IRFiles)), CombinedCGDataHash(CombinedCGDataHash) {}
|
IRFiles(std::move(IRFiles)), CombinedCGDataHash(CombinedCGDataHash) {}
|
||||||
|
|
||||||
Error runThinLTOBackendThread(
|
Error runThinLTOBackendThread(
|
||||||
@ -1809,7 +1840,7 @@ public:
|
|||||||
|
|
||||||
return thinBackend(Conf, Task, AddStream, *LoadedModule, CombinedIndex,
|
return thinBackend(Conf, Task, AddStream, *LoadedModule, CombinedIndex,
|
||||||
ImportList, DefinedGlobals, &ModuleMap,
|
ImportList, DefinedGlobals, &ModuleMap,
|
||||||
/*CodeGenOnly=*/true);
|
/*CodeGenOnly=*/true, BitcodeLibFuncs);
|
||||||
};
|
};
|
||||||
if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) ||
|
if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) ||
|
||||||
all_of(CombinedIndex.getModuleHash(ModuleID),
|
all_of(CombinedIndex.getModuleHash(ModuleID),
|
||||||
@ -1848,11 +1879,12 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
|
|||||||
auto Func =
|
auto Func =
|
||||||
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn AddStream, FileCache Cache) {
|
AddStreamFn AddStream, FileCache Cache,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs) {
|
||||||
return std::make_unique<InProcessThinBackend>(
|
return std::make_unique<InProcessThinBackend>(
|
||||||
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
||||||
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
|
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
|
||||||
ShouldEmitImportsFiles);
|
ShouldEmitImportsFiles, BitcodeLibFuncs);
|
||||||
};
|
};
|
||||||
return ThinBackend(Func, Parallelism);
|
return ThinBackend(Func, Parallelism);
|
||||||
}
|
}
|
||||||
@ -1969,7 +2001,8 @@ ThinBackend lto::createWriteIndexesThinBackend(
|
|||||||
auto Func =
|
auto Func =
|
||||||
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn AddStream, FileCache Cache) {
|
AddStreamFn AddStream, FileCache Cache,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs) {
|
||||||
return std::make_unique<WriteIndexesThinBackend>(
|
return std::make_unique<WriteIndexesThinBackend>(
|
||||||
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
||||||
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
|
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
|
||||||
@ -2222,7 +2255,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
|
|||||||
if (!CodeGenDataThinLTOTwoRounds) {
|
if (!CodeGenDataThinLTOTwoRounds) {
|
||||||
std::unique_ptr<ThinBackendProc> BackendProc =
|
std::unique_ptr<ThinBackendProc> BackendProc =
|
||||||
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
|
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
|
||||||
AddStream, Cache);
|
AddStream, Cache, BitcodeLibFuncs);
|
||||||
return RunBackends(BackendProc.get());
|
return RunBackends(BackendProc.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2245,7 +2278,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
|
|||||||
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n");
|
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n");
|
||||||
auto FirstRoundLTO = std::make_unique<FirstRoundThinBackend>(
|
auto FirstRoundLTO = std::make_unique<FirstRoundThinBackend>(
|
||||||
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
||||||
CG.AddStream, CG.Cache, IR.AddStream, IR.Cache);
|
CG.AddStream, CG.Cache, BitcodeLibFuncs, IR.AddStream, IR.Cache);
|
||||||
if (Error E = RunBackends(FirstRoundLTO.get()))
|
if (Error E = RunBackends(FirstRoundLTO.get()))
|
||||||
return E;
|
return E;
|
||||||
|
|
||||||
@ -2261,7 +2294,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
|
|||||||
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n");
|
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n");
|
||||||
auto SecondRoundLTO = std::make_unique<SecondRoundThinBackend>(
|
auto SecondRoundLTO = std::make_unique<SecondRoundThinBackend>(
|
||||||
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
|
||||||
AddStream, Cache, IR.getResult(), CombinedHash);
|
AddStream, Cache, BitcodeLibFuncs, IR.getResult(), CombinedHash);
|
||||||
return RunBackends(SecondRoundLTO.get());
|
return RunBackends(SecondRoundLTO.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2768,7 +2801,7 @@ ThinBackend lto::createOutOfProcessThinBackend(
|
|||||||
auto Func =
|
auto Func =
|
||||||
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
|
||||||
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
|
||||||
AddStreamFn, FileCache Cache) {
|
AddStreamFn, FileCache Cache, ArrayRef<StringRef> BitcodeLibFuncs) {
|
||||||
return std::make_unique<OutOfProcessThinBackend>(
|
return std::make_unique<OutOfProcessThinBackend>(
|
||||||
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, Cache,
|
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries, Cache,
|
||||||
OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles,
|
OnWrite, ShouldEmitIndexFiles, ShouldEmitImportsFiles,
|
||||||
|
|||||||
@ -259,7 +259,8 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) {
|
|||||||
static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
|
static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
|
||||||
unsigned OptLevel, bool IsThinLTO,
|
unsigned OptLevel, bool IsThinLTO,
|
||||||
ModuleSummaryIndex *ExportSummary,
|
ModuleSummaryIndex *ExportSummary,
|
||||||
const ModuleSummaryIndex *ImportSummary) {
|
const ModuleSummaryIndex *ImportSummary,
|
||||||
|
const DenseSet<StringRef> &BitcodeLibFuncs) {
|
||||||
std::optional<PGOOptions> PGOOpt;
|
std::optional<PGOOptions> PGOOpt;
|
||||||
if (!Conf.SampleProfile.empty())
|
if (!Conf.SampleProfile.empty())
|
||||||
PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping,
|
PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping,
|
||||||
@ -301,6 +302,20 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
|
|||||||
new TargetLibraryInfoImpl(TM->getTargetTriple(), TM->Options.VecLib));
|
new TargetLibraryInfoImpl(TM->getTargetTriple(), TM->Options.VecLib));
|
||||||
if (Conf.Freestanding)
|
if (Conf.Freestanding)
|
||||||
TLII->disableAllFunctions();
|
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); });
|
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
|
||||||
|
|
||||||
// Parse a custom AA pipeline if asked to.
|
// Parse a custom AA pipeline if asked to.
|
||||||
@ -384,7 +399,8 @@ static bool isEmptyModule(const Module &Mod) {
|
|||||||
bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
|
bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
|
||||||
bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
|
bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
|
||||||
const ModuleSummaryIndex *ImportSummary,
|
const ModuleSummaryIndex *ImportSummary,
|
||||||
const std::vector<uint8_t> &CmdArgs) {
|
const std::vector<uint8_t> &CmdArgs,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs) {
|
||||||
llvm::TimeTraceScope timeScope("opt");
|
llvm::TimeTraceScope timeScope("opt");
|
||||||
if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) {
|
if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) {
|
||||||
// FIXME: the motivation for capturing post-merge bitcode and command line
|
// FIXME: the motivation for capturing post-merge bitcode and command line
|
||||||
@ -409,9 +425,11 @@ 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
|
// 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.
|
// regular LTO combined module, with a large combined index from ThinLTO.
|
||||||
if (!isEmptyModule(Mod)) {
|
if (!isEmptyModule(Mod)) {
|
||||||
|
DenseSet<StringRef> BitcodeLibFuncsSet(BitcodeLibFuncs.begin(),
|
||||||
|
BitcodeLibFuncs.end());
|
||||||
// FIXME: Plumb the combined index into the new pass manager.
|
// FIXME: Plumb the combined index into the new pass manager.
|
||||||
runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary,
|
runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary,
|
||||||
ImportSummary);
|
ImportSummary, BitcodeLibFuncsSet);
|
||||||
}
|
}
|
||||||
return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
|
return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod);
|
||||||
}
|
}
|
||||||
@ -577,7 +595,8 @@ Error lto::finalizeOptimizationRemarks(LLVMRemarkFileHandle DiagOutputFile) {
|
|||||||
|
|
||||||
Error lto::backend(const Config &C, AddStreamFn AddStream,
|
Error lto::backend(const Config &C, AddStreamFn AddStream,
|
||||||
unsigned ParallelCodeGenParallelismLevel, Module &Mod,
|
unsigned ParallelCodeGenParallelismLevel, Module &Mod,
|
||||||
ModuleSummaryIndex &CombinedIndex) {
|
ModuleSummaryIndex &CombinedIndex,
|
||||||
|
ArrayRef<StringRef> BitcodeLibFuncs) {
|
||||||
llvm::TimeTraceScope timeScope("LTO backend");
|
llvm::TimeTraceScope timeScope("LTO backend");
|
||||||
Expected<const Target *> TOrErr = initAndLookupTarget(C, Mod);
|
Expected<const Target *> TOrErr = initAndLookupTarget(C, Mod);
|
||||||
if (!TOrErr)
|
if (!TOrErr)
|
||||||
@ -589,7 +608,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream,
|
|||||||
if (!C.CodeGenOnly) {
|
if (!C.CodeGenOnly) {
|
||||||
if (!opt(C, TM.get(), 0, Mod, /*IsThinLTO=*/false,
|
if (!opt(C, TM.get(), 0, Mod, /*IsThinLTO=*/false,
|
||||||
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
|
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
|
||||||
/*CmdArgs*/ std::vector<uint8_t>()))
|
/*CmdArgs*/ std::vector<uint8_t>(), BitcodeLibFuncs))
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,7 +648,8 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
|
|||||||
const FunctionImporter::ImportMapTy &ImportList,
|
const FunctionImporter::ImportMapTy &ImportList,
|
||||||
const GVSummaryMapTy &DefinedGlobals,
|
const GVSummaryMapTy &DefinedGlobals,
|
||||||
MapVector<StringRef, BitcodeModule> *ModuleMap,
|
MapVector<StringRef, BitcodeModule> *ModuleMap,
|
||||||
bool CodeGenOnly, AddStreamFn IRAddStream,
|
bool CodeGenOnly, ArrayRef<StringRef> BitcodeLibFuncs,
|
||||||
|
AddStreamFn IRAddStream,
|
||||||
const std::vector<uint8_t> &CmdArgs) {
|
const std::vector<uint8_t> &CmdArgs) {
|
||||||
llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier());
|
llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier());
|
||||||
Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
|
Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
|
||||||
@ -668,7 +688,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
|
|||||||
// Perform optimization and code generation for ThinLTO.
|
// Perform optimization and code generation for ThinLTO.
|
||||||
if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true,
|
if (!opt(Conf, TM, Task, Mod, /*IsThinLTO=*/true,
|
||||||
/*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex,
|
/*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex,
|
||||||
CmdArgs))
|
CmdArgs, BitcodeLibFuncs))
|
||||||
return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
|
return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
|
||||||
|
|
||||||
// Save the current module before the first codegen round.
|
// Save the current module before the first codegen round.
|
||||||
|
|||||||
@ -614,7 +614,7 @@ bool LTOCodeGenerator::optimize() {
|
|||||||
TargetMach = createTargetMachine();
|
TargetMach = createTargetMachine();
|
||||||
if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false,
|
if (!opt(Config, TargetMach.get(), 0, *MergedModule, /*IsThinLTO=*/false,
|
||||||
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
|
/*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr,
|
||||||
/*CmdArgs*/ std::vector<uint8_t>())) {
|
/*CmdArgs*/ std::vector<uint8_t>(), /*BitcodeLibFuncs=*/{})) {
|
||||||
emitError("LTO middle-end optimizations failed");
|
emitError("LTO middle-end optimizations failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -639,7 +639,7 @@ bool LTOCodeGenerator::compileOptimized(AddStreamFn AddStream,
|
|||||||
|
|
||||||
Config.CodeGenOnly = true;
|
Config.CodeGenOnly = true;
|
||||||
Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule,
|
Error Err = backend(Config, AddStream, ParallelismLevel, *MergedModule,
|
||||||
CombinedIndex);
|
CombinedIndex, /*BitcodeLibFuncs=*/{});
|
||||||
assert(!Err && "unexpected code-generation failure");
|
assert(!Err && "unexpected code-generation failure");
|
||||||
(void)Err;
|
(void)Err;
|
||||||
|
|
||||||
|
|||||||
@ -292,8 +292,10 @@ addUsedSymbolToPreservedGUID(const lto::InputFile &File,
|
|||||||
DenseSet<GlobalValue::GUID> &PreservedGUID) {
|
DenseSet<GlobalValue::GUID> &PreservedGUID) {
|
||||||
Triple TT(File.getTargetTriple());
|
Triple TT(File.getTargetTriple());
|
||||||
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
|
RTLIB::RuntimeLibcallsInfo Libcalls(TT);
|
||||||
|
TargetLibraryInfoImpl TLII(TT);
|
||||||
|
TargetLibraryInfo TLI(TLII);
|
||||||
for (const auto &Sym : File.symbols())
|
for (const auto &Sym : File.symbols())
|
||||||
if (Sym.isUsed() || Sym.isLibcall(Libcalls))
|
if (Sym.isUsed() || Sym.isLibcall(TLI, Libcalls))
|
||||||
PreservedGUID.insert(
|
PreservedGUID.insert(
|
||||||
GlobalValue::getGUIDAssumingExternalLinkage(Sym.getIRName()));
|
GlobalValue::getGUIDAssumingExternalLinkage(Sym.getIRName()));
|
||||||
}
|
}
|
||||||
|
|||||||
25
llvm/test/LTO/Resolution/X86/libcall-external.ll
Normal file
25
llvm/test/LTO/Resolution/X86/libcall-external.ll
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
;; 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)
|
||||||
35
llvm/test/LTO/Resolution/X86/libcall-in-thin-link.ll
Normal file
35
llvm/test/LTO/Resolution/X86/libcall-in-thin-link.ll
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
;; 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)
|
||||||
|
|
||||||
34
llvm/test/LTO/Resolution/X86/libcall-in-tu.ll
Normal file
34
llvm/test/LTO/Resolution/X86/libcall-in-tu.ll
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
;; 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
|
||||||
|
}
|
||||||
|
|
||||||
@ -234,6 +234,19 @@ static cl::opt<bool>
|
|||||||
AllVtablesHaveTypeInfos("all-vtables-have-type-infos", cl::Hidden,
|
AllVtablesHaveTypeInfos("all-vtables-have-type-infos", cl::Hidden,
|
||||||
cl::desc("All vtables have type infos"));
|
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<bool> TimeTrace("time-trace", cl::desc("Record time trace"));
|
||||||
|
|
||||||
static cl::opt<unsigned> TimeTraceGranularity(
|
static cl::opt<unsigned> TimeTraceGranularity(
|
||||||
@ -514,6 +527,9 @@ static int run(int argc, char **argv) {
|
|||||||
if (HasErrors)
|
if (HasErrors)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
Lto.setBitcodeLibFuncs(
|
||||||
|
SmallVector<StringRef>(BitcodeLibFuncs.begin(), BitcodeLibFuncs.end()));
|
||||||
|
|
||||||
FileCache Cache;
|
FileCache Cache;
|
||||||
if (!CacheDir.empty())
|
if (!CacheDir.empty())
|
||||||
Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),
|
Cache = check(localCache("ThinLTO", "Thin", CacheDir, AddBuffer),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user