Index: COFF/CMakeLists.txt =================================================================== --- COFF/CMakeLists.txt +++ COFF/CMakeLists.txt @@ -15,6 +15,7 @@ ICF.cpp InputFiles.cpp Librarian.cpp + LTO.cpp MapFile.cpp MarkLive.cpp ModuleDef.cpp Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -114,6 +114,8 @@ // Used for /opt:lldltojobs=N unsigned LTOJobs = 1; + // Used for /opt:lldltopartitions=N + unsigned LTOPartitions = 1; // Used for /merge:from=to (e.g. /merge:.rdata=.text) std::map Merge; Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -609,6 +609,13 @@ fatal("/opt:lldltojobs: invalid job count: " + Jobs); continue; } + if (StringRef(S).startswith("lldltopartitions=")) { + StringRef N = StringRef(S).substr(17); + if (N.getAsInteger(10, Config->LTOPartitions) || + Config->LTOPartitions == 0) + fatal("/opt:lldltopartitions: invalid partition count: " + N); + continue; + } if (S != "ref" && S != "lbr" && S != "nolbr") fatal("/opt: unknown option: " + S); } Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ COFF/InputFiles.h @@ -13,8 +13,7 @@ #include "lld/Core/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/LTO/legacy/LTOModule.h" +#include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFF.h" #include "llvm/Support/StringSaver.h" @@ -25,7 +24,6 @@ namespace lld { namespace coff { -using llvm::LTOModule; using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; using llvm::COFF::MachineTypes; using llvm::object::Archive; @@ -191,16 +189,13 @@ static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } std::vector &getSymbols() { return SymbolBodies; } MachineTypes getMachineType() override; - std::unique_ptr takeModule() { return std::move(M); } - - static llvm::LLVMContext Context; + std::unique_ptr Obj; private: void parse() override; std::vector SymbolBodies; llvm::BumpPtrAllocator Alloc; - std::unique_ptr M; }; } // namespace coff Index: COFF/InputFiles.cpp =================================================================== --- COFF/InputFiles.cpp +++ COFF/InputFiles.cpp @@ -19,8 +19,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/LTO/legacy/LTOModule.h" +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" #include "llvm/Support/COFF.h" @@ -45,7 +44,19 @@ namespace lld { namespace coff { -LLVMContext BitcodeFile::Context; +/// Checks that Source is compatible with being a weak alias to Target. +/// If Source is Undefined and has no weak alias set, makes it a weak +/// alias to Target. +static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F, + SymbolBody *Source, SymbolBody *Target) { + auto *U = dyn_cast(Source); + if (!U) + return; + else if (!U->WeakAlias) + U->WeakAlias = Target; + else if (U->WeakAlias != Target) + Symtab->reportDuplicate(Source->symbol(), F); +} ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} @@ -175,15 +186,9 @@ I += Sym.getNumberOfAuxSymbols(); LastSectionNumber = Sym.getSectionNumber(); } - for (auto WeakAlias : WeakAliases) { - auto *U = dyn_cast(WeakAlias.first); - if (!U) - continue; - // Report an error if two undefined symbols have different weak aliases. - if (U->WeakAlias && U->WeakAlias != SparseSymbolBodies[WeakAlias.second]) - Symtab->reportDuplicate(U->symbol(), this); - U->WeakAlias = SparseSymbolBodies[WeakAlias.second]; - } + for (auto WeakAlias : WeakAliases) + checkAndSetWeakAlias(Symtab, this, WeakAlias.first, + SparseSymbolBodies[WeakAlias.second]); } SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { @@ -198,7 +203,10 @@ if (Sym.isCommon()) { auto *C = new (Alloc) CommonChunk(Sym); Chunks.push_back(C); - return Symtab->addCommon(this, Sym, C)->body(); + COFFObj->getSymbolName(Sym, Name); + Symbol *S = + Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); + return S->body(); } if (Sym.isAbsolute()) { COFFObj->getSymbolName(Sym, Name); @@ -245,10 +253,14 @@ } DefinedRegular *B; - if (Sym.isExternal()) - B = cast(Symtab->addRegular(this, Sym, SC)->body()); - else - B = new (Alloc) DefinedRegular(this, Sym, SC); + if (Sym.isExternal()) { + COFFObj->getSymbolName(Sym, Name); + Symbol *S = + Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC); + B = cast(S->body()); + } else + B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(), + /*IsExternal*/ false, Sym.getGeneric(), SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); @@ -327,39 +339,42 @@ } void BitcodeFile::parse() { - Context.enableDebugTypeODRUniquing(); - ErrorOr> ModOrErr = LTOModule::createFromBuffer( - Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions()); - M = check(std::move(ModOrErr), "could not create LTO module"); - - StringSaver Saver(Alloc); - for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) { - lto_symbol_attributes Attrs = M->getSymbolAttributes(I); - if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) - continue; - - StringRef SymName = Saver.save(M->getSymbolName(I)); - int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK; - if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) { - SymbolBodies.push_back(Symtab->addUndefined(SymName, this, false)->body()); + Obj = check(lto::InputFile::create( + MemoryBufferRef(MB.getBuffer(), Saver.save(MB.getBufferIdentifier())))); + SmallVector, 8> WeakAliases; + for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { + StringRef SymName = Saver.save(ObjSym.getName()); + auto Flags = ObjSym.getFlags(); + Symbol *Sym; + if (Flags & object::BasicSymbolRef::SF_Undefined) { + Sym = Symtab->addUndefined(SymName, this, false); + } else if (Flags & object::BasicSymbolRef::SF_Common) { + Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize()); + } else if ((Flags & object::BasicSymbolRef::SF_Weak) && + (Flags & object::BasicSymbolRef::SF_Indirect)) { + // Weak external. + Sym = Symtab->addUndefined(SymName, this, true); + std::string Fallback = ObjSym.getCOFFWeakExternalFallback(); + WeakAliases.emplace_back(Sym->body(), Saver.save(Fallback)); } else { - bool Replaceable = - (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common - (Attrs & LTO_SYMBOL_COMDAT) || // comdat - (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external - (Attrs & LTO_SYMBOL_ALIAS))); - SymbolBodies.push_back( - Symtab->addBitcode(this, SymName, Replaceable)->body()); + Expected ComdatIndex = ObjSym.getComdatIndex(); + bool IsCOMDAT = ComdatIndex && *ComdatIndex != -1; + Sym = Symtab->addRegular(this, SymName, IsCOMDAT); } + SymbolBodies.push_back(Sym->body()); } + for (auto WeakAlias : WeakAliases) + checkAndSetWeakAlias(Symtab, this, WeakAlias.first, + Symtab->addUndefined(WeakAlias.second)); - Directives = M->getLinkerOpts(); + Directives = check(Obj->getLinkerOpts()); } MachineTypes BitcodeFile::getMachineType() { - if (!M) + Expected ET = getBitcodeTargetTriple(MB); + if (!ET) return IMAGE_FILE_MACHINE_UNKNOWN; - switch (Triple(M->getTargetTriple()).getArch()) { + switch (Triple(*ET).getArch()) { case Triple::x86_64: return AMD64; case Triple::x86: Index: COFF/LTO.h =================================================================== --- /dev/null +++ COFF/LTO.h @@ -0,0 +1,56 @@ +//===- LTO.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a way to combine bitcode files into one ELF +// file by compiling them using LLVM. +// +// If LTO is in use, your input files are not in regular ELF files +// but instead LLVM bitcode files. In that case, the linker has to +// convert bitcode files into the native format so that we can create +// an ELF file that contains native code. This file provides that +// functionality. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_LTO_H +#define LLD_COFF_LTO_H + +#include "lld/Core/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include +#include + +namespace llvm { +namespace lto { +class LTO; +} +} + +namespace lld { +namespace coff { + +class BitcodeFile; +class InputFile; + +class BitcodeCompiler { +public: + BitcodeCompiler(); + ~BitcodeCompiler(); + + void add(BitcodeFile &F); + std::vector compile(); + +private: + std::unique_ptr LTOObj; + std::vector> Buff; +}; +} +} + +#endif Index: COFF/LTO.cpp =================================================================== --- /dev/null +++ COFF/LTO.cpp @@ -0,0 +1,125 @@ +//===- LTO.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LTO.h" +#include "Config.h" +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "lld/Core/TargetOptionsCommandFlags.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/LTO/Config.h" +#include "llvm/LTO/LTO.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::object; + +using namespace lld; +using namespace lld::coff; + +static void diagnosticHandler(const DiagnosticInfo &DI) { + SmallString<128> ErrStorage; + raw_svector_ostream OS(ErrStorage); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + warn(ErrStorage); +} + +static void checkError(Error E) { + handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error { + error(EIB.message()); + return Error::success(); + }); +} + +static std::unique_ptr createLTO() { + lto::Config Conf; + Conf.Options = InitTargetOptionsFromCodeGenFlags(); + Conf.RelocModel = Reloc::PIC_; + Conf.DisableVerify = true; + Conf.DiagHandler = diagnosticHandler; + Conf.OptLevel = Config->LTOOptLevel; + lto::ThinBackend Backend; + if (Config->LTOJobs != -1u) + Backend = lto::createInProcessThinBackend(Config->LTOJobs); + return llvm::make_unique(std::move(Conf), Backend, + Config->LTOPartitions); +} + +BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} + +BitcodeCompiler::~BitcodeCompiler() = default; + +static void undefine(Symbol *S) { + replaceBody(S, S->body()->getName()); +} + +void BitcodeCompiler::add(BitcodeFile &F) { + lto::InputFile &Obj = *F.Obj; + unsigned SymNum = 0; + std::vector SymBodies = F.getSymbols(); + std::vector Resols(SymBodies.size()); + + // Provide a resolution to the LTO API for each symbol. + for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { + SymbolBody *B = SymBodies[SymNum]; + Symbol *Sym = B->symbol(); + lto::SymbolResolution &R = Resols[SymNum]; + ++SymNum; + + // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile + // reports two symbols for module ASM defined. Without this check, lld + // flags an undefined in IR with a definition in ASM as prevailing. + // Once IRObjectFile is fixed to report only one symbol this hack can + // be removed. + R.Prevailing = + !(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) && + B->getFile() == &F; + R.VisibleToRegularObj = Sym->IsUsedInRegularObj; + if (R.Prevailing) + undefine(Sym); + } + checkError(LTOObj->add(std::move(F.Obj), Resols)); +} + +// Merge all the bitcode files we have seen, codegen the result +// and return the resulting ObjectFile(s). +std::vector BitcodeCompiler::compile() { + std::vector Ret; + unsigned MaxTasks = LTOObj->getMaxTasks(); + Buff.resize(MaxTasks); + + checkError(LTOObj->run([&](size_t Task) { + return llvm::make_unique( + llvm::make_unique(Buff[Task])); + })); + + for (unsigned I = 0; I != MaxTasks; ++I) { + if (Buff[I].empty()) + continue; + Ret.push_back(make(MemoryBufferRef(Buff[I], "lto.tmp"))); + } + return Ret; +} Index: COFF/SymbolTable.h =================================================================== --- COFF/SymbolTable.h +++ COFF/SymbolTable.h @@ -11,6 +11,7 @@ #define LLD_COFF_SYMBOL_TABLE_H #include "InputFiles.h" +#include "LTO.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" @@ -90,9 +91,12 @@ Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); void addLazy(ArchiveFile *F, const Archive::Symbol Sym); Symbol *addAbsolute(StringRef N, COFFSymbolRef S); - Symbol *addRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C); - Symbol *addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable); - Symbol *addCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C); + Symbol *addRegular(InputFile *F, StringRef N, bool IsCOMDAT, + const llvm::object::coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr); + Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, + const llvm::object::coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr); Symbol *addImportData(StringRef N, ImportFile *F); Symbol *addImportThunk(StringRef Name, DefinedImportData *S, uint16_t Machine); @@ -110,12 +114,11 @@ StringRef findByPrefix(StringRef Prefix); void addCombinedLTOObject(ObjectFile *Obj); - std::vector createLTOObjects(llvm::LTOCodeGenerator *CG); llvm::DenseMap Symtab; std::vector BitcodeFiles; - std::vector> Objs; + std::unique_ptr LTO; }; extern SymbolTable *Symtab; Index: COFF/SymbolTable.cpp =================================================================== --- COFF/SymbolTable.cpp +++ COFF/SymbolTable.cpp @@ -11,10 +11,10 @@ #include "Config.h" #include "Driver.h" #include "Error.h" +#include "LTO.h" #include "Memory.h" #include "Symbols.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/LTO/legacy/LTOCodeGenerator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include @@ -24,6 +24,36 @@ namespace lld { namespace coff { +enum SymbolPreference { + SP_EXISTING = -1, + SP_CONFLICT = 0, + SP_NEW = 1, +}; + +/// Checks if an existing symbol S should be kept or replaced by a new symbol. +/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol +/// should be kept, and SP_CONFLICT if no valid resolution exists. +static SymbolPreference compareDefined(Symbol *S, bool WasInserted, + bool NewIsCOMDAT) { + // If the symbol wasn't previously known, the new symbol wins by default. + if (WasInserted || !isa(S->body())) + return SP_NEW; + + // If the existing symbol is a DefinedRegular, both it and the new symbol + // must be comdats. In that case, we have no reason to prefer one symbol + // over the other, and we keep the existing one. If one of the symbols + // is not a comdat, we report a conflict. + if (auto *R = dyn_cast(S->body())) { + if (NewIsCOMDAT && R->isCOMDAT()) + return SP_EXISTING; + else + return SP_CONFLICT; + } + + // Existing symbol is not a DefinedRegular; new symbol wins. + return SP_NEW; +} + SymbolTable *Symtab; void SymbolTable::addFile(InputFile *File) { @@ -204,59 +234,35 @@ return S; } -Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym, +Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT, + const coff_symbol_generic *Sym, SectionChunk *C) { - StringRef Name; - F->getCOFFObj()->getSymbolName(Sym, Name); - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - S->IsUsedInRegularObj = true; - if (WasInserted || isa(S->body()) || isa(S->body())) - replaceBody(S, F, Sym, C); - else if (auto *R = dyn_cast(S->body())) { - if (!C->isCOMDAT() || !R->isCOMDAT()) - reportDuplicate(S, F); - } else if (auto *B = dyn_cast(S->body())) { - if (B->IsReplaceable) - replaceBody(S, F, Sym, C); - else if (!C->isCOMDAT()) - reportDuplicate(S, F); - } else - replaceBody(S, F, Sym, C); - return S; -} - -Symbol *SymbolTable::addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); - if (WasInserted || isa(S->body()) || isa(S->body())) { - replaceBody(S, F, N, IsReplaceable); - return S; + if (!isa(F)) + S->IsUsedInRegularObj = true; + SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT); + if (SP == SP_CONFLICT) { + reportDuplicate(S, F); + } else if (SP == SP_NEW) { + replaceBody(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C); } - if (isa(S->body())) - return S; - if (IsReplaceable) - if (isa(S->body()) || isa(S->body())) - return S; - reportDuplicate(S, F); return S; } -Symbol *SymbolTable::addCommon(ObjectFile *F, COFFSymbolRef Sym, - CommonChunk *C) { - StringRef Name; - F->getCOFFObj()->getSymbolName(Sym, Name); +Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, + const coff_symbol_generic *Sym, CommonChunk *C) { Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - S->IsUsedInRegularObj = true; + std::tie(S, WasInserted) = insert(N); + if (!isa(F)) + S->IsUsedInRegularObj = true; if (WasInserted || !isa(S->body())) - replaceBody(S, F, Sym, C); + replaceBody(S, F, N, Size, Sym, C); else if (auto *DC = dyn_cast(S->body())) - if (Sym.getValue() > DC->getSize()) - replaceBody(S, F, Sym, C); + if (Size > DC->getSize()) + replaceBody(S, F, N, Size, Sym, C); return S; } @@ -349,61 +355,15 @@ if (BitcodeFiles.empty()) return; - // Create an object file and add it to the symbol table by replacing any - // DefinedBitcode symbols with the definitions in the object file. - LTOCodeGenerator CG(BitcodeFile::Context); - CG.setOptLevel(Config->LTOOptLevel); - for (ObjectFile *Obj : createLTOObjects(&CG)) - Obj->parse(); -} + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *F : BitcodeFiles) + LTO->add(*F); -// Combine and compile bitcode files and then return the result -// as a vector of regular COFF object files. -std::vector SymbolTable::createLTOObjects(LTOCodeGenerator *CG) { - // All symbols referenced by non-bitcode objects, including GC roots, must be - // preserved. We must also replace bitcode symbols with undefined symbols so - // that they may be replaced with real definitions without conflicting. - for (BitcodeFile *File : BitcodeFiles) - for (SymbolBody *Body : File->getSymbols()) { - if (!isa(Body)) - continue; - if (Body->symbol()->IsUsedInRegularObj) - CG->addMustPreserveSymbol(Body->getName()); - replaceBody(Body->symbol(), Body->getName()); - } - - CG->setModule(BitcodeFiles[0]->takeModule()); - for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I) - CG->addModule(BitcodeFiles[I]->takeModule().get()); - - bool DisableVerify = true; -#ifdef NDEBUG - DisableVerify = false; -#endif - if (!CG->optimize(DisableVerify, false, false, false)) - fatal(""); // optimize() should have emitted any error message. - - Objs.resize(Config->LTOJobs); - // Use std::list to avoid invalidation of pointers in OSPtrs. - std::list OSs; - std::vector OSPtrs; - for (SmallString<0> &Obj : Objs) { - OSs.emplace_back(Obj); - OSPtrs.push_back(&OSs.back()); - } - - if (!CG->compileOptimized(OSPtrs)) - fatal(""); // compileOptimized() should have emitted any error message. - - std::vector ObjFiles; - for (SmallString<0> &Obj : Objs) { - auto *ObjFile = make(MemoryBufferRef(Obj, "")); - ObjectFiles.push_back(ObjFile); - ObjFiles.push_back(ObjFile); + for (auto *File : LTO->compile()) { + auto *Obj = cast(File); + ObjectFiles.push_back(Obj); + Obj->parse(); } - - return ObjFiles; } - } // namespace coff } // namespace lld Index: COFF/Symbols.h =================================================================== --- COFF/Symbols.h +++ COFF/Symbols.h @@ -30,7 +30,6 @@ using llvm::object::coff_symbol_generic; class ArchiveFile; -class BitcodeFile; class InputFile; class ObjectFile; struct Symbol; @@ -52,13 +51,12 @@ DefinedImportDataKind, DefinedAbsoluteKind, DefinedRelativeKind, - DefinedBitcodeKind, UndefinedKind, LazyKind, LastDefinedCOFFKind = DefinedCommonKind, - LastDefinedKind = DefinedBitcodeKind, + LastDefinedKind = DefinedRelativeKind, }; Kind kind() const { return static_cast(SymbolKind); } @@ -81,7 +79,7 @@ friend SymbolTable; explicit SymbolBody(Kind K, StringRef N = "") : SymbolKind(K), IsExternal(true), IsCOMDAT(false), - IsReplaceable(false), WrittenToSymtab(false), Name(N) {} + WrittenToSymtab(false), Name(N) {} const unsigned SymbolKind : 8; unsigned IsExternal : 1; @@ -89,11 +87,9 @@ // This bit is used by the \c DefinedRegular subclass. unsigned IsCOMDAT : 1; - // This bit is used by the \c DefinedBitcode subclass. - unsigned IsReplaceable : 1; - public: - // This bit is used by Writer::createSymbolAndStringTable(). + // This bit is used by Writer::createSymbolAndStringTable() to prevent + // symbols from being written to the symbol table more than once. unsigned WrittenToSymtab : 1; protected: @@ -104,7 +100,7 @@ // etc. class Defined : public SymbolBody { public: - Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {} + Defined(Kind K, StringRef N) : SymbolBody(K, N) {} static bool classof(const SymbolBody *S) { return S->kind() <= LastDefinedKind; @@ -127,22 +123,25 @@ bool isExecutable(); }; -// Symbols defined via a COFF object file. +// Symbols defined via a COFF object file or bitcode file. For COFF files, this +// stores a coff_symbol_generic*, and names of internal symbols are lazily +// loaded through that. For bitcode files, Sym is nullptr and the name is stored +// as a StringRef. class DefinedCOFF : public Defined { friend SymbolBody; public: - DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S) - : Defined(K), File(F), Sym(S.getGeneric()) {} + DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S) + : Defined(K, N), File(F), Sym(S) {} static bool classof(const SymbolBody *S) { return S->kind() <= LastDefinedCOFFKind; } - ObjectFile *getFile() { return File; } + InputFile *getFile() { return File; } COFFSymbolRef getCOFFSymbol(); - ObjectFile *File; + InputFile *File; protected: const coff_symbol_generic *Sym; @@ -151,10 +150,13 @@ // Regular defined symbols read from object file symbol tables. class DefinedRegular : public DefinedCOFF { public: - DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C) - : DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) { - IsExternal = S.isExternal(); - IsCOMDAT = C->isCOMDAT(); + DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT, + bool IsExternal = false, + const coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr) + : DefinedCOFF(DefinedRegularKind, F, N, S), Data(&C->Repl) { + this->IsExternal = IsExternal; + this->IsCOMDAT = IsCOMDAT; } static bool classof(const SymbolBody *S) { @@ -172,9 +174,11 @@ class DefinedCommon : public DefinedCOFF { public: - DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C) - : DefinedCOFF(DefinedCommonKind, F, S), Data(C) { - IsExternal = S.isExternal(); + DefinedCommon(InputFile *F, StringRef N, uint64_t Size, + const coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr) + : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { + this->IsExternal = true; } static bool classof(const SymbolBody *S) { @@ -185,8 +189,9 @@ private: friend SymbolTable; - uint64_t getSize() { return Sym->Value; } + uint64_t getSize() const { return Size; } CommonChunk *Data; + uint64_t Size; }; // Absolute symbols. @@ -340,26 +345,6 @@ LocalImportChunk *Data; }; -class DefinedBitcode : public Defined { - friend SymbolBody; -public: - DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) - : Defined(DefinedBitcodeKind, N), File(F) { - // IsReplaceable tracks whether the bitcode symbol may be replaced with some - // other (defined, common or bitcode) symbol. This is the case for common, - // comdat and weak external symbols. We try to replace bitcode symbols with - // "real" symbols (see SymbolTable::add{Regular,Bitcode}), and resolve the - // result against the real symbol from the combined LTO object. - this->IsReplaceable = IsReplaceable; - } - - static bool classof(const SymbolBody *S) { - return S->kind() == DefinedBitcodeKind; - } - - BitcodeFile *File; -}; - inline uint64_t Defined::getRVA() { switch (kind()) { case DefinedAbsoluteKind: @@ -376,8 +361,6 @@ return cast(this)->getRVA(); case DefinedRegularKind: return cast(this)->getRVA(); - case DefinedBitcodeKind: - llvm_unreachable("There is no address for a bitcode symbol."); case LazyKind: case UndefinedKind: llvm_unreachable("Cannot get the address for an undefined symbol."); @@ -401,10 +384,9 @@ // This field is used to store the Symbol's SymbolBody. This instantiation of // AlignedCharArrayUnion gives us a struct with a char array field that is // large and aligned enough to store any derived class of SymbolBody. - llvm::AlignedCharArrayUnion + llvm::AlignedCharArrayUnion< + DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedRelative, Lazy, + Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport> Body; SymbolBody *body() { Index: COFF/Symbols.cpp =================================================================== --- COFF/Symbols.cpp +++ COFF/Symbols.cpp @@ -30,7 +30,7 @@ namespace coff { StringRef SymbolBody::getName() { - // DefinedCOFF names are read lazily for a performance reason. + // COFF symbol names are read lazily for a performance reason. // Non-external symbol names are never used by the linker except for logging // or debugging. Their internal references are resolved not by name but by // symbol index. And because they are not external, no one can refer them by @@ -39,7 +39,7 @@ // is a waste of time. if (Name.empty()) { auto *D = cast(this); - D->File->getCOFFObj()->getSymbolName(D->Sym, Name); + cast(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name); } return Name; } @@ -47,15 +47,14 @@ InputFile *SymbolBody::getFile() { if (auto *Sym = dyn_cast(this)) return Sym->File; - if (auto *Sym = dyn_cast(this)) - return Sym->File; if (auto *Sym = dyn_cast(this)) return Sym->File; return nullptr; } COFFSymbolRef DefinedCOFF::getCOFFSymbol() { - size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize(); + size_t SymSize = + cast(File)->getCOFFObj()->getSymbolTableEntrySize(); if (SymSize == sizeof(coff_symbol16)) return COFFSymbolRef(reinterpret_cast(Sym)); assert(SymSize == sizeof(coff_symbol32)); Index: test/COFF/lto-comdat.ll =================================================================== --- test/COFF/lto-comdat.ll +++ test/COFF/lto-comdat.ll @@ -10,6 +10,8 @@ ; RUN: rm -f %T/comdat.lib ; RUN: llvm-ar cru %T/comdat.lib %T/comdat1.obj %T/comdat2.obj +; Check that, when we use an LTO main with LTO objects, we optimize away all +; of f1, f2, and comdat. ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.lto.obj %T/comdat2.lto.obj ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s @@ -17,6 +19,9 @@ ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-11 %s ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-11 %s +; Check that, when we use a non-LTO main with LTO objects, we pick the comdat +; implementation in LTO, elide calls to it from inside LTO, and retain the +; call to comdat from main. ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.obj %T/comdat1.lto.obj %T/comdat2.lto.obj ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s @@ -24,6 +29,9 @@ ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-01 %s ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-01 %s +; Check that, when we use an LTO main with non-LTO objects, we pick the comdat +; implementation in LTO, elide the call to it from inside LTO, and keep the +; calls to comdat from the non-LTO objects. ; RUN: lld-link /out:%T/comdat-main.exe /entry:main /subsystem:console %T/comdat-main.lto.obj %T/comdat1.obj %T/comdat2.obj ; RUN: llvm-readobj -file-headers %T/comdat-main.exe | FileCheck -check-prefix=HEADERS-10 %s ; RUN: llvm-objdump -d %T/comdat-main.exe | FileCheck -check-prefix=TEXT-10 %s @@ -46,70 +54,39 @@ ; TEXT-01-NEXT: callq 13 ; TEXT-01-NEXT: xorl %eax, %eax ; TEXT-01-NEXT: addq $40, %rsp -; TEXT-01-NEXT: retq -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: retq -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: int3 -; TEXT-01-NEXT: retq -; TEXT-01-NEXT: nopw %cs:(%rax,%rax) -; TEXT-01-NEXT: retq +; TEXT-01: retq +; TEXT-01-NOT: callq +; TEXT-01: retq +; TEXT-01-NOT: callq +; TEXT-01: retq +; TEXT-01-NOT: callq +; TEXT-01: retq +; TEXT-01-NOT: {{.}} -; HEADERS-10: AddressOfEntryPoint: 0x2030 +; HEADERS-10: AddressOfEntryPoint: 0x2020 ; TEXT-10: Disassembly of section .text: ; TEXT-10-NEXT: .text: ; TEXT-10-NEXT: subq $40, %rsp -; TEXT-10-NEXT: callq 7 +; TEXT-10-NEXT: callq 55 ; TEXT-10-NEXT: nop ; TEXT-10-NEXT: addq $40, %rsp ; TEXT-10-NEXT: retq ; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: retq -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 -; TEXT-10-NEXT: int3 ; TEXT-10-NEXT: subq $40, %rsp -; TEXT-10-NEXT: callq -25 +; TEXT-10-NEXT: callq 39 ; TEXT-10-NEXT: nop ; TEXT-10-NEXT: addq $40, %rsp ; TEXT-10-NEXT: retq ; TEXT-10-NEXT: int3 ; TEXT-10-NEXT: subq $40, %rsp -; TEXT-10-NEXT: callq -57 +; TEXT-10-NEXT: callq -41 ; TEXT-10-NEXT: callq -30 ; TEXT-10-NEXT: xorl %eax, %eax ; TEXT-10-NEXT: addq $40, %rsp ; TEXT-10-NEXT: retq +; TEXT-10-NOT: callq +; TEXT-10: retq +; TEXT-10-NOT: {{.}} target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" Index: test/COFF/lto-parallel.ll =================================================================== --- test/COFF/lto-parallel.ll +++ test/COFF/lto-parallel.ll @@ -1,19 +1,19 @@ ; RUN: llvm-as -o %t.obj %s -; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltojobs=2 /subsystem:console /lldmap:%t.map %t.obj +; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj ; RUN: FileCheck %s < %t.map target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" -; CHECK: +; CHECK: lto.tmp ; CHECK-NEXT: foo define void @foo() { call void @bar() ret void } -; CHECK: -; CHECK-NEXT: bar +; CHECK: lto.tmp +; CHECK: bar define void @bar() { call void @foo() ret void Index: test/COFF/weak-external.test =================================================================== --- test/COFF/weak-external.test +++ test/COFF/weak-external.test @@ -4,7 +4,7 @@ # RUN: lld-link /out:%t2.exe /entry:g /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj # RUN: FileCheck %s < %t2.map -# CHECK: +# CHECK: lto.tmp # CHECK-NEXT: 0 g --- !COFF Index: test/COFF/weak-external3.test =================================================================== --- test/COFF/weak-external3.test +++ test/COFF/weak-external3.test @@ -5,7 +5,7 @@ # RUN: lld-link /out:%t2.exe /entry:f /subsystem:console /lldmap:%t2.map %t.obj %t.lto.obj # RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map -# CHECK1: +# CHECK1: lto.tmp # CHECK1-NEXT: 0 g # CHECK2: weak-external3.test.tmp.obj