Index: include/llvm/Linker/IRMover.h =================================================================== --- include/llvm/Linker/IRMover.h +++ include/llvm/Linker/IRMover.h @@ -77,7 +77,7 @@ /// when importing for ThinLTO, otherwise we can have duplicate symbols. Error move(std::unique_ptr Src, ArrayRef ValuesToLink, std::function AddLazyFor, - bool LinkModuleInlineAsm); + bool LinkModuleInlineAsm, bool IsPerformingImport); Module &getModule() { return Composite; } private: Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ 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: lib/Linker/IRMover.cpp =================================================================== --- lib/Linker/IRMover.cpp +++ lib/Linker/IRMover.cpp @@ -480,6 +480,7 @@ Function *copyFunctionProto(const Function *SF); GlobalValue *copyGlobalAliasProto(const GlobalAlias *SGA); + void linkImportedCompileUnits(); void linkNamedMDNodes(); public: @@ -487,7 +488,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 +499,8 @@ ValueMap.getMDMap() = std::move(SharedMDs); for (GlobalValue *GV : ValuesToLink) maybeAdd(GV); + if (IsPerformingImport) + linkImportedCompileUnits(); } ~IRLinker() { SharedMDs = std::move(*ValueMap.getMDMap()); } @@ -1005,6 +1008,61 @@ return Error::success(); } +// When importing for ThinLTO, prevent importing of types listed on +// the DICompileUnit that we don't need a copy of in the importing +// module. Do this by setting their value map entries to nullptr, +// which will automatically prevent their importing when reached +// from the DICompileUnit during metadata mapping. +void IRLinker::linkImportedCompileUnits() { + NamedMDNode *SrcCompileUnits = SrcM->getNamedMetadata("llvm.dbg.cu"); + if (!SrcCompileUnits) + return; + 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. + 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. Create a list of those, and replace the source CU's + // imported entity list with the new list, so only those are mapped in. + 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 +1424,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: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -583,7 +583,7 @@ [this](GlobalValue &GV, IRMover::ValueAdder Add) { addLazyFor(GV, Add); }, - !isPerformingImport())) { + !isPerformingImport(), isPerformingImport())) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) { DstM.getContext().diagnose(LinkDiagnosticInfo(DS_Error, EIB.message())); HasErrors = true; Index: test/ThinLTO/X86/Inputs/debuginfo-cu-import.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/Inputs/debuginfo-cu-import.ll @@ -0,0 +1,31 @@ +; ModuleID = 'test.c' +source_filename = "test.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() #0 !dbg !6 { +entry: + call void (...) @foo(), !dbg !10 + ret i32 0, !dbg !11 +} + +declare void @foo(...) #1 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 289058) (llvm/trunk 289060)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +!1 = !DIFile(filename: "test.c", directory: ".") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 4.0.0 (trunk 289058) (llvm/trunk 289060)"} +!6 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 2, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, variables: !2) +!7 = !DISubroutineType(types: !8) +!8 = !{!9} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DILocation(line: 3, column: 3, scope: !6) +!11 = !DILocation(line: 4, column: 1, scope: !6) + Index: test/ThinLTO/X86/debuginfo-cu-import.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/debuginfo-cu-import.ll @@ -0,0 +1,81 @@ +; 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]] = !{![[IMPENTITY:[0-9]+]]} +; CHECK: ![[IMPENTITY]] = !DIImportedEntity + +; ModuleID = 'test3.c' +source_filename = "test3.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)