Index: include/llvm/Linker/IRMover.h =================================================================== --- include/llvm/Linker/IRMover.h +++ include/llvm/Linker/IRMover.h @@ -63,7 +63,8 @@ bool move(Module &Src, ArrayRef ValuesToLink, std::function AddLazyFor, DenseMap *ValIDToTempMDMap = nullptr, - bool IsMetadataLinkingPostpass = false); + bool IsMetadataLinkingPostpass = false, + bool IsFunctionImport = false); Module &getModule() { return Composite; } private: Index: lib/Linker/IRMover.cpp =================================================================== --- lib/Linker/IRMover.cpp +++ lib/Linker/IRMover.cpp @@ -408,6 +408,11 @@ /// importing). bool IsMetadataLinkingPostpass; + /// Flag indicating that this is a module with a function being + /// imported for ThinLTO. Used to control the amount of metadata + /// linked in. + bool IsFunctionImport; + /// Flags to pass to value mapper invocations. RemapFlags ValueMapperFlags = RF_MoveDistinctMDs; @@ -495,6 +500,10 @@ void linkNamedMDNodes(); + /// For ThinLTO function importing, specialize the import of the + /// compile unit metadata to avoid importing unneeded type definitions. + void linkImportedCompileUnit(); + /// Populate the UnneededSubprograms set with the DISubprogram metadata /// from the source module that we don't need to link into the dest module, /// because the functions were not imported directly or via an inlined body @@ -516,11 +525,12 @@ ArrayRef ValuesToLink, std::function AddLazyFor, DenseMap *ValIDToTempMDMap = nullptr, - bool IsMetadataLinkingPostpass = false) + bool IsMetadataLinkingPostpass = false, + bool IsFunctionImport = false) : DstM(DstM), SrcM(SrcM), AddLazyFor(AddLazyFor), TypeMap(Set), GValMaterializer(this), LValMaterializer(this), IsMetadataLinkingPostpass(IsMetadataLinkingPostpass), - ValIDToTempMDMap(ValIDToTempMDMap) { + IsFunctionImport(IsFunctionImport), ValIDToTempMDMap(ValIDToTempMDMap) { for (GlobalValue *GV : ValuesToLink) maybeAdd(GV); @@ -1287,15 +1297,207 @@ CU->replaceSubprograms(MDTuple::get(CU->getContext(), NewSPs)); } +/// Helper to check if the given DIType is a composite type, and if +/// so, whether it already exists in the dest module. Otherwise, return +/// it as a composite type. Assumes that the provided type is needed +/// in the dest module due to an import. +static DICompositeType * +getCompositeTypeToImport(DIType *Ty, const Module &DstM, + DITypeIdentifierMap &DestTypeIdentifierMap) { + if (!Ty || !isa(Ty)) + return nullptr; + // At this point we have an identifier string for a composite + // type that is needed by something mapped from the source module + // into the dest module. + auto *Composite = dyn_cast(Ty); + // This either returns an existing MDString matching the + // identifier StringRef, or creates a new one (which is + // fine given that we know we need this in the dest module). + auto *NewMDString = + MDString::get(DstM.getContext(), Composite->getIdentifier()); + // If it already exists in the dest type map, no need to + // do anything. + if (NewMDString && + (DestTypeIdentifierMap.find(NewMDString) != DestTypeIdentifierMap.end())) + return nullptr; + return Composite; +} + +/// Recursively walks through the given MDNode's operands to locate +/// the set of reached composite types that do not yet exist in the +/// dest module. Any found are added to the \p RetainWorklist. +static void +findReachedCompositeTypes(const MDNode *Node, const Module &DstM, + DITypeIdentifierMap &SrcTypeIdentifierMap, + DITypeIdentifierMap &DestTypeIdentifierMap, + std::vector &RetainWorklist, + SmallPtrSet &Visited) { + if (!Visited.insert(Node).second) + return; + + for (auto &Op : Node->operands()) { + if (auto *MDS = dyn_cast_or_null(Op.get())) { + // First check if this maps to a composite type in the source. + auto I = SrcTypeIdentifierMap.find(MDS); + if (I == SrcTypeIdentifierMap.end()) + continue; + auto *Ty = cast(I->second); + // Invoke getCompositeTypeToImport to see if this is a composite + // type that is not yet in the dest module. + auto *Composite = + getCompositeTypeToImport(Ty, DstM, DestTypeIdentifierMap); + if (Composite) + RetainWorklist.push_back(Composite); + } else if (auto *OpN = dyn_cast_or_null(Op.get())) + // Recursively check the MDNode operands + findReachedCompositeTypes(OpN, DstM, SrcTypeIdentifierMap, + DestTypeIdentifierMap, RetainWorklist, Visited); + } +} + +void IRLinker::linkImportedCompileUnit() { + NamedMDNode *SrcCompileUnits = SrcM.getNamedMetadata("llvm.dbg.cu"); + NamedMDNode *DestCompileUnits = DstM.getNamedMetadata("llvm.dbg.cu"); + auto SrcTypeIdentifierMap = generateDITypeIdentifierMap(SrcCompileUnits); + auto DestTypeIdentifierMap = generateDITypeIdentifierMap(DestCompileUnits); + for (unsigned I = 0, E = SrcCompileUnits->getNumOperands(); I != E; ++I) { + auto *CU = cast(SrcCompileUnits->getOperand(I)); + assert(CU && "Expected valid compile unit"); + auto *NewFile = + MapMetadata(CU->getFile(), ValueMap, + ValueMapperFlags | RF_NullMapMissingGlobalValues, &TypeMap, + &GValMaterializer); + auto *NewSubprograms = + MapMetadata(CU->getSubprograms().get(), ValueMap, + ValueMapperFlags | RF_NullMapMissingGlobalValues, &TypeMap, + &GValMaterializer); + std::vector RetainWorklist; + if (!IsMetadataLinkingPostpass) { + for (DIType *Ty : CU->getRetainedTypes()) { + // For non-postpass metadata linking, any metadata referenced + // by imported functions should be mapped. If not, then we didn't + // need this composite type (unless it serves as the scope for + // another imported type, which is handled while iterating over + // the worklist. + auto *Composite = dyn_cast(Ty); + if (!Composite) + continue; + Metadata *NewMD = + ValueMap.MD().lookup(Composite->getRawIdentifier()).get(); + if (!NewMD) + continue; + + // Although we know Op is a composite, this will return null + // if it is already mapped into the dest. + Composite = getCompositeTypeToImport(Ty, DstM, DestTypeIdentifierMap); + if (!Composite) + continue; + + RetainWorklist.push_back(Composite); + } + } else { + // For postpass metadata linking, we have not yet mapped in the + // subprograms, so we need to recursively visit any needed subprograms + // to locate all referenced composite types not yet in the dest module. + SmallPtrSet Visited; + for (auto *Op : CU->getSubprograms()) { + if (UnneededSubprograms.count(Op)) + continue; + findReachedCompositeTypes(Op, DstM, SrcTypeIdentifierMap, + DestTypeIdentifierMap, RetainWorklist, + Visited); + } + } + // Next we need to walk up through the scope chain of any reached + // composite types and bring in any composite types that are the outer + // scope for our retained types. + SmallPtrSet RetainSet; + for (auto *Composite : RetainWorklist) { + // Add each visited retained type to the set. + // We can abort the scope walk once we hit an already identified and + // therefore visited retained type. + while (RetainSet.insert(Composite).second) { + // Get the scope of this retained type and check if it is a + // composite that is not yet in the dest module. + DIType *Ty = dyn_cast_or_null( + Composite->getScope().resolve(SrcTypeIdentifierMap)); + Composite = getCompositeTypeToImport(Ty, DstM, DestTypeIdentifierMap); + // If not, we can abort the scope walk. + if (!Composite) + break; + } + } + // Finally, walk through the source modules retained types list and + // add any identified as needed to the list that will be mapped into + // the new compile unit in the dest module. This ensures that the + // retained types list ordering is stable. + SmallVector RetainValues; + for (auto *Ty : CU->getRetainedTypes()) { + auto *Composite = dyn_cast(Ty); + if (!Composite) + continue; + if (!RetainSet.count(Composite)) + continue; + auto *NewScope = + Composite->getScope() + ? MapMetadata(Composite->getScope(), ValueMap, + ValueMapperFlags | RF_NullMapMissingGlobalValues, + &TypeMap, &GValMaterializer) + : nullptr; + auto *NewBaseType = + Composite->getBaseType() + ? MapMetadata(Composite->getBaseType(), ValueMap, + ValueMapperFlags | RF_NullMapMissingGlobalValues, + &TypeMap, &GValMaterializer) + : nullptr; + auto *NewComposite = DICompositeType::get( + CU->getContext(), Composite->getTag(), Composite->getRawName(), + Composite->getFile(), Composite->getLine(), NewScope, NewBaseType, + Composite->getSizeInBits(), Composite->getAlignInBits(), + Composite->getOffsetInBits(), + Composite->getFlags() | DINode::FlagFwdDecl, nullptr /* Elements */, + Composite->getRuntimeLang(), nullptr /* VTableHolder */, + nullptr /* TemplateParams */, Composite->getRawIdentifier()); + RetainValues.push_back(NewComposite); + } + // Create the simple DICompileUnit to hold the necessary + // mapped operands (DISubprogram and DIFile) and other simple + // non-metadata operands. + auto *NewCU = DICompileUnit::getDistinct( + CU->getContext(), CU->getSourceLanguage(), NewFile, + CU->getRawProducer(), CU->isOptimized(), CU->getRawFlags(), + CU->getRuntimeVersion(), CU->getRawSplitDebugFilename(), + CU->getEmissionKind(), nullptr /* EnumTypes */, + MDTuple::get(CU->getContext(), RetainValues), NewSubprograms, + nullptr /* GlobalVariables */, nullptr /* ImportedEntities */, + nullptr /* Macros */, CU->getDWOId()); + stripNullSubprograms(NewCU); + DestCompileUnits->addOperand(NewCU); + } +} + /// Insert all of the named MDNodes in Src into the Dest module. void IRLinker::linkNamedMDNodes() { findNeededSubprograms(); const NamedMDNode *SrcModFlags = SrcM.getModuleFlagsMetadata(); + NamedMDNode *CompileUnits = SrcM.getNamedMetadata("llvm.dbg.cu"); for (const NamedMDNode &NMD : SrcM.named_metadata()) { // Don't link module flags here. Do them separately. if (&NMD == SrcModFlags) continue; NamedMDNode *DestNMD = DstM.getOrInsertNamedMetadata(NMD.getName()); + + // Check if we are importing a function from the source module for + // ThinLTO. In that case we only need to map in metadata for imported + // functions and any required type declarations, and don't need to link in + // the enums, type definitions and other metadata hanging off the + // DICompileUnit. Create a simple DICompileUnit with just the needed + // metadata and other operands populated. + if (&NMD == CompileUnits && IsFunctionImport) { + linkImportedCompileUnit(); + continue; + } + // Add Src elements into Dest node. for (const MDNode *op : NMD.operands()) { MDNode *DestMD = MapMetadata( @@ -1697,9 +1899,10 @@ Module &Src, ArrayRef ValuesToLink, std::function AddLazyFor, DenseMap *ValIDToTempMDMap, - bool IsMetadataLinkingPostpass) { + bool IsMetadataLinkingPostpass, bool IsFunctionImport) { IRLinker TheIRLinker(Composite, IdentifiedStructTypes, Src, ValuesToLink, - AddLazyFor, ValIDToTempMDMap, IsMetadataLinkingPostpass); + AddLazyFor, ValIDToTempMDMap, IsMetadataLinkingPostpass, + IsFunctionImport); bool RetCode = TheIRLinker.run(); Composite.dropTriviallyDeadConstantArrays(); return RetCode; Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -806,7 +806,7 @@ [this](GlobalValue &GV, IRMover::ValueAdder Add) { addLazyFor(GV, Add); }, - ValIDToTempMDMap, false)) + ValIDToTempMDMap, false, isPerformingImport())) return true; Module &DstM = Mover.getModule(); for (auto &P : Internalize) { @@ -839,7 +839,7 @@ if (Mover.move( Src, ValuesToLink.getArrayRef(), [this](GlobalValue &GV, IRMover::ValueAdder Add) { assert(false); }, - ValIDToTempMDMap, true)) + ValIDToTempMDMap, true, true)) return true; return false; } Index: lib/Transforms/Utils/ValueMapper.cpp =================================================================== --- lib/Transforms/Utils/ValueMapper.cpp +++ lib/Transforms/Utils/ValueMapper.cpp @@ -399,6 +399,9 @@ Metadata *llvm::MapMetadata(const Metadata *MD, ValueToValueMapTy &VM, RemapFlags Flags, ValueMapTypeRemapper *TypeMapper, ValueMaterializer *Materializer) { + if (!MD) + return nullptr; + SmallVector DistinctWorklist; Metadata *NewMD = MapMetadataImpl(MD, DistinctWorklist, VM, Flags, TypeMapper, Materializer); Index: test/Linker/thinlto_funcimport_debug.ll =================================================================== --- test/Linker/thinlto_funcimport_debug.ll +++ test/Linker/thinlto_funcimport_debug.ll @@ -10,13 +10,33 @@ ; CHECK: define available_externally i32 @func1 ; Extract out the list of subprograms from each compile unit and ensure -; that neither contains null. +; that neither contains null (by checking that each contains exactly the +; expected number of subprograms). ; CHECK: !{{[0-9]+}} = distinct !DICompileUnit({{.*}} subprograms: ![[SPs1:[0-9]+]] -; CHECK-NOT: ![[SPs1]] = !{{{.*}}null{{.*}}} -; CHECK: !{{[0-9]+}} = distinct !DICompileUnit({{.*}} subprograms: ![[SPs2:[0-9]+]] -; CHECK-NOT: ![[SPs2]] = !{{{.*}}null{{.*}}} +; CHECK: ![[SPs1]] = !{!{{[0-9]+}}} +; Confirm that the enums didn't get pulled in to the imported compile unit +; as it isn't needed here, but ensuring that retainedTypes immediately follows +; emissionKind. +; CHECK: !{{[0-9]+}} = distinct !DICompileUnit({{.*}} emissionKind: {{[0-9]+}}, retainedTypes: ![[RTs:[0-9]+]], subprograms: ![[SPs2:[0-9]+]] +; CHECK: ![[RTs]] = !{![[RT1:[0-9]+]], ![[RT2:[0-9]+]], ![[RT3:[0-9]+]]} +; CompositeID1 is scope of imported func1, should be mapped in as declaration. +; CHECK: ![[RT1]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite1", scope: !"CompositeID2", file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID1") +; CompositeID2 is scope of CompositeID1, and should be mapped as declaration. +; CHECK: ![[RT2]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID2") +; CompositeID3 is scope of non-imported func2, should not be mapped in. +; CompositeID4 is vtableHolder of imported composite type (which won't have +; a vtableHolder on its imported declaration), as well as base +; type of non-imported derived type, neither should cause it to be mapped in. +; CompositeID5 is baseType of imported derived type, should be mapped in as +; declaration. +; CHECK: ![[RT3]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID5") + +; CHECK: ![[SPs2]] = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}} ; CHECK: distinct !DISubprogram(name: "func1" +; This derived type is in the subroutine type list of imported func1, and should +; be mapped in. +; CHECK: DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"CompositeID5" ; CHECK-NOT: distinct !DISubprogram(name: "func2" ; CHECK: distinct !DISubprogram(name: "func3" ; CHECK: distinct !DISubprogram(name: "func4" @@ -27,21 +47,21 @@ target triple = "x86_64-unknown-linux-gnu" ; Function Attrs: nounwind readnone uwtable -define i32 @func1(i32 %n) #0 !dbg !4 { +define i32 @func1(i32 %n) #0 !dbg !12 { entry: - tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !9, metadata !17), !dbg !18 - tail call void @llvm.dbg.value(metadata i32 5, i64 0, metadata !10, metadata !17), !dbg !19 - %cmp = icmp sgt i32 %n, 10, !dbg !20 - %. = select i1 %cmp, i32 10, i32 5, !dbg !22 - tail call void @llvm.dbg.value(metadata i32 %., i64 0, metadata !10, metadata !17), !dbg !19 - ret i32 %., !dbg !23 + tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !18, metadata !30), !dbg !31 + tail call void @llvm.dbg.value(metadata i32 5, i64 0, metadata !19, metadata !30), !dbg !32 + %cmp = icmp sgt i32 %n, 10, !dbg !33 + %. = select i1 %cmp, i32 10, i32 5, !dbg !36 + tail call void @llvm.dbg.value(metadata i32 %., i64 0, metadata !19, metadata !30), !dbg !32 + ret i32 %., !dbg !37 } ; Function Attrs: nounwind readnone uwtable -define i32 @func2(i32 %n) #0 !dbg !11 { +define i32 @func2(i32 %n) #0 !dbg !20 { entry: - tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !13, metadata !17), !dbg !24 - ret i32 %n, !dbg !25 + tail call void @llvm.dbg.value(metadata i32 %n, i64 0, metadata !22, metadata !30), !dbg !38 + ret i32 %n, !dbg !39 } ; Function Attrs: nounwind readnone @@ -51,40 +71,46 @@ attributes #1 = { nounwind readnone } !llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!14, !15} -!llvm.ident = !{!16} +!llvm.module.flags = !{!27, !28} +!llvm.ident = !{!29} -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 251407) (llvm/trunk 251401)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 251407) (llvm/trunk 251401)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !11) !1 = !DIFile(filename: "dbg.c", directory: ".") !2 = !{} -!3 = !{!4, !11, !27, !30} -!4 = distinct !DISubprogram(name: "func1", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, variables: !8) -!5 = !DISubroutineType(types: !6) -!6 = !{!7, !7} -!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) -!8 = !{!9, !10} -!9 = !DILocalVariable(name: "n", arg: 1, scope: !4, file: !1, line: 1, type: !7) -!10 = !DILocalVariable(name: "x", scope: !4, file: !1, line: 2, type: !7) -!11 = distinct !DISubprogram(name: "func2", scope: !1, file: !1, line: 8, type: !5, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !12) -!12 = !{!13} -!13 = !DILocalVariable(name: "n", arg: 1, scope: !11, file: !1, line: 8, type: !7) -!14 = !{i32 2, !"Dwarf Version", i32 4} -!15 = !{i32 2, !"Debug Info Version", i32 3} -!16 = !{!"clang version 3.8.0 (trunk 251407) (llvm/trunk 251401)"} -!17 = !DIExpression() -!18 = !DILocation(line: 1, column: 15, scope: !4) -!19 = !DILocation(line: 2, column: 7, scope: !4) -!20 = !DILocation(line: 3, column: 9, scope: !21, inlinedAt: !26) -!21 = distinct !DILexicalBlock(scope: !27, file: !1, line: 3, column: 7) -!22 = !DILocation(line: 3, column: 7, scope: !4) -!23 = !DILocation(line: 5, column: 3, scope: !4) -!24 = !DILocation(line: 8, column: 15, scope: !11) -!25 = !DILocation(line: 9, column: 3, scope: !11) -!26 = !DILocation(line: 9, column: 3, scope: !4) -!27 = distinct !DISubprogram(name: "func3", scope: !1, file: !1, line: 8, type: !5, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !28) -!28 = !{!29} -!29 = !DILocalVariable(name: "n", arg: 1, scope: !30, file: !1, line: 8, type: !7) -!30 = distinct !DISubprogram(name: "func4", scope: !1, file: !1, line: 8, type: !5, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !31) -!31 = !{!32} -!32 = !DILocalVariable(name: "n", arg: 1, scope: !30, file: !1, line: 8, type: !7) - +!3 = !{!4, !7, !8, !9, !10} +!4 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite1", scope: !"CompositeID2", file: !1, line: 100, size: 64, align: 64, elements: !5, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID1") +!5 = !{!6} +!6 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !"CompositeID1", baseType: !"CompositeID4", flags: DIFlagPublic) +!7 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite2", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID2") +!8 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite3", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID3") +!9 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite4", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, templateParams: !2, identifier: "CompositeID4") +!10 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite5", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, templateParams: !2, identifier: "CompositeID5") +!11 = !{!12, !20, !23, !26} +!12 = distinct !DISubprogram(name: "func1", scope: !"CompositeID1", file: !1, line: 1, type: !13, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, variables: !17) +!13 = !DISubroutineType(types: !14) +!14 = !{!15, !15, !16} +!15 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"CompositeID5", flags: DIFlagPublic) +!17 = !{!18, !19} +!18 = !DILocalVariable(name: "n", arg: 1, scope: !12, file: !1, line: 1, type: !15) +!19 = !DILocalVariable(name: "x", scope: !12, file: !1, line: 2, type: !15) +!20 = distinct !DISubprogram(name: "func2", scope: !"CompositeID3", file: !1, line: 8, type: !13, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !21) +!21 = !{!22} +!22 = !DILocalVariable(name: "n", arg: 1, scope: !20, file: !1, line: 8, type: !15) +!23 = distinct !DISubprogram(name: "func3", scope: !1, file: !1, line: 8, type: !13, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !24) +!24 = !{!25} +!25 = !DILocalVariable(name: "n", arg: 1, scope: !26, file: !1, line: 8, type: !15) +!26 = distinct !DISubprogram(name: "func4", scope: !1, file: !1, line: 8, type: !13, isLocal: false, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !24) +!27 = !{i32 2, !"Dwarf Version", i32 4} +!28 = !{i32 2, !"Debug Info Version", i32 3} +!29 = !{!"clang version 3.8.0 (trunk 251407) (llvm/trunk 251401)"} +!30 = !DIExpression() +!31 = !DILocation(line: 1, column: 15, scope: !12) +!32 = !DILocation(line: 2, column: 7, scope: !12) +!33 = !DILocation(line: 3, column: 9, scope: !34, inlinedAt: !35) +!34 = distinct !DILexicalBlock(scope: !23, file: !1, line: 3, column: 7) +!35 = !DILocation(line: 9, column: 3, scope: !12) +!36 = !DILocation(line: 3, column: 7, scope: !12) +!37 = !DILocation(line: 5, column: 3, scope: !12) +!38 = !DILocation(line: 8, column: 15, scope: !20) +!39 = !DILocation(line: 9, column: 3, scope: !20) Index: test/Transforms/FunctionImport/Inputs/funcimport_debug.ll =================================================================== --- test/Transforms/FunctionImport/Inputs/funcimport_debug.ll +++ test/Transforms/FunctionImport/Inputs/funcimport_debug.ll @@ -3,25 +3,34 @@ target triple = "x86_64-unknown-linux-gnu" ; Function Attrs: nounwind uwtable -define void @func() #0 !dbg !4 { +define void @func() #0 !dbg !12 { entry: - ret void, !dbg !10 + ret void, !dbg !19 } attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!7, !8} -!llvm.ident = !{!9} +!llvm.module.flags = !{!16, !17} +!llvm.ident = !{!18} -!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !11) !1 = !DIFile(filename: "funcimport_debug.c", directory: ".") !2 = !{} -!3 = !{!4} -!4 = distinct !DISubprogram(name: "func", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, variables: !2) -!5 = !DISubroutineType(types: !6) -!6 = !{null} -!7 = !{i32 2, !"Dwarf Version", i32 4} -!8 = !{i32 2, !"Debug Info Version", i32 3} -!9 = !{!"clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)"} -!10 = !DILocation(line: 2, column: 1, scope: !4) +!3 = !{!4, !7, !8, !9, !10} +!4 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite1", scope: !"CompositeID2", file: !1, line: 100, size: 64, align: 64, elements: !5, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID1") +!5 = !{!6} +!6 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !"CompositeID1", baseType: !"CompositeID4", flags: DIFlagPublic) +!7 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite2", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID2") +!8 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite3", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID3") +!9 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite4", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, templateParams: !2, identifier: "CompositeID4") +!10 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite5", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, templateParams: !2, identifier: "CompositeID5") +!11 = !{!12} +!12 = distinct !DISubprogram(name: "func", scope: !"CompositeID1", file: !1, line: 1, type: !13, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, variables: !2) +!13 = !DISubroutineType(types: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"CompositeID5", flags: DIFlagPublic) +!16 = !{i32 2, !"Dwarf Version", i32 4} +!17 = !{i32 2, !"Debug Info Version", i32 3} +!18 = !{!"clang version 3.8.0 (trunk 255685) (llvm/trunk 255682)"} +!19 = !DILocation(line: 2, column: 1, scope: !12) Index: test/Transforms/FunctionImport/funcimport_debug.ll =================================================================== --- test/Transforms/FunctionImport/funcimport_debug.ll +++ test/Transforms/FunctionImport/funcimport_debug.ll @@ -14,8 +14,26 @@ ; CHECK: !{{[0-9]+}} = distinct !DICompileUnit({{.*}} subprograms: ![[SPs1:[0-9]+]] ; CHECK: ![[SPs1]] = !{![[MAINSP:[0-9]+]]} ; CHECK: ![[MAINSP]] = distinct !DISubprogram(name: "main" -; CHECK: !{{[0-9]+}} = distinct !DICompileUnit({{.*}} subprograms: ![[SPs2:[0-9]+]] -; CHECK-NOT: ![[SPs2]] = !{{{.*}}null{{.*}}} + +; Confirm that the enums didn't get pulled in to the imported compile unit +; as it isn't needed here, but ensuring that retainedTypes immediately follows +; emissionKind. +; CHECK: !{{[0-9]+}} = distinct !DICompileUnit({{.*}} emissionKind: {{[0-9]+}}, retainedTypes: ![[RTs:[0-9]+]], subprograms: ![[SPs2:[0-9]+]] + +; CHECK: ![[RTs]] = !{![[RT1:[0-9]+]], ![[RT2:[0-9]+]], ![[RT3:[0-9]+]]} +; CompositeID1 is scope of imported func, should be mapped in as declaration. +; CHECK: ![[RT1]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite1", scope: !"CompositeID2", file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID1") +; CompositeID2 is scope of CompositeID1, and should be mapped as declaration. +; CHECK: ![[RT2]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite2", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID2") +; CompositeID3 is not referenced (in reality could be the scope of a +; non-imported function), and should not be mapped in. +; CompositeID4 is vtableHolder of imported composite type (which won't have +; a vtableHolder on its imported declaration), as well as base +; type of non-imported derived type, neither should cause it to be mapped in. +; CompositeID5 is baseType of imported derived type, should be mapped in as +; declaration. +; CHECK: ![[RT3]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID5") + ; CHECK: ![[SPs2]] = !{![[FUNCSP:[0-9]+]]} ; CHECK: ![[FUNCSP]] = distinct !DISubprogram(name: "func" ; CHECK-NOT: distinct !DISubprogram