Index: llvm/trunk/include/llvm/Linker/IRMover.h =================================================================== --- llvm/trunk/include/llvm/Linker/IRMover.h +++ llvm/trunk/include/llvm/Linker/IRMover.h @@ -75,9 +75,11 @@ /// 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. + /// - \p IsPerformingImport is true when this IR link is to perform ThinLTO + /// function importing from Src. Error move(std::unique_ptr Src, ArrayRef ValuesToLink, std::function AddLazyFor, - bool LinkModuleInlineAsm); + bool LinkModuleInlineAsm, bool IsPerformingImport); Module &getModule() { return Composite; } private: Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -409,7 +409,8 @@ return RegularLTO.Mover->move(Obj->takeModule(), Keep, [](GlobalValue &, IRMover::ValueAdder) {}, - /* LinkModuleInlineAsm */ true); + /* LinkModuleInlineAsm */ true, + /* IsPerformingImport */ false); } // Add a ThinLTO object to the link. Index: llvm/trunk/lib/Linker/IRMover.cpp =================================================================== --- llvm/trunk/lib/Linker/IRMover.cpp +++ llvm/trunk/lib/Linker/IRMover.cpp @@ -480,6 +480,10 @@ Function *copyFunctionProto(const Function *SF); GlobalValue *copyGlobalAliasProto(const GlobalAlias *SGA); + /// When importing for ThinLTO, prevent importing of types listed on + /// the DICompileUnit that we don't need a copy of in the importing + /// module. + void prepareCompileUnitsForImport(); void linkNamedMDNodes(); public: @@ -487,7 +491,7 @@ IRMover::IdentifiedStructTypeSet &Set, std::unique_ptr SrcM, ArrayRef ValuesToLink, std::function AddLazyFor, - bool LinkModuleInlineAsm) + bool LinkModuleInlineAsm, bool IsPerformingImport) : DstM(DstM), SrcM(std::move(SrcM)), AddLazyFor(std::move(AddLazyFor)), TypeMap(Set), GValMaterializer(*this), LValMaterializer(*this), SharedMDs(SharedMDs), LinkModuleInlineAsm(LinkModuleInlineAsm), @@ -498,6 +502,8 @@ ValueMap.getMDMap() = std::move(SharedMDs); for (GlobalValue *GV : ValuesToLink) maybeAdd(GV); + if (IsPerformingImport) + prepareCompileUnitsForImport(); } ~IRLinker() { SharedMDs = std::move(*ValueMap.getMDMap()); } @@ -1005,6 +1011,70 @@ return Error::success(); } +void IRLinker::prepareCompileUnitsForImport() { + NamedMDNode *SrcCompileUnits = SrcM->getNamedMetadata("llvm.dbg.cu"); + if (!SrcCompileUnits) + return; + // When importing for ThinLTO, prevent importing of types listed on + // the DICompileUnit that we don't need a copy of in the importing + // module. They will be emitted by the originating module. + for (unsigned I = 0, E = SrcCompileUnits->getNumOperands(); I != E; ++I) { + auto *CU = cast(SrcCompileUnits->getOperand(I)); + assert(CU && "Expected valid compile unit"); + // Enums, macros, and retained types don't need to be listed on the + // imported DICompileUnit. This means they will only be imported + // if reached from the mapped IR. Do this by setting their value map + // entries to nullptr, which will automatically prevent their importing + // when reached from the DICompileUnit during metadata mapping. + ValueMap.MD()[CU->getRawEnumTypes()].reset(nullptr); + ValueMap.MD()[CU->getRawMacros()].reset(nullptr); + ValueMap.MD()[CU->getRawRetainedTypes()].reset(nullptr); + // If we ever start importing global variable defs, we'll need to + // add their DIGlobalVariable to the globals list on the imported + // DICompileUnit. Confirm none are imported, and then we can + // map the list of global variables to nullptr. + assert(none_of( + ValuesToLink, + [](const GlobalValue *GV) { return isa(GV); }) && + "Unexpected importing of a GlobalVariable definition"); + ValueMap.MD()[CU->getRawGlobalVariables()].reset(nullptr); + + // Imported entities only need to be mapped in if they have local + // scope, as those might correspond to an imported entity inside a + // function being imported (any locally scoped imported entities that + // don't end up referenced by an imported function will not be emitted + // into the object). Imported entities not in a local scope + // (e.g. on the namespace) only need to be emitted by the originating + // module. Create a list of the locally scoped imported entities, and + // replace the source CUs imported entity list with the new list, so + // only those are mapped in. + // FIXME: Locally-scoped imported entities could be moved to the + // functions they are local to instead of listing them on the CU, and + // we would naturally only link in those needed by function importing. + SmallVector AllImportedModules; + bool ReplaceImportedEntities = false; + for (auto *IE : CU->getImportedEntities()) { + DIScope *Scope = IE->getScope(); + assert(Scope && "Invalid Scope encoding!"); + if (isa(Scope)) + AllImportedModules.emplace_back(IE); + else + ReplaceImportedEntities = true; + } + if (ReplaceImportedEntities) { + if (!AllImportedModules.empty()) + CU->replaceImportedEntities(MDTuple::get( + CU->getContext(), + SmallVector(AllImportedModules.begin(), + AllImportedModules.end()))); + else + // If there were no local scope imported entities, we can map + // the whole list to nullptr. + ValueMap.MD()[CU->getRawImportedEntities()].reset(nullptr); + } + } +} + /// Insert all of the named MDNodes in Src into the Dest module. void IRLinker::linkNamedMDNodes() { const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata(); @@ -1366,10 +1436,10 @@ Error IRMover::move( std::unique_ptr Src, ArrayRef ValuesToLink, std::function AddLazyFor, - bool LinkModuleInlineAsm) { + bool LinkModuleInlineAsm, bool IsPerformingImport) { IRLinker TheIRLinker(Composite, SharedMDs, IdentifiedStructTypes, std::move(Src), ValuesToLink, std::move(AddLazyFor), - LinkModuleInlineAsm); + LinkModuleInlineAsm, IsPerformingImport); Error E = TheIRLinker.run(); Composite.dropTriviallyDeadConstantArrays(); return E; Index: llvm/trunk/lib/Linker/LinkModules.cpp =================================================================== --- llvm/trunk/lib/Linker/LinkModules.cpp +++ llvm/trunk/lib/Linker/LinkModules.cpp @@ -583,7 +583,8 @@ [this](GlobalValue &GV, IRMover::ValueAdder Add) { addLazyFor(GV, Add); }, - !isPerformingImport())) { + /* LinkModuleInlineAsm */ !isPerformingImport(), + /* IsPerformingImport */ isPerformingImport())) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { DstM.getContext().diagnose(LinkDiagnosticInfo(DS_Error, EIB.message())); HasErrors = true; Index: llvm/trunk/test/ThinLTO/X86/Inputs/debuginfo-cu-import.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/Inputs/debuginfo-cu-import.ll +++ llvm/trunk/test/ThinLTO/X86/Inputs/debuginfo-cu-import.ll @@ -0,0 +1,13 @@ +; ModuleID = 'debuginfo-cu-import2.c' +source_filename = "debuginfo-cu-import2.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define i32 @main() { +entry: + call void (...) @foo() + ret i32 0 +} + +declare void @foo(...) #1 Index: llvm/trunk/test/ThinLTO/X86/debuginfo-cu-import.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/debuginfo-cu-import.ll +++ llvm/trunk/test/ThinLTO/X86/debuginfo-cu-import.ll @@ -0,0 +1,80 @@ +; Test to ensure only the necessary DICompileUnit fields are imported +; for ThinLTO + +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/debuginfo-cu-import.ll -o %t2.bc +; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc + +; Don't import enums, macros, retainedTypes or globals lists. +; Only import local scope imported entities. +; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t.index.bc -o - | llvm-dis -o - | FileCheck %s +; CHECK-NOT: DICompileUnit{{.*}} enums: +; CHECK-NOT: DICompileUnit{{.*}} macros: +; CHECK-NOT: DICompileUnit{{.*}} retainedTypes: +; CHECK-NOT: DICompileUnit{{.*}} globals: +; CHECK: DICompileUnit{{.*}} imports: ![[IMP:[0-9]+]] +; CHECK: ![[IMP]] = !{!{{[0-9]+}}} + +; ModuleID = 'debuginfo-cu-import.c' +source_filename = "debuginfo-cu-import.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define void @foo() #0 !dbg !31 { +entry: + ret void, !dbg !34 +} + +define void @_ZN1A1aEv() #0 !dbg !4 { +entry: + ret void, !dbg !14 +} + +define internal void @_ZN1A1bEv() #0 !dbg !8 { +entry: + ret void, !dbg !15 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!11, !12} +!llvm.ident = !{!13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 (trunk 286863) (llvm/trunk 286875)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, macros: !26, retainedTypes: !35, globals: !37, imports: !9) +!1 = !DIFile(filename: "a2.cc", directory: "") +!2 = !{!23} +!4 = distinct !DISubprogram(name: "a", linkageName: "_ZN1A1aEv", scope: !5, file: !1, line: 7, type: !6, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !30) +!5 = !DINamespace(name: "A", scope: null, file: !1, line: 1) +!6 = !DISubroutineType(types: !7) +!7 = !{null} +!8 = distinct !DISubprogram(name: "b", linkageName: "_ZN1A1bEv", scope: !5, file: !1, line: 8, type: !6, isLocal: true, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !30) +!9 = !{!10, !16} +!10 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !5, entity: !4, line: 8) +!11 = !{i32 2, !"Dwarf Version", i32 4} +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{!"clang version 4.0.0 (trunk 286863) (llvm/trunk 286875)"} +!14 = !DILocation(line: 7, column: 12, scope: !4) +!15 = !DILocation(line: 8, column: 24, scope: !8) +!16 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !17, entity: !19, line: 8) +!17 = distinct !DILexicalBlock(scope: !18, file: !1, line: 9, column: 8) +!18 = distinct !DISubprogram(name: "c", linkageName: "_ZN1A1cEv", scope: !5, file: !1, line: 9, type: !6, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !30) +!19 = distinct !DILexicalBlock(scope: !20, file: !1, line: 10, column: 8) +!20 = distinct !DISubprogram(name: "d", linkageName: "_ZN1A1dEv", scope: !5, file: !1, line: 10, type: !6, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !30) +!21 = !DILocation(line: 9, column: 8, scope: !18) +!22 = !DILocation(line: 10, column: 8, scope: !20) +!23 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "enum1", scope: !5, file: !1, line: 50, size: 32, elements: !30, identifier: "_ZTSN9__gnu_cxx12_Lock_policyE") +!24 = !{!25} +!25 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "StateTag", scope: !5, file: !1, line: 1653, size: 32, elements: !30, identifier: "_ZTSN2v88StateTagE") +!26 = !{!27} +!27 = !DIMacroFile(line: 0, file: !1, nodes: !28) +!28 = !{!29} +!29 = !DIMacro(type: DW_MACINFO_define, line: 3, name: "X", value: "5") +!30 = !{} +!31 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !32, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, variables: !30) +!32 = !DISubroutineType(types: !33) +!33 = !{null} +!34 = !DILocation(line: 3, column: 1, scope: !31) +!35 = !{!36} +!36 = !DICompositeType(tag: DW_TAG_structure_type, name: "Base", line: 1, size: 32, align: 32, file: !1, elements: !30, identifier: "_ZTS4Base") +!37 = !{!38} +!38 = !DIGlobalVariable(name: "version", scope: !5, file: !1, line: 2, type: !36, isLocal: false, isDefinition: true)