Skip to content

Commit cde5e5b

Browse files
committed
refactor COFF linker to use new LTO API
Summary: The COFF linker previously implemented link-time optimization using an API which has now been marked as legacy. This change refactors the COFF linker to use the new LTO API, which is also used by the ELF linker. Reviewers: pcc, ruiu Reviewed By: pcc Subscribers: mgorny, mehdi_amini Differential Revision: https://reviews.llvm.org/D29059 llvm-svn: 293967
1 parent fbc229d commit cde5e5b

File tree

15 files changed

+373
-255
lines changed

15 files changed

+373
-255
lines changed

lld/COFF/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_lld_library(lldCOFF
1515
ICF.cpp
1616
InputFiles.cpp
1717
Librarian.cpp
18+
LTO.cpp
1819
MapFile.cpp
1920
MarkLive.cpp
2021
ModuleDef.cpp

lld/COFF/Config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ struct Configuration {
114114

115115
// Used for /opt:lldltojobs=N
116116
unsigned LTOJobs = 1;
117+
// Used for /opt:lldltopartitions=N
118+
unsigned LTOPartitions = 1;
117119

118120
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
119121
std::map<StringRef, StringRef> Merge;

lld/COFF/Driver.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
609609
fatal("/opt:lldltojobs: invalid job count: " + Jobs);
610610
continue;
611611
}
612+
if (StringRef(S).startswith("lldltopartitions=")) {
613+
StringRef N = StringRef(S).substr(17);
614+
if (N.getAsInteger(10, Config->LTOPartitions) ||
615+
Config->LTOPartitions == 0)
616+
fatal("/opt:lldltopartitions: invalid partition count: " + N);
617+
continue;
618+
}
612619
if (S != "ref" && S != "lbr" && S != "nolbr")
613620
fatal("/opt: unknown option: " + S);
614621
}

lld/COFF/InputFiles.cpp

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
#include "llvm/ADT/SmallVector.h"
2020
#include "llvm/ADT/Triple.h"
2121
#include "llvm/ADT/Twine.h"
22-
#include "llvm/IR/LLVMContext.h"
23-
#include "llvm/LTO/legacy/LTOModule.h"
22+
#include "llvm/Bitcode/BitcodeReader.h"
2423
#include "llvm/Object/Binary.h"
2524
#include "llvm/Object/COFF.h"
2625
#include "llvm/Support/COFF.h"
@@ -45,7 +44,19 @@ using llvm::support::ulittle32_t;
4544
namespace lld {
4645
namespace coff {
4746

48-
LLVMContext BitcodeFile::Context;
47+
/// Checks that Source is compatible with being a weak alias to Target.
48+
/// If Source is Undefined and has no weak alias set, makes it a weak
49+
/// alias to Target.
50+
static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
51+
SymbolBody *Source, SymbolBody *Target) {
52+
auto *U = dyn_cast<Undefined>(Source);
53+
if (!U)
54+
return;
55+
else if (!U->WeakAlias)
56+
U->WeakAlias = Target;
57+
else if (U->WeakAlias != Target)
58+
Symtab->reportDuplicate(Source->symbol(), F);
59+
}
4960

5061
ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
5162

@@ -175,15 +186,9 @@ void ObjectFile::initializeSymbols() {
175186
I += Sym.getNumberOfAuxSymbols();
176187
LastSectionNumber = Sym.getSectionNumber();
177188
}
178-
for (auto WeakAlias : WeakAliases) {
179-
auto *U = dyn_cast<Undefined>(WeakAlias.first);
180-
if (!U)
181-
continue;
182-
// Report an error if two undefined symbols have different weak aliases.
183-
if (U->WeakAlias && U->WeakAlias != SparseSymbolBodies[WeakAlias.second])
184-
Symtab->reportDuplicate(U->symbol(), this);
185-
U->WeakAlias = SparseSymbolBodies[WeakAlias.second];
186-
}
189+
for (auto WeakAlias : WeakAliases)
190+
checkAndSetWeakAlias(Symtab, this, WeakAlias.first,
191+
SparseSymbolBodies[WeakAlias.second]);
187192
}
188193

189194
SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) {
@@ -198,7 +203,10 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
198203
if (Sym.isCommon()) {
199204
auto *C = new (Alloc) CommonChunk(Sym);
200205
Chunks.push_back(C);
201-
return Symtab->addCommon(this, Sym, C)->body();
206+
COFFObj->getSymbolName(Sym, Name);
207+
Symbol *S =
208+
Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
209+
return S->body();
202210
}
203211
if (Sym.isAbsolute()) {
204212
COFFObj->getSymbolName(Sym, Name);
@@ -245,10 +253,14 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
245253
}
246254

247255
DefinedRegular *B;
248-
if (Sym.isExternal())
249-
B = cast<DefinedRegular>(Symtab->addRegular(this, Sym, SC)->body());
250-
else
251-
B = new (Alloc) DefinedRegular(this, Sym, SC);
256+
if (Sym.isExternal()) {
257+
COFFObj->getSymbolName(Sym, Name);
258+
Symbol *S =
259+
Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
260+
B = cast<DefinedRegular>(S->body());
261+
} else
262+
B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(),
263+
/*IsExternal*/ false, Sym.getGeneric(), SC);
252264
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
253265
SC->setSymbol(B);
254266

@@ -327,39 +339,38 @@ void ImportFile::parse() {
327339
}
328340

329341
void BitcodeFile::parse() {
330-
Context.enableDebugTypeODRUniquing();
331-
ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer(
332-
Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions());
333-
M = check(std::move(ModOrErr), "could not create LTO module");
334-
335-
StringSaver Saver(Alloc);
336-
for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
337-
lto_symbol_attributes Attrs = M->getSymbolAttributes(I);
338-
if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
339-
continue;
340-
341-
StringRef SymName = Saver.save(M->getSymbolName(I));
342-
int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK;
343-
if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) {
344-
SymbolBodies.push_back(Symtab->addUndefined(SymName, this, false)->body());
342+
Obj = check(lto::InputFile::create(
343+
MemoryBufferRef(MB.getBuffer(), Saver.save(MB.getBufferIdentifier()))));
344+
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
345+
StringRef SymName = Saver.save(ObjSym.getName());
346+
auto Flags = ObjSym.getFlags();
347+
Symbol *Sym;
348+
if (Flags & object::BasicSymbolRef::SF_Undefined) {
349+
Sym = Symtab->addUndefined(SymName, this, false);
350+
} else if (Flags & object::BasicSymbolRef::SF_Common) {
351+
Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
352+
} else if ((Flags & object::BasicSymbolRef::SF_Weak) &&
353+
(Flags & object::BasicSymbolRef::SF_Indirect)) {
354+
// Weak external.
355+
Sym = Symtab->addUndefined(SymName, this, true);
356+
std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
357+
SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback));
358+
checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias);
345359
} else {
346-
bool Replaceable =
347-
(SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common
348-
(Attrs & LTO_SYMBOL_COMDAT) || // comdat
349-
(SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external
350-
(Attrs & LTO_SYMBOL_ALIAS)));
351-
SymbolBodies.push_back(
352-
Symtab->addBitcode(this, SymName, Replaceable)->body());
360+
Expected<int> ComdatIndex = ObjSym.getComdatIndex();
361+
bool IsCOMDAT = ComdatIndex && *ComdatIndex != -1;
362+
Sym = Symtab->addRegular(this, SymName, IsCOMDAT);
353363
}
364+
SymbolBodies.push_back(Sym->body());
354365
}
355-
356-
Directives = M->getLinkerOpts();
366+
Directives = check(Obj->getLinkerOpts());
357367
}
358368

359369
MachineTypes BitcodeFile::getMachineType() {
360-
if (!M)
370+
Expected<std::string> ET = getBitcodeTargetTriple(MB);
371+
if (!ET)
361372
return IMAGE_FILE_MACHINE_UNKNOWN;
362-
switch (Triple(M->getTargetTriple()).getArch()) {
373+
switch (Triple(*ET).getArch()) {
363374
case Triple::x86_64:
364375
return AMD64;
365376
case Triple::x86:

lld/COFF/InputFiles.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
#include "lld/Core/LLVM.h"
1414
#include "llvm/ADT/ArrayRef.h"
1515
#include "llvm/ADT/DenseSet.h"
16-
#include "llvm/IR/LLVMContext.h"
17-
#include "llvm/LTO/legacy/LTOModule.h"
16+
#include "llvm/LTO/LTO.h"
1817
#include "llvm/Object/Archive.h"
1918
#include "llvm/Object/COFF.h"
2019
#include "llvm/Support/StringSaver.h"
@@ -25,7 +24,6 @@
2524
namespace lld {
2625
namespace coff {
2726

28-
using llvm::LTOModule;
2927
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
3028
using llvm::COFF::MachineTypes;
3129
using llvm::object::Archive;
@@ -191,16 +189,13 @@ class BitcodeFile : public InputFile {
191189
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
192190
std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; }
193191
MachineTypes getMachineType() override;
194-
std::unique_ptr<LTOModule> takeModule() { return std::move(M); }
195-
196-
static llvm::LLVMContext Context;
192+
std::unique_ptr<llvm::lto::InputFile> Obj;
197193

198194
private:
199195
void parse() override;
200196

201197
std::vector<SymbolBody *> SymbolBodies;
202198
llvm::BumpPtrAllocator Alloc;
203-
std::unique_ptr<LTOModule> M;
204199
};
205200
} // namespace coff
206201

lld/COFF/LTO.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//===- LTO.cpp ------------------------------------------------------------===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "LTO.h"
11+
#include "Config.h"
12+
#include "Error.h"
13+
#include "InputFiles.h"
14+
#include "Symbols.h"
15+
#include "lld/Core/TargetOptionsCommandFlags.h"
16+
#include "llvm/ADT/STLExtras.h"
17+
#include "llvm/ADT/SmallString.h"
18+
#include "llvm/ADT/StringRef.h"
19+
#include "llvm/ADT/Twine.h"
20+
#include "llvm/IR/DiagnosticPrinter.h"
21+
#include "llvm/LTO/Config.h"
22+
#include "llvm/LTO/LTO.h"
23+
#include "llvm/Object/SymbolicFile.h"
24+
#include "llvm/Support/CodeGen.h"
25+
#include "llvm/Support/Error.h"
26+
#include "llvm/Support/FileSystem.h"
27+
#include "llvm/Support/MemoryBuffer.h"
28+
#include "llvm/Support/raw_ostream.h"
29+
#include <algorithm>
30+
#include <cstddef>
31+
#include <memory>
32+
#include <string>
33+
#include <system_error>
34+
#include <vector>
35+
36+
using namespace llvm;
37+
using namespace llvm::object;
38+
39+
using namespace lld;
40+
using namespace lld::coff;
41+
42+
static void diagnosticHandler(const DiagnosticInfo &DI) {
43+
SmallString<128> ErrStorage;
44+
raw_svector_ostream OS(ErrStorage);
45+
DiagnosticPrinterRawOStream DP(OS);
46+
DI.print(DP);
47+
warn(ErrStorage);
48+
}
49+
50+
static void checkError(Error E) {
51+
handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
52+
error(EIB.message());
53+
return Error::success();
54+
});
55+
}
56+
57+
static std::unique_ptr<lto::LTO> createLTO() {
58+
lto::Config Conf;
59+
Conf.Options = InitTargetOptionsFromCodeGenFlags();
60+
Conf.RelocModel = Reloc::PIC_;
61+
Conf.DisableVerify = true;
62+
Conf.DiagHandler = diagnosticHandler;
63+
Conf.OptLevel = Config->LTOOptLevel;
64+
lto::ThinBackend Backend;
65+
if (Config->LTOJobs != -1u)
66+
Backend = lto::createInProcessThinBackend(Config->LTOJobs);
67+
return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
68+
Config->LTOPartitions);
69+
}
70+
71+
BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
72+
73+
BitcodeCompiler::~BitcodeCompiler() = default;
74+
75+
static void undefine(Symbol *S) {
76+
replaceBody<Undefined>(S, S->body()->getName());
77+
}
78+
79+
void BitcodeCompiler::add(BitcodeFile &F) {
80+
lto::InputFile &Obj = *F.Obj;
81+
unsigned SymNum = 0;
82+
std::vector<SymbolBody *> SymBodies = F.getSymbols();
83+
std::vector<lto::SymbolResolution> Resols(SymBodies.size());
84+
85+
// Provide a resolution to the LTO API for each symbol.
86+
for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
87+
SymbolBody *B = SymBodies[SymNum];
88+
Symbol *Sym = B->symbol();
89+
lto::SymbolResolution &R = Resols[SymNum];
90+
++SymNum;
91+
92+
// Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
93+
// reports two symbols for module ASM defined. Without this check, lld
94+
// flags an undefined in IR with a definition in ASM as prevailing.
95+
// Once IRObjectFile is fixed to report only one symbol this hack can
96+
// be removed.
97+
R.Prevailing =
98+
!(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
99+
B->getFile() == &F;
100+
R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
101+
if (R.Prevailing)
102+
undefine(Sym);
103+
}
104+
checkError(LTOObj->add(std::move(F.Obj), Resols));
105+
}
106+
107+
// Merge all the bitcode files we have seen, codegen the result
108+
// and return the resulting ObjectFile(s).
109+
std::vector<InputFile *> BitcodeCompiler::compile() {
110+
std::vector<InputFile *> Ret;
111+
unsigned MaxTasks = LTOObj->getMaxTasks();
112+
Buff.resize(MaxTasks);
113+
114+
checkError(LTOObj->run([&](size_t Task) {
115+
return llvm::make_unique<lto::NativeObjectStream>(
116+
llvm::make_unique<raw_svector_ostream>(Buff[Task]));
117+
}));
118+
119+
for (unsigned I = 0; I != MaxTasks; ++I) {
120+
if (Buff[I].empty())
121+
continue;
122+
Ret.push_back(make<ObjectFile>(MemoryBufferRef(Buff[I], "lto.tmp")));
123+
}
124+
return Ret;
125+
}

lld/COFF/LTO.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===- LTO.h ----------------------------------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Linker
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file provides a way to combine bitcode files into one COFF
11+
// file by compiling them using LLVM.
12+
//
13+
// If LTO is in use, your input files are not in regular COFF files
14+
// but instead LLVM bitcode files. In that case, the linker has to
15+
// convert bitcode files into the native format so that we can create
16+
// a COFF file that contains native code. This file provides that
17+
// functionality.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef LLD_COFF_LTO_H
22+
#define LLD_COFF_LTO_H
23+
24+
#include "lld/Core/LLVM.h"
25+
#include "llvm/ADT/SmallString.h"
26+
#include <memory>
27+
#include <vector>
28+
29+
namespace llvm {
30+
namespace lto {
31+
class LTO;
32+
}
33+
}
34+
35+
namespace lld {
36+
namespace coff {
37+
38+
class BitcodeFile;
39+
class InputFile;
40+
41+
class BitcodeCompiler {
42+
public:
43+
BitcodeCompiler();
44+
~BitcodeCompiler();
45+
46+
void add(BitcodeFile &F);
47+
std::vector<InputFile *> compile();
48+
49+
private:
50+
std::unique_ptr<llvm::lto::LTO> LTOObj;
51+
std::vector<SmallString<0>> Buff;
52+
};
53+
}
54+
}
55+
56+
#endif

0 commit comments

Comments
 (0)