Index: include/llvm/Linker/IRMover.h =================================================================== --- include/llvm/Linker/IRMover.h +++ include/llvm/Linker/IRMover.h @@ -71,8 +71,13 @@ /// not present in ValuesToLink. The GlobalValue and a ValueAdder callback /// are passed as an argument, and the callback is expected to be called /// if the GlobalValue needs to be added to the \p ValuesToLink and linked. + /// - \p LinkModuleInlineAsm is true if the ModuleInlineAsm string in Src + /// should be linked with (concatenated into) the ModuleInlineAsm string + /// for the destination module. It should be true for full LTO, but not + /// when importing for ThinLTO, otherwise we can have duplicate symbols. Error move(std::unique_ptr Src, ArrayRef ValuesToLink, - std::function AddLazyFor); + std::function AddLazyFor, + bool LinkModuleInlineAsm); Module &getModule() { return Composite; } private: Index: include/llvm/Support/TargetRegistry.h =================================================================== --- include/llvm/Support/TargetRegistry.h +++ include/llvm/Support/TargetRegistry.h @@ -280,6 +280,9 @@ /// hasMCAsmBackend - Check if this target supports .o generation. bool hasMCAsmBackend() const { return MCAsmBackendCtorFn != nullptr; } + /// hasMCAsmParser - Check if this target supports assembly parsing. + bool hasMCAsmParser() const { return MCAsmParserCtorFn != nullptr; } + /// @} /// @name Feature Constructors /// @{ Index: lib/Analysis/LLVMBuild.txt =================================================================== --- lib/Analysis/LLVMBuild.txt +++ lib/Analysis/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = Analysis parent = Libraries -required_libraries = Core Support ProfileData +required_libraries = Core Support ProfileData Object Index: lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- lib/Analysis/ModuleSummaryAnalysis.cpp +++ lib/Analysis/ModuleSummaryAnalysis.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/ModuleSummaryAnalysis.h" +#include "llvm/ADT/Triple.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BlockFrequencyInfoImpl.h" #include "llvm/Analysis/BranchProbabilityInfo.h" @@ -24,6 +25,7 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Object/IRObjectFile.h" #include "llvm/Pass.h" using namespace llvm; @@ -260,6 +262,7 @@ // into this module, which is also necessary to avoid needing to rename // in case of a name clash between a local in this module and an imported // global. + // // FIXME: If we find we need a finer-grained approach of preventing promotion // and renaming of just the functions using inline assembly we will need to: // - Add flag in the function summaries to identify those with inline asm. @@ -270,6 +273,24 @@ // alias to the original name in the current module (even if we don't // export the function using those values in inline asm, another function // with a reference could be exported). + + // We similarly prevent importing from modules containing module-level inline + // assembly that defines a local value. These would also requiring renaming + // on import. + if (!M.getModuleInlineAsm().empty()) { + bool LocalIsDefined = false; + object::IRObjectFile::CollectAsmUndefinedRefs( + Triple(M.getTargetTriple()), M.getModuleInlineAsm(), + [&LocalIsDefined](StringRef Name, object::BasicSymbolRef::Flags Flags) { + if (!(Flags & (object::BasicSymbolRef::SF_Weak || + object::BasicSymbolRef::SF_Global))) + LocalIsDefined = true; + }); + + if (LocalIsDefined) + return false; + } + SmallPtrSet Used; collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); bool LocalIsUsed = Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -367,7 +367,8 @@ assert(ResI == Res.end()); return RegularLTO.Mover->move(Obj->takeModule(), Keep, - [](GlobalValue &, IRMover::ValueAdder) {}); + [](GlobalValue &, IRMover::ValueAdder) {}, + /* LinkModuleInlineAsm */ true); } // Add a ThinLTO object to the link. Index: lib/Linker/IRMover.cpp =================================================================== --- lib/Linker/IRMover.cpp +++ lib/Linker/IRMover.cpp @@ -397,6 +397,12 @@ Worklist.push_back(GV); } + /// Flag whether the ModuleInlineAsm string in Src should be linked with + /// (concatenated into) the ModuleInlineAsm string for the destination + /// module. It should be true for full LTO, but not when importing for + /// ThinLTO, otherwise we can have duplicate symbols. + bool LinkModuleInlineAsm; + /// Set to true when all global value body linking is complete (including /// lazy linking). Used to prevent metadata linking from creating new /// references. @@ -482,10 +488,11 @@ IRLinker(Module &DstM, MDMapT &SharedMDs, IRMover::IdentifiedStructTypeSet &Set, std::unique_ptr SrcM, ArrayRef ValuesToLink, - std::function AddLazyFor) + std::function AddLazyFor, + bool LinkModuleInlineAsm) : DstM(DstM), SrcM(std::move(SrcM)), AddLazyFor(std::move(AddLazyFor)), TypeMap(Set), GValMaterializer(*this), LValMaterializer(*this), - SharedMDs(SharedMDs), + SharedMDs(SharedMDs), LinkModuleInlineAsm(LinkModuleInlineAsm), Mapper(ValueMap, RF_MoveDistinctMDs | RF_IgnoreMissingLocals, &TypeMap, &GValMaterializer), AliasMCID(Mapper.registerAlternateMappingContext(AliasValueMap, @@ -1216,7 +1223,7 @@ DstM.setTargetTriple(mergeTriples(SrcTriple, DstTriple)); // Append the module inline asm string. - if (!SrcM->getModuleInlineAsm().empty()) { + if (LinkModuleInlineAsm && !SrcM->getModuleInlineAsm().empty()) { if (DstM.getModuleInlineAsm().empty()) DstM.setModuleInlineAsm(SrcM->getModuleInlineAsm()); else @@ -1354,9 +1361,11 @@ Error IRMover::move( std::unique_ptr Src, ArrayRef ValuesToLink, - std::function AddLazyFor) { + std::function AddLazyFor, + bool LinkModuleInlineAsm) { IRLinker TheIRLinker(Composite, SharedMDs, IdentifiedStructTypes, - std::move(Src), ValuesToLink, std::move(AddLazyFor)); + std::move(Src), ValuesToLink, std::move(AddLazyFor), + LinkModuleInlineAsm); Error E = TheIRLinker.run(); Composite.dropTriviallyDeadConstantArrays(); return E; Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -582,7 +582,8 @@ if (Error E = Mover.move(std::move(SrcM), ValuesToLink.getArrayRef(), [this](GlobalValue &GV, IRMover::ValueAdder Add) { addLazyFor(GV, Add); - })) { + }, + !isPerformingImport())) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { DstM.getContext().diagnose(LinkDiagnosticInfo(DS_Error, EIB.message())); HasErrors = true; Index: lib/Object/IRObjectFile.cpp =================================================================== --- lib/Object/IRObjectFile.cpp +++ lib/Object/IRObjectFile.cpp @@ -54,8 +54,7 @@ std::string Err; const Target *T = TargetRegistry::lookupTarget(TT.str(), Err); - if (!T) - return; + assert(T && T->hasMCAsmParser()); std::unique_ptr MRI(T->createMCRegInfo(TT.str())); if (!MRI) Index: test/LTO/X86/current-section.ll =================================================================== --- test/LTO/X86/current-section.ll +++ test/LTO/X86/current-section.ll @@ -2,4 +2,7 @@ ; RUN: llvm-lto -o %t2 %t1 ; REQUIRES: default_triple +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + module asm ".align 4" Index: test/ThinLTO/X86/Inputs/module_asm.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/Inputs/module_asm.ll @@ -0,0 +1,8 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @main({ i64, { i64, i8* }* } %unnamed) #0 { + %1 = call i32 @_simplefunction() #1 + ret i32 %1 +} +declare i32 @_simplefunction() #1 Index: test/ThinLTO/X86/module_asm_glob.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/module_asm_glob.ll @@ -0,0 +1,35 @@ +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/module_asm.ll -o %t2.bc + +; RUN: llvm-lto -thinlto-action=run -exported-symbol=main %t1.bc %t2.bc +; RUN: llvm-nm %t1.bc.thinlto.o | FileCheck %s --check-prefix=NM0 +; RUN: llvm-nm %t2.bc.thinlto.o | FileCheck %s --check-prefix=NM1 + +; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \ +; RUN: -r=%t1.bc,foo,plx \ +; RUN: -r=%t1.bc,_simplefunction,pl \ +; RUN: -r=%t2.bc,main,plx \ +; RUN: -r=%t2.bc,_simplefunction,l +; RUN: llvm-nm %t.o.0 | FileCheck %s --check-prefix=NM0 +; RUN: llvm-nm %t.o.1 | FileCheck %s --check-prefix=NM1 + +; NM0: T foo +; NM1-NOT: foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm "\09.text" +module asm "\09.globl\09foo" +module asm "\09.align\0916, 0x90" +module asm "\09.type\09foo,@function" +module asm "foo:" +module asm "\09ret " +module asm "\09.size\09foo, .-foo" +module asm "" + +declare zeroext i16 @foo() #0 + +define i32 @_simplefunction() #1 { + ret i32 1 +} Index: test/ThinLTO/X86/module_asm_local.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/module_asm_local.ll @@ -0,0 +1,34 @@ +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/module_asm.ll -o %t2.bc + +; RUN: llvm-lto -thinlto-action=run -exported-symbol=main %t1.bc %t2.bc +; RUN: llvm-nm %t1.bc.thinlto.o | FileCheck %s --check-prefix=NM0 +; RUN: llvm-nm %t2.bc.thinlto.o | FileCheck %s --check-prefix=NM1 + +; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \ +; RUN: -r=%t1.bc,foo,plx \ +; RUN: -r=%t1.bc,_simplefunction,pl \ +; RUN: -r=%t2.bc,main,plx \ +; RUN: -r=%t2.bc,_simplefunction,l +; RUN: llvm-nm %t.o.0 | FileCheck %s --check-prefix=NM0 +; RUN: llvm-nm %t.o.1 | FileCheck %s --check-prefix=NM1 + +; NM0: t foo +; NM1-NOT: foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm "\09.text" +module asm "\09.type\09foo,@function" +module asm "foo:" +module asm "\09ret " +module asm "\09.size\09foo, .-foo" +module asm "" + +declare i16 @foo() #0 + +define i32 @_simplefunction() #1 { + call i16 @foo() + ret i32 1 +} Index: tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- tools/llvm-lto2/llvm-lto2.cpp +++ tools/llvm-lto2/llvm-lto2.cpp @@ -158,6 +158,12 @@ check(InputFile::create(MB->getMemBufferRef()), F); std::vector Res; + // FIXME: Workaround PR30396 which means that a symbol can appear + // more than once if it is defined in module-level assembly and + // has a GV declaration. Keep track of the resolutions found in this + // file and remove them from the CommandLineResolutions map afterwards, + // so that we don't flag the second one as missing. + std::map CurrentFileSymResolutions; for (const InputFile::Symbol &Sym : Input->symbols()) { auto I = CommandLineResolutions.find({F, Sym.getName()}); if (I == CommandLineResolutions.end()) { @@ -166,9 +172,13 @@ HasErrors = true; } else { Res.push_back(I->second); - CommandLineResolutions.erase(I); + CurrentFileSymResolutions[Sym.getName()] = I->second; } } + for (auto I : CurrentFileSymResolutions) { + auto NumErased = CommandLineResolutions.erase({F, I.first}); + assert(NumErased > 0); + } if (HasErrors) continue; Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -364,6 +364,7 @@ InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry();