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,7 @@ // Used for /opt:lldltojobs=N unsigned LTOJobs = 1; + unsigned LTOPartitions = 1; // Used for /merge:from=to (e.g. /merge:.rdata=.text) std::map Merge; Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -116,6 +116,7 @@ void enqueueTask(std::function Task); bool run(); + void runLoop(); // Driver is the owner of all opened files. // InputFiles have MemoryBufferRefs to them. Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -435,6 +435,44 @@ return DidWork; } +void LinkerDriver::runLoop() { + // This code may add new undefined symbols to the link, which may enqueue more + // symbol resolution tasks, so we need to continue executing tasks until we + // converge. + do { + // Windows specific -- if entry point is not found, + // search for its mangled names. + if (Config->Entry) + Symtab.mangleMaybe(Config->Entry); + + // Windows specific -- Make sure we resolve all dllexported symbols. + for (Export &E : Config->Exports) { + if (!E.ForwardTo.empty()) + continue; + E.Sym = addUndefined(E.Name); + if (!E.Directives) + Symtab.mangleMaybe(E.Sym); + } + + // Add weak aliases. Weak aliases is a mechanism to give remaining + // undefined symbols final chance to be resolved successfully. + for (auto Pair : Config->AlternateNames) { + StringRef From = Pair.first; + StringRef To = Pair.second; + Symbol *Sym = Symtab.find(From); + if (!Sym) + continue; + if (auto *U = dyn_cast(Sym->body())) + if (!U->WeakAlias) + U->WeakAlias = Symtab.addUndefined(To); + } + + // Windows specific -- if __load_config_used can be resolved, resolve it. + if (Symtab.findUnderscore("_load_config_used")) + addUndefined(mangle("_load_config_used")); + } while (run()); +} + void LinkerDriver::link(ArrayRef ArgsArr) { // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. @@ -771,46 +809,12 @@ Symtab.addAbsolute(mangle("__guard_fids_count"), 0); Symtab.addAbsolute(mangle("__guard_flags"), 0x100); - // This code may add new undefined symbols to the link, which may enqueue more - // symbol resolution tasks, so we need to continue executing tasks until we - // converge. - do { - // Windows specific -- if entry point is not found, - // search for its mangled names. - if (Config->Entry) - Symtab.mangleMaybe(Config->Entry); - - // Windows specific -- Make sure we resolve all dllexported symbols. - for (Export &E : Config->Exports) { - if (!E.ForwardTo.empty()) - continue; - E.Sym = addUndefined(E.Name); - if (!E.Directives) - Symtab.mangleMaybe(E.Sym); - } - - // Add weak aliases. Weak aliases is a mechanism to give remaining - // undefined symbols final chance to be resolved successfully. - for (auto Pair : Config->AlternateNames) { - StringRef From = Pair.first; - StringRef To = Pair.second; - Symbol *Sym = Symtab.find(From); - if (!Sym) - continue; - if (auto *U = dyn_cast(Sym->body())) - if (!U->WeakAlias) - U->WeakAlias = Symtab.addUndefined(To); - } - - // Windows specific -- if __load_config_used can be resolved, resolve it. - if (Symtab.findUnderscore("_load_config_used")) - addUndefined(mangle("_load_config_used")); - } while (run()); + runLoop(); // Do LTO by compiling bitcode input files to a set of native COFF files then // link those files. Symtab.addCombinedLTOObjects(); - run(); + runLoop(); // Make sure we have resolved all symbols. Symtab.reportRemainingUndefines(); Index: COFF/InputFiles.h =================================================================== --- COFF/InputFiles.h +++ COFF/InputFiles.h @@ -14,7 +14,7 @@ #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 +25,6 @@ namespace lld { namespace coff { -using llvm::LTOModule; using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; using llvm::COFF::MachineTypes; using llvm::object::Archive; @@ -191,7 +190,7 @@ 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); } + std::unique_ptr Obj; static llvm::LLVMContext Context; @@ -200,7 +199,6 @@ 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,8 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/IR/LLVMContext.h" -#include "llvm/LTO/legacy/LTOModule.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" #include "llvm/Support/COFF.h" @@ -198,7 +198,11 @@ 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.isExternal(), + Sym.getGeneric(), C); + S->IsUsedInRegularObj = true; + return S->body(); } if (Sym.isAbsolute()) { COFFObj->getSymbolName(Sym, Name); @@ -245,10 +249,15 @@ } 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.isExternal(), + Sym.getGeneric(), SC); + S->IsUsedInRegularObj = true; + B = cast(S->body()); + } else + B = new (Alloc) DefinedRegular(this, Name, SC->isCOMDAT(), Sym.isExternal(), + Sym.getGeneric(), SC); if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP) SC->setSymbol(B); @@ -328,38 +337,43 @@ 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())))); + 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 { - 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; + if (!IsCOMDAT && (Flags & object::BasicSymbolRef::SF_Weak)) { + // Weak external. + Sym = Symtab->addUndefined(SymName, this, true); + StringRef AliasName = ObjSym.getAliasName(); + assert(AliasName); + if (auto *U = dyn_cast(Sym->body())) + U->WeakAlias = Symtab->addUndefined(AliasName); + } else { + Sym = Symtab->addRegular(this, SymName, IsCOMDAT); + } } + if (ObjSym.hasDLLExportStorageClass()) + Sym->IsUsedInRegularObj = true; + SymbolBodies.push_back(Sym->body()); } - 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 =================================================================== --- COFF/LTO.cpp +++ COFF/LTO.cpp @@ -12,17 +12,16 @@ #include "Error.h" #include "InputFiles.h" #include "Symbols.h" +#include "lld/Config/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/CodeGen/CommandFlags.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/ELF.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -36,19 +35,9 @@ using namespace llvm; using namespace llvm::object; -using namespace llvm::ELF; using namespace lld; -using namespace lld::elf; - -// This is for use when debugging LTO. -static void saveBuffer(StringRef Buffer, const Twine &Path) { - std::error_code EC; - raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); - if (EC) - error("cannot create " + Path + ": " + EC.message()); - OS << Buffer; -} +using namespace lld::coff; static void diagnosticHandler(const DiagnosticInfo &DI) { SmallString<128> ErrStorage; @@ -67,27 +56,14 @@ static std::unique_ptr createLTO() { lto::Config Conf; - - // LLD supports the new relocations. Conf.Options = InitTargetOptionsFromCodeGenFlags(); - Conf.Options.RelaxELFRelocations = true; - - Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static; - Conf.DisableVerify = Config->DisableVerify; + Conf.RelocModel = Reloc::PIC_; + Conf.DisableVerify = true; Conf.DiagHandler = diagnosticHandler; - Conf.OptLevel = Config->LTOO; - - // Set up a custom pipeline if we've been asked to. - Conf.OptPipeline = Config->LTONewPmPasses; - Conf.AAPipeline = Config->LTOAAPipeline; - - if (Config->SaveTemps) - checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", - /*UseInputModulePath*/ true)); - + Conf.OptLevel = Config->LTOOptLevel; lto::ThinBackend Backend; - if (Config->ThinLTOJobs != -1u) - Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); + if (Config->LTOJobs != -1u) + Backend = lto::createInProcessThinBackend(Config->LTOJobs); return llvm::make_unique(std::move(Conf), Backend, Config->LTOPartitions); } @@ -96,23 +72,22 @@ BitcodeCompiler::~BitcodeCompiler() = default; -template static void undefine(Symbol *S) { - replaceBody>(S, S->body()->getName(), /*IsLocal=*/false, - STV_DEFAULT, S->body()->Type, nullptr); +static void undefine(Symbol *S) { + replaceBody(S, S->body()->getName()); } -template void BitcodeCompiler::add(BitcodeFile &F) { +void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; - std::vector Syms = F.getSymbols(); - std::vector Resols(Syms.size()); + 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()) { - Symbol *Sym = Syms[SymNum]; + SymbolBody *B = SymBodies[SymNum]; + Symbol *Sym = B->symbol(); lto::SymbolResolution &R = Resols[SymNum]; ++SymNum; - SymbolBody *B = Sym->body(); // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld @@ -121,12 +96,10 @@ // be removed. R.Prevailing = !(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) && - B->File == &F; - - R.VisibleToRegularObj = - Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); + B->getFile() == &F; + R.VisibleToRegularObj = Sym->IsUsedInRegularObj; if (R.Prevailing) - undefine(Sym); + undefine(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } @@ -146,19 +119,7 @@ for (unsigned I = 0; I != MaxTasks; ++I) { if (Buff[I].empty()) continue; - if (Config->SaveTemps) { - if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.o"); - else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o"); - } - InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp")); - Ret.push_back(Obj); + Ret.push_back(make(MemoryBufferRef(Buff[I], "lto.tmp"))); } return Ret; } - -template void BitcodeCompiler::template add(BitcodeFile &); -template void BitcodeCompiler::template add(BitcodeFile &); -template void BitcodeCompiler::template add(BitcodeFile &); -template void BitcodeCompiler::template add(BitcodeFile &); Index: COFF/MapFile.cpp =================================================================== --- COFF/MapFile.cpp +++ COFF/MapFile.cpp @@ -78,8 +78,7 @@ ArrayRef Syms = File->getSymbols(); for (SymbolBody *Sym : Syms) { auto *DR = dyn_cast(Sym); - if (!DR || DR->getChunk() != SC || - DR->getCOFFSymbol().isSectionDefinition()) + if (!DR || DR->getChunk() != SC || DR->isSectionDefinition()) continue; writeSymbolLine(OS, DR->getRVA(), SC->getSize(), toString(*Sym)); OS << '\n'; 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,14 @@ 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, + bool IsExternal = false, + const llvm::object::coff_symbol_generic *S = nullptr, + SectionChunk *C = nullptr); + Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, + bool IsExternal = false, + 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 +116,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,39 @@ 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; + auto *R = dyn_cast(S->body()); + + // Non-comdat symbols win over comdat symbols. + // If both symbols are non-comdat, they conflict. + bool ExistingIsCOMDAT = R && R->isCOMDAT(); + if (NewIsCOMDAT) { + if (!ExistingIsCOMDAT) + return SP_EXISTING; + } else { + if (ExistingIsCOMDAT) + return SP_NEW; + else + return SP_CONFLICT; + } + + // If we have no reason to prefer either symbol, we keep the existing one. + return SP_EXISTING; +} + SymbolTable *Symtab; void SymbolTable::addFile(InputFile *File) { @@ -204,59 +237,32 @@ return S; } -Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym, +Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT, + bool IsExternal, 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; + SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT); + if (SP == SP_CONFLICT) { + reportDuplicate(S, F); + } else if (SP == SP_NEW) { + replaceBody(S, F, N, IsCOMDAT, IsExternal, 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, +Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, + bool IsExternal, const coff_symbol_generic *Sym, CommonChunk *C) { - StringRef Name; - F->getCOFFObj()->getSymbolName(Sym, Name); Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - S->IsUsedInRegularObj = true; + std::tie(S, WasInserted) = insert(N); if (WasInserted || !isa(S->body())) - replaceBody(S, F, Sym, C); + replaceBody(S, F, N, Size, IsExternal, 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, IsExternal, Sym, C); return S; } @@ -349,61 +355,12 @@ 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(); -} - -// 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()); - } + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *F : BitcodeFiles) + LTO->add(*F); - 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); - } - - return ObjFiles; + for (InputFile *File : LTO->compile()) + addFile(File); } - } // 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 symobl 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) {} + explicit Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {} static bool classof(const SymbolBody *S) { return S->kind() <= LastDefinedKind; @@ -127,22 +123,31 @@ 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 the symbol name is +// 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; } + bool isSectionDefinition() { + if (isa(File)) + return getCOFFSymbol().isSectionDefinition(); + else + return false; + } COFFSymbolRef getCOFFSymbol(); - ObjectFile *File; + InputFile *File; protected: const coff_symbol_generic *Sym; @@ -151,10 +156,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 +180,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, + bool IsExternal = false, const coff_symbol_generic *S = nullptr, + CommonChunk *C = nullptr) + : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) { + this->IsExternal = IsExternal; } static bool classof(const SymbolBody *S) { @@ -185,8 +195,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 +351,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 +367,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 +390,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 @@ -38,8 +38,10 @@ // StringRefs for them (which involves lots of strlen() on the string table) // is a waste of time. if (Name.empty()) { - auto *D = cast(this); - D->File->getCOFFObj()->getSymbolName(D->Sym, Name); + auto *D = dyn_cast(this); + auto *O = dyn_cast(getFile()); + if (D && O) + O->getCOFFObj()->getSymbolName(D->Sym, Name); } return Name; } @@ -47,15 +49,16 @@ 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(); + auto *F = dyn_cast(File); + if (!F) + fatal("getCOFFSymbol applied to SymbolBody not backed by COFF object file"); + size_t SymSize = F->getCOFFObj()->getSymbolTableEntrySize(); if (SymSize == sizeof(coff_symbol16)) return COFFSymbolRef(reinterpret_cast(Sym)); assert(SymSize == sizeof(coff_symbol32)); Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -12,11 +12,11 @@ #include "Error.h" #include "InputFiles.h" #include "Symbols.h" +#include "lld/Config/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" Index: include/lld/Config/TargetOptionsCommandFlags.h =================================================================== --- /dev/null +++ include/lld/Config/TargetOptionsCommandFlags.h @@ -0,0 +1,18 @@ +//===-- TargetOptionsCommandFlags.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper to create TargetOptions from command line flags. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Target/TargetOptions.h" + +namespace lld { +llvm::TargetOptions InitTargetOptionsFromCodeGenFlags(); +} Index: lib/Config/CMakeLists.txt =================================================================== --- lib/Config/CMakeLists.txt +++ lib/Config/CMakeLists.txt @@ -1,4 +1,5 @@ add_lld_library(lldConfig + TargetOptionsCommandFlags.cpp Version.cpp ADDITIONAL_HEADER_DIRS Index: lib/Config/TargetOptionsCommandFlags.cpp =================================================================== --- /dev/null +++ lib/Config/TargetOptionsCommandFlags.cpp @@ -0,0 +1,31 @@ +//===-- TargetOptionsCommandFlags.cpp ---------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file exists as a place for global variables defined in LLVM's +// CodeGen/CommandFlags.h. By putting the resulting object file in +// an archive and linking with it, the definitions will automatically be +// included when needed and skipped when already present. +// +//===----------------------------------------------------------------------===// + +#include "lld/Config/TargetOptionsCommandFlags.h" + +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/Target/TargetOptions.h" + +namespace lld { + +// Define an externally visible version of +// InitTargetOptionsFromCodeGenFlags, so that its functionality can be +// used without having to include llvm/CodeGen/CommandFlags.h, which +// would lead to multiple definitions of the command line flags. +llvm::TargetOptions InitTargetOptionsFromCodeGenFlags() { + return ::InitTargetOptionsFromCodeGenFlags(); +} +} 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 @@ -5,15 +5,14 @@ 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: 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