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 @@ -87,6 +87,7 @@ bool Relocatable = true; bool Force = false; bool Debug = false; + bool SaveTemps; bool WriteSymtab = true; unsigned DebugTypes = static_cast(DebugType::None); StringRef PDBPath; @@ -114,6 +115,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 @@ -436,6 +436,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. @@ -772,46 +810,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; @@ -66,6 +65,17 @@ // Returns .drectve section contents if exist. StringRef getDirectives() { return StringRef(Directives).trim(); } + // Filename of .a which contained this file. If this file was + // not in an archive file, it is the empty string. We use this + // string for creating error messages. + StringRef ArchiveName; + + // If this file is in an archive, the member contains the offset of + // the file in the archive. Otherwise, it's just zero. We store this + // field so that we can pass it to lib/LTO in order to disambiguate + // between objects. + uint64_t OffsetInArchive; + protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} @@ -191,7 +201,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,8 +210,10 @@ std::vector SymbolBodies; llvm::BumpPtrAllocator Alloc; - std::unique_ptr M; }; + +InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", + uint64_t OffsetInArchive = 0); } // namespace coff std::string toString(coff::InputFile *File); 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" @@ -330,38 +330,47 @@ 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(ArchiveName + MB.getBufferIdentifier() + + utostr(OffsetInArchive))))); + + for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) { + StringRef SymName = Saver.save(ObjSym.getName()); + auto Flags = ObjSym.getFlags(); + Expected ComdatIndex = ObjSym.getComdatIndex(); + if (Flags & object::BasicSymbolRef::SF_Undefined) { + SymbolBodies.push_back( + Symtab->addUndefined(SymName, this, false)->body()); } 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))); + bool Replaceable = (Flags & object::BasicSymbolRef::SF_Common) // common + || (ComdatIndex && *ComdatIndex != -1) // comdat + || (Flags & object::BasicSymbolRef::SF_Weak); // weak SymbolBodies.push_back( Symtab->addBitcode(this, SymName, Replaceable)->body()); } } - Directives = M->getLinkerOpts(); + // Extract linker options. + raw_string_ostream OS(Directives); + std::unique_ptr M = + check(getLazyBitcodeModule(MB, Context), toString(this)); + if (Metadata *Val = M->getModuleFlag("Linker Options")) { + MDNode *LinkerOptions = cast(Val); + for (unsigned i = 0, e = LinkerOptions->getNumOperands(); i != e; ++i) { + MDNode *MDOptions = cast(LinkerOptions->getOperand(i)); + for (unsigned ii = 0, ie = MDOptions->getNumOperands(); ii != ie; ++ii) { + MDString *MDOption = cast(MDOptions->getOperand(ii)); + OS << " " << MDOption->getString(); + } + } + } } 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: @@ -372,6 +381,20 @@ return IMAGE_FILE_MACHINE_UNKNOWN; } } + +static bool isBitcode(MemoryBufferRef MB) { + using namespace sys::fs; + return identify_magic(MB.getBuffer()) == file_magic::bitcode; +} + +InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, + uint64_t OffsetInArchive) { + InputFile *F = isBitcode(MB) ? static_cast(make(MB)) + : static_cast(make(MB)); + F->ArchiveName = ArchiveName; + F->OffsetInArchive = OffsetInArchive; + return F; +} } // namespace coff } // namespace lld 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(); + + template 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,158 @@ +//===- 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/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/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" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::ELF; + +using namespace lld; +using namespace lld::coff; + +// 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; +} + +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; + + // LLD supports the new relocations. + Conf.Options = InitTargetOptionsFromCodeGenFlags(); + Conf.Options.RelaxELFRelocations = true; + + Conf.RelocModel = Config->Relocatable ? Reloc::PIC_ : Reloc::Static; + Conf.DisableVerify = true; + Conf.DiagHandler = diagnosticHandler; + Conf.OptLevel = Config->LTOOptLevel; + + // Set up a custom pipeline if we've been asked to. + Conf.OptPipeline = ""; + Conf.AAPipeline = ""; + + if (Config->SaveTemps) + checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", + /*UseInputModulePath*/ true)); + + 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 || + (R.Prevailing && ObjSym.hasDLLExportStorageClass()); + 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; + if (Config->SaveTemps) { + if (MaxTasks == 1) + 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); + } + 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" @@ -110,12 +111,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 @@ -218,9 +218,9 @@ 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()) + if (C->isCOMDAT()) + return S; + else reportDuplicate(S, F); } else replaceBody(S, F, Sym, C); @@ -235,6 +235,11 @@ replaceBody(S, F, N, IsReplaceable); return S; } + if (auto *R = dyn_cast(S->body())) + if (R->isCOMDAT()) { + replaceBody(S, F, N, IsReplaceable); + return S; + } if (isa(S->body())) return S; if (IsReplaceable) @@ -349,61 +354,19 @@ 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()); - } - - 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. + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *F : BitcodeFiles) + LTO->add(*F); - std::vector ObjFiles; - for (SmallString<0> &Obj : Objs) { - auto *ObjFile = make(MemoryBufferRef(Obj, "")); - ObjectFiles.push_back(ObjFile); - ObjFiles.push_back(ObjFile); - } + for (BitcodeFile *F : BitcodeFiles) + // Replace bitcode symbols with undefined symbols so that they may + // be replaced with real definitions without conflicting. + for (SymbolBody *Body : F->getSymbols()) + if (auto *B = dyn_cast(Body)) + replaceBody(Body->symbol(), Body->getName()); - return ObjFiles; + for (InputFile *File : LTO->compile()) + addFile(File); } - } // namespace coff } // namespace lld Index: COFF/Symbols.h =================================================================== --- COFF/Symbols.h +++ COFF/Symbols.h @@ -93,7 +93,8 @@ 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: 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 @@ -41,75 +49,44 @@ ; TEXT-01: Disassembly of section .text: ; TEXT-01-NEXT: .text: ; TEXT-01-NEXT: subq $40, %rsp -; TEXT-01-NEXT: callq 39 -; TEXT-01-NEXT: callq 50 -; TEXT-01-NEXT: callq 13 +; TEXT-01-NEXT: callq 23 +; TEXT-01-NEXT: callq 34 +; TEXT-01-NEXT: callq 45 ; 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