Skip to content

Commit ec0c85d

Browse files
committed
[LTO][LLD] Prevent invalid LTO libfunc transforms
This patch ensures that: 1) New bitcode is not extracted for libfuncs after LTO occurs, and 2) Extracted bitcode for libfuncs is considered external, since new calls to it may be emitted.
1 parent 89206de commit ec0c85d

File tree

15 files changed

+261
-37
lines changed

15 files changed

+261
-37
lines changed

lld/ELF/Driver.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2701,15 +2701,30 @@ static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) {
27012701
template <class ELFT>
27022702
void LinkerDriver::compileBitcodeFiles(bool skipLinkedOutput) {
27032703
llvm::TimeTraceScope timeScope("LTO");
2704+
// Capture the triple before moving the bitcode into the bitcode compiler.
2705+
std::optional<llvm::Triple> tt;
2706+
if (!ctx.bitcodeFiles.empty())
2707+
tt = llvm::Triple(ctx.bitcodeFiles.front()->obj->getTargetTriple());
27042708
// Compile bitcode files and replace bitcode symbols.
27052709
lto.reset(new BitcodeCompiler(ctx));
27062710
for (BitcodeFile *file : ctx.bitcodeFiles)
27072711
lto->add(*file);
27082712

2709-
if (!ctx.bitcodeFiles.empty())
2713+
llvm::BumpPtrAllocator alloc;
2714+
llvm::StringSaver saver(alloc);
2715+
SmallVector<StringRef> bitcodeLibFuncs;
2716+
if (!ctx.bitcodeFiles.empty()) {
27102717
markBuffersAsDontNeed(ctx, skipLinkedOutput);
2718+
for (StringRef libFunc : lto::LTO::getLibFuncSymbols(*tt, saver)) {
2719+
Symbol *sym = ctx.symtab->find(libFunc);
2720+
if (!sym)
2721+
continue;
2722+
if (isa<BitcodeFile>(sym->file))
2723+
bitcodeLibFuncs.push_back(libFunc);
2724+
}
2725+
}
27112726

2712-
ltoObjectFiles = lto->compile();
2727+
ltoObjectFiles = lto->compile(bitcodeLibFuncs);
27132728
for (auto &file : ltoObjectFiles) {
27142729
auto *obj = cast<ObjFile<ELFT>>(file.get());
27152730
obj->parse(/*ignoreComdats=*/true);

lld/ELF/LTO.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,10 @@ static void thinLTOCreateEmptyIndexFiles(Ctx &ctx) {
311311

312312
// Merge all the bitcode files we have seen, codegen the result
313313
// and return the resulting ObjectFile(s).
314-
SmallVector<std::unique_ptr<InputFile>, 0> BitcodeCompiler::compile() {
314+
SmallVector<std::unique_ptr<InputFile>, 0>
315+
BitcodeCompiler::compile(const SmallVector<StringRef> &bitcodeLibFuncs) {
316+
ltoObj->setBitcodeLibFuncs(bitcodeLibFuncs);
317+
315318
unsigned maxTasks = ltoObj->getMaxTasks();
316319
buf.resize(maxTasks);
317320
files.resize(maxTasks);

lld/ELF/LTO.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ class BitcodeCompiler {
4242
~BitcodeCompiler();
4343

4444
void add(BitcodeFile &f);
45-
SmallVector<std::unique_ptr<InputFile>, 0> compile();
45+
SmallVector<std::unique_ptr<InputFile>, 0>
46+
compile(const SmallVector<StringRef> &bitcodeLibFuncs);
4647

4748
private:
4849
Ctx &ctx;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; REQUIRES: x86
2+
3+
; RUN: rm -rf %t && split-file %s %t && cd %t
4+
; RUN: llvm-as main.ll -o main.o
5+
; RUN: llvm-as bcmp.ll -o bcmp.o
6+
; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu memcmp.s -o memcmp.o
7+
; RUN: llvm-ar rc libc.a bcmp.o memcmp.o
8+
9+
;; Ensure that no memcmp->bcmp translation occurs during LTO because bcmp is in
10+
;; bitcode, but was not brought into the link. This would fail the link by
11+
;; extracting bitcode after LTO.
12+
; RUN: ld.lld -o out main.o -L. -lc
13+
; RUN: llvm-nm out | FileCheck %s
14+
15+
;--- bcmp.ll
16+
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"
17+
target triple = "x86_64-unknown-linux-gnu"
18+
19+
define i32 @bcmp(ptr %0, ptr %1, i64 %2) {
20+
ret i32 0
21+
}
22+
23+
;--- memcmp.s
24+
.globl memcmp
25+
memcmp:
26+
ret
27+
28+
;--- main.ll
29+
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"
30+
target triple = "x86_64-unknown-linux-gnu"
31+
32+
define i1 @_start(ptr %0, ptr %1, i64 %2) {
33+
%cmp = call i32 @memcmp(ptr %0, ptr %1, i64 %2)
34+
%eq = icmp eq i32 %cmp, 0
35+
ret i1 %eq
36+
}
37+
38+
; CHECK-NOT: bcmp
39+
; CHECK: memcmp
40+
declare i32 @memcmp(ptr, ptr, i64)
41+

llvm/include/llvm/LTO/LTO.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ class ThinBackendProc {
264264
using ThinBackendFunction = std::function<std::unique_ptr<ThinBackendProc>(
265265
const Config &C, ModuleSummaryIndex &CombinedIndex,
266266
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
267-
AddStreamFn AddStream, FileCache Cache)>;
267+
AddStreamFn AddStream, FileCache Cache,
268+
const SmallVector<StringRef> &BitcodeLibFuncs)>;
268269

269270
/// This type defines the behavior following the thin-link phase during ThinLTO.
270271
/// It encapsulates a backend function and a strategy for thread pool
@@ -279,10 +280,11 @@ struct ThinBackend {
279280
std::unique_ptr<ThinBackendProc> operator()(
280281
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
281282
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
282-
AddStreamFn AddStream, FileCache Cache) {
283+
AddStreamFn AddStream, FileCache Cache,
284+
const SmallVector<StringRef> &BitcodeLibFuncs) {
283285
assert(isValid() && "Invalid backend function");
284286
return Func(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
285-
std::move(AddStream), std::move(Cache));
287+
std::move(AddStream), std::move(Cache), BitcodeLibFuncs);
286288
}
287289
ThreadPoolStrategy getParallelism() const { return Parallelism; }
288290
bool isValid() const { return static_cast<bool>(Func); }
@@ -400,6 +402,12 @@ class LTO {
400402
LLVM_ABI Error add(std::unique_ptr<InputFile> Obj,
401403
ArrayRef<SymbolResolution> Res);
402404

405+
/// Set the list of functions implemented in bitcode across the link, whether
406+
/// extracted or not. Such functions may not be referenced if they were not
407+
/// extracted by the time LTO occurs.
408+
LLVM_ABI void
409+
setBitcodeLibFuncs(const SmallVector<StringRef> &BitcodeLibFuncs);
410+
403411
/// Returns an upper bound on the number of tasks that the client may expect.
404412
/// This may only be called after all IR object files have been added. For a
405413
/// full description of tasks see LTOBackend.h.
@@ -420,6 +428,14 @@ class LTO {
420428
LLVM_ABI static SmallVector<const char *>
421429
getRuntimeLibcallSymbols(const Triple &TT);
422430

431+
/// Static method that returns a list of library function symbols that can be
432+
/// generated by LTO but might not be visible from bitcode symbol table.
433+
/// Unlike the runtime libcalls, the linker can report to the code generator
434+
/// which of these are actually available in the link, and the code generator
435+
/// can then only reference that set of symbols.
436+
LLVM_ABI static SmallVector<StringRef>
437+
getLibFuncSymbols(const Triple &TT, llvm::StringSaver &Saver);
438+
423439
private:
424440
Config Conf;
425441

@@ -591,6 +607,8 @@ class LTO {
591607

592608
// Diagnostic optimization remarks file
593609
LLVMRemarkFileHandle DiagnosticOutputFile;
610+
611+
SmallVector<StringRef> BitcodeLibFuncs;
594612
};
595613

596614
/// The resolution for a symbol. The linker must provide a SymbolResolution for

llvm/include/llvm/LTO/LTOBackend.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ LLVM_ABI bool opt(const Config &Conf, TargetMachine *TM, unsigned Task,
3939
Module &Mod, bool IsThinLTO,
4040
ModuleSummaryIndex *ExportSummary,
4141
const ModuleSummaryIndex *ImportSummary,
42-
const std::vector<uint8_t> &CmdArgs);
42+
const std::vector<uint8_t> &CmdArgs,
43+
const SmallVector<StringRef> &BitcodeLibFuncs);
4344

4445
/// Runs a regular LTO backend. The regular LTO backend can also act as the
4546
/// regular LTO phase of ThinLTO, which may need to access the combined index.
4647
LLVM_ABI Error backend(const Config &C, AddStreamFn AddStream,
4748
unsigned ParallelCodeGenParallelismLevel, Module &M,
48-
ModuleSummaryIndex &CombinedIndex);
49+
ModuleSummaryIndex &CombinedIndex,
50+
const SmallVector<StringRef> &BitcodeLibFuncs);
4951

5052
/// Runs a ThinLTO backend.
5153
/// If \p ModuleMap is not nullptr, all the module files to be imported have
@@ -62,6 +64,7 @@ thinBackend(const Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
6264
const FunctionImporter::ImportMapTy &ImportList,
6365
const GVSummaryMapTy &DefinedGlobals,
6466
MapVector<StringRef, BitcodeModule> *ModuleMap, bool CodeGenOnly,
67+
const SmallVector<StringRef> &BitcodeLibFuncs,
6568
AddStreamFn IRAddStream = nullptr,
6669
const std::vector<uint8_t> &CmdArgs = std::vector<uint8_t>());
6770

llvm/lib/LTO/LTO.cpp

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,10 @@ Error LTO::add(std::unique_ptr<InputFile> Input,
763763
return Error::success();
764764
}
765765

766+
void LTO::setBitcodeLibFuncs(const SmallVector<StringRef> &BitcodeLibFuncs) {
767+
this->BitcodeLibFuncs = BitcodeLibFuncs;
768+
}
769+
766770
Expected<ArrayRef<SymbolResolution>>
767771
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
768772
unsigned ModI, ArrayRef<SymbolResolution> Res) {
@@ -1385,9 +1389,9 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
13851389
}
13861390

13871391
if (!RegularLTO.EmptyCombinedModule || Conf.AlwaysEmitRegularLTOObj) {
1388-
if (Error Err =
1389-
backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
1390-
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex))
1392+
if (Error Err = backend(
1393+
Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
1394+
*RegularLTO.CombinedModule, ThinLTO.CombinedIndex, BitcodeLibFuncs))
13911395
return Err;
13921396
}
13931397

@@ -1407,6 +1411,21 @@ SmallVector<const char *> LTO::getRuntimeLibcallSymbols(const Triple &TT) {
14071411
return LibcallSymbols;
14081412
}
14091413

1414+
SmallVector<StringRef> LTO::getLibFuncSymbols(const Triple &TT,
1415+
StringSaver &Saver) {
1416+
auto TLII = std::make_unique<TargetLibraryInfoImpl>(TT);
1417+
TargetLibraryInfo TLI(*TLII);
1418+
SmallVector<StringRef> LibFuncSymbols;
1419+
LibFuncSymbols.reserve(LibFunc::NumLibFuncs);
1420+
for (unsigned I = 0, E = static_cast<unsigned>(LibFunc::NumLibFuncs); I != E;
1421+
++I) {
1422+
LibFunc F = static_cast<LibFunc>(I);
1423+
if (TLI.has(F))
1424+
LibFuncSymbols.push_back(Saver.save(TLI.getName(F)).data());
1425+
}
1426+
return LibFuncSymbols;
1427+
}
1428+
14101429
Error ThinBackendProc::emitFiles(
14111430
const FunctionImporter::ImportMapTy &ImportList, llvm::StringRef ModulePath,
14121431
const std::string &NewModulePath) const {
@@ -1484,18 +1503,20 @@ class CGThinBackend : public ThinBackendProc {
14841503
class InProcessThinBackend : public CGThinBackend {
14851504
protected:
14861505
FileCache Cache;
1506+
const SmallVector<StringRef> &BitcodeLibFuncs;
14871507

14881508
public:
14891509
InProcessThinBackend(
14901510
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
14911511
ThreadPoolStrategy ThinLTOParallelism,
14921512
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
14931513
AddStreamFn AddStream, FileCache Cache, lto::IndexWriteCallback OnWrite,
1494-
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles)
1514+
bool ShouldEmitIndexFiles, bool ShouldEmitImportsFiles,
1515+
const SmallVector<StringRef> &BitcodeLibFuncs)
14951516
: CGThinBackend(Conf, CombinedIndex, ModuleToDefinedGVSummaries,
14961517
AddStream, OnWrite, ShouldEmitIndexFiles,
14971518
ShouldEmitImportsFiles, ThinLTOParallelism),
1498-
Cache(std::move(Cache)) {}
1519+
Cache(std::move(Cache)), BitcodeLibFuncs(BitcodeLibFuncs) {}
14991520

15001521
virtual Error runThinLTOBackendThread(
15011522
AddStreamFn AddStream, FileCache Cache, unsigned Task, BitcodeModule BM,
@@ -1516,7 +1537,7 @@ class InProcessThinBackend : public CGThinBackend {
15161537

15171538
return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
15181539
ImportList, DefinedGlobals, &ModuleMap,
1519-
Conf.CodeGenOnly);
1540+
Conf.CodeGenOnly, BitcodeLibFuncs);
15201541
};
15211542
if (ShouldEmitIndexFiles) {
15221543
if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str()))
@@ -1601,13 +1622,14 @@ class FirstRoundThinBackend : public InProcessThinBackend {
16011622
const Config &Conf, ModuleSummaryIndex &CombinedIndex,
16021623
ThreadPoolStrategy ThinLTOParallelism,
16031624
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
1604-
AddStreamFn CGAddStream, FileCache CGCache, AddStreamFn IRAddStream,
1625+
AddStreamFn CGAddStream, FileCache CGCache,
1626+
const SmallVector<StringRef> &BitcodeLibFuncs, AddStreamFn IRAddStream,
16051627
FileCache IRCache)
16061628
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
16071629
ModuleToDefinedGVSummaries, std::move(CGAddStream),
16081630
std::move(CGCache), /*OnWrite=*/nullptr,
16091631
/*ShouldEmitIndexFiles=*/false,
1610-
/*ShouldEmitImportsFiles=*/false),
1632+
/*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs),
16111633
IRAddStream(std::move(IRAddStream)), IRCache(std::move(IRCache)) {}
16121634

16131635
Error runThinLTOBackendThread(
@@ -1630,7 +1652,7 @@ class FirstRoundThinBackend : public InProcessThinBackend {
16301652

16311653
return thinBackend(Conf, Task, CGAddStream, **MOrErr, CombinedIndex,
16321654
ImportList, DefinedGlobals, &ModuleMap,
1633-
Conf.CodeGenOnly, IRAddStream);
1655+
Conf.CodeGenOnly, BitcodeLibFuncs, IRAddStream);
16341656
};
16351657
// Like InProcessThinBackend, we produce index files as needed for
16361658
// FirstRoundThinBackend. However, these files are not generated for
@@ -1697,14 +1719,15 @@ class SecondRoundThinBackend : public InProcessThinBackend {
16971719
ThreadPoolStrategy ThinLTOParallelism,
16981720
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
16991721
AddStreamFn AddStream, FileCache Cache,
1722+
const SmallVector<StringRef> &BitcodeLibFuncs,
17001723
std::unique_ptr<SmallVector<StringRef>> IRFiles,
17011724
stable_hash CombinedCGDataHash)
17021725
: InProcessThinBackend(Conf, CombinedIndex, ThinLTOParallelism,
17031726
ModuleToDefinedGVSummaries, std::move(AddStream),
17041727
std::move(Cache),
17051728
/*OnWrite=*/nullptr,
17061729
/*ShouldEmitIndexFiles=*/false,
1707-
/*ShouldEmitImportsFiles=*/false),
1730+
/*ShouldEmitImportsFiles=*/false, BitcodeLibFuncs),
17081731
IRFiles(std::move(IRFiles)), CombinedCGDataHash(CombinedCGDataHash) {}
17091732

17101733
Error runThinLTOBackendThread(
@@ -1725,7 +1748,7 @@ class SecondRoundThinBackend : public InProcessThinBackend {
17251748

17261749
return thinBackend(Conf, Task, AddStream, *LoadedModule, CombinedIndex,
17271750
ImportList, DefinedGlobals, &ModuleMap,
1728-
/*CodeGenOnly=*/true);
1751+
/*CodeGenOnly=*/true, BitcodeLibFuncs);
17291752
};
17301753
if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) ||
17311754
all_of(CombinedIndex.getModuleHash(ModuleID),
@@ -1764,11 +1787,12 @@ ThinBackend lto::createInProcessThinBackend(ThreadPoolStrategy Parallelism,
17641787
auto Func =
17651788
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
17661789
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
1767-
AddStreamFn AddStream, FileCache Cache) {
1790+
AddStreamFn AddStream, FileCache Cache,
1791+
const SmallVector<StringRef> &BitcodeLibFuncs) {
17681792
return std::make_unique<InProcessThinBackend>(
17691793
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
17701794
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,
1771-
ShouldEmitImportsFiles);
1795+
ShouldEmitImportsFiles, BitcodeLibFuncs);
17721796
};
17731797
return ThinBackend(Func, Parallelism);
17741798
}
@@ -1885,7 +1909,8 @@ ThinBackend lto::createWriteIndexesThinBackend(
18851909
auto Func =
18861910
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
18871911
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
1888-
AddStreamFn AddStream, FileCache Cache) {
1912+
AddStreamFn AddStream, FileCache Cache,
1913+
const SmallVector<StringRef> &BitcodeLibFuncs) {
18891914
return std::make_unique<WriteIndexesThinBackend>(
18901915
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
18911916
OldPrefix, NewPrefix, NativeObjectPrefix, ShouldEmitImportsFiles,
@@ -2103,7 +2128,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
21032128
if (!CodeGenDataThinLTOTwoRounds) {
21042129
std::unique_ptr<ThinBackendProc> BackendProc =
21052130
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
2106-
AddStream, Cache);
2131+
AddStream, Cache, BitcodeLibFuncs);
21072132
return RunBackends(BackendProc.get());
21082133
}
21092134

@@ -2126,7 +2151,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
21262151
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the first round of codegen\n");
21272152
auto FirstRoundLTO = std::make_unique<FirstRoundThinBackend>(
21282153
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
2129-
CG.AddStream, CG.Cache, IR.AddStream, IR.Cache);
2154+
CG.AddStream, CG.Cache, BitcodeLibFuncs, IR.AddStream, IR.Cache);
21302155
if (Error E = RunBackends(FirstRoundLTO.get()))
21312156
return E;
21322157

@@ -2142,7 +2167,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
21422167
LLVM_DEBUG(dbgs() << "[TwoRounds] Running the second round of codegen\n");
21432168
auto SecondRoundLTO = std::make_unique<SecondRoundThinBackend>(
21442169
Conf, ThinLTO.CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
2145-
AddStream, Cache, IR.getResult(), CombinedHash);
2170+
AddStream, Cache, BitcodeLibFuncs, IR.getResult(), CombinedHash);
21462171
return RunBackends(SecondRoundLTO.get());
21472172
}
21482173

@@ -2620,7 +2645,8 @@ ThinBackend lto::createOutOfProcessThinBackend(
26202645
auto Func =
26212646
[=](const Config &Conf, ModuleSummaryIndex &CombinedIndex,
26222647
const DenseMap<StringRef, GVSummaryMapTy> &ModuleToDefinedGVSummaries,
2623-
AddStreamFn AddStream, FileCache Cache) {
2648+
AddStreamFn AddStream, FileCache Cache,
2649+
const SmallVector<StringRef> &BitcodeLibFuncs) {
26242650
return std::make_unique<OutOfProcessThinBackend>(
26252651
Conf, CombinedIndex, Parallelism, ModuleToDefinedGVSummaries,
26262652
AddStream, Cache, OnWrite, ShouldEmitIndexFiles,

0 commit comments

Comments
 (0)