Index: include/llvm/Linker/IRMover.h =================================================================== --- include/llvm/Linker/IRMover.h +++ include/llvm/Linker/IRMover.h @@ -63,7 +63,8 @@ bool move(std::unique_ptr 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 @@ -17,9 +17,16 @@ #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/TypeFinder.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils/Cloning.h" using namespace llvm; +/// Flag whether we need to import full type definitions for ThinLTO. +/// Currently needed for Darwin and LLDB. +static cl::opt ImportFullTypeDefinitions( + "import-full-type-definitions", cl::init(false), cl::Hidden, + cl::desc("Import full type definitions for ThinLTO.")); + //===----------------------------------------------------------------------===// // TypeMap implementation. //===----------------------------------------------------------------------===// @@ -408,6 +415,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 +507,24 @@ void linkNamedMDNodes(); + /// For ThinLTO function importing, specialize the import of the + /// compile unit metadata to avoid importing unneeded type definitions. + void linkImportedCompileUnits(); + + /// Helper to create a new retained type declaration when importing + /// only the needed metadata (e.g. for ThinLTO). + Metadata *importRetainedTypeAsDeclaration( + DICompositeType *Composite, + DenseMap &RetainMap, + DICompileUnit *CU); + + /// Helper to import a scope for ThinLTO, importing as a type declaration + /// if appropriate. + Metadata * + importScope(Metadata *Ty, + DenseMap &RetainMap, + DICompileUnit *CU); + /// 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 +546,12 @@ std::unique_ptr SrcM, ArrayRef ValuesToLink, std::function AddLazyFor, DenseMap *ValIDToTempMDMap = nullptr, - bool IsMetadataLinkingPostpass = false) + bool IsMetadataLinkingPostpass = false, + bool IsFunctionImport = false) : DstM(DstM), SrcM(std::move(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 +1318,210 @@ 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; +} + +Metadata *IRLinker::importRetainedTypeAsDeclaration( + DICompositeType *Composite, + DenseMap &RetainMap, + DICompileUnit *CU) { + auto RMI = RetainMap.find(Composite); + // An entry should have been made in the map for any retained type + // that is needed, and we should only invoke this for needed retained types. + assert(RMI != RetainMap.end()); + // If we already created a new composite type declaration, use it. + if (auto *NewComposite = RMI->second) + return NewComposite; + + // This is the first time we invoked this routine for this composite + // type. Create a declaration for the imported copy. + // For now we include the size and alignment in bits, as this is consistent + // with other type declarations created by the compiler, but it isn't clear + // that they are needed. + auto *NewScope = importScope(Composite->getScope(), RetainMap, CU); + auto *NewComposite = DICompositeType::get( + CU->getContext(), Composite->getTag(), Composite->getRawName(), + Composite->getFile(), Composite->getLine(), NewScope, + nullptr /* BaseType */, Composite->getSizeInBits(), + Composite->getAlignInBits(), 0 /* OffsetInBits */, + Composite->getFlags() | DINode::FlagFwdDecl, nullptr /* Elements */, + Composite->getRuntimeLang(), nullptr /* VTableHolder */, + nullptr /* TemplateParams */, Composite->getRawIdentifier()); + // Save this new declaration so it is used elsewhere (either in the + // imported retained types map, or as the scope in other imported + // composite types). + RetainMap[Composite] = NewComposite; + return NewComposite; +} + +Metadata * +IRLinker::importScope(Metadata *Scope, + DenseMap &RetainMap, + DICompileUnit *CU) { + if (!Scope) + return nullptr; + // If scope is a composite type, we want to import it as a declaration. + // Any existing imported copy in the \p RetainMap is used. + if (isa(Scope)) + return importRetainedTypeAsDeclaration(dyn_cast(Scope), + RetainMap, CU); + // Otherwise, map the scope metadata normally. + return MapMetadata(Scope, ValueMap, + ValueMapperFlags | RF_NullMapMissingGlobalValues, &TypeMap, + &GValMaterializer); +} + +void IRLinker::linkImportedCompileUnits() { + 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); + // Map in any needed subprograms before walking the retained types list + // below. This ensures that in the case of postpass metadata linking we + // have already mapped in any composite types reached via direct reference. + auto *NewSubprograms = + MapMetadata(CU->getSubprograms().get(), ValueMap, + ValueMapperFlags | RF_NullMapMissingGlobalValues, &TypeMap, + &GValMaterializer); + std::vector RetainWorklist; + // Any metadata reached from imported functions via direct + // references would have been mapped in via the MapMetadata() calls in + // IRLinker::linkFunctionBody() and above when creating the new + // subprograms list. We just need to identify which retained + // types were mapped, and add those to the list we will later process + // the scope chain of and add to the imported DICompileUnit. + for (DIType *Ty : CU->getRetainedTypes()) { + // If the retained type is not mapped at this point, 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 already existed in the dest module. + Composite = getCompositeTypeToImport(Ty, DstM, DestTypeIdentifierMap); + if (!Composite) + continue; + + RetainWorklist.push_back(Composite); + } + // 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. Insert into the map with a null value, + // which will eventually be replaced with the imported type declaration. + DenseMap RetainMap; + for (auto *Composite : RetainWorklist) { + // Add each visited retained type to the map. + // We can abort the scope walk once we hit an already identified and + // therefore visited retained type. + while (RetainMap.insert(std::make_pair(Composite, nullptr)).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; + // First check if this was identified as needed for an imported function, + // possibly indirectly via a scope chain of another needed type. + auto RMI = RetainMap.find(Composite); + if (RMI == RetainMap.end()) + continue; + // Import it as a type declaration. The \p RetainMap is used to + // ensure we import as a declaration exactly once. The composite + // type might be encountered both in this retained types list and + // again in the scope chain of another imported retained type. + auto *NewComposite = + importRetainedTypeAsDeclaration(Composite, RetainMap, CU); + 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 && + !ImportFullTypeDefinitions) { + linkImportedCompileUnits(); + continue; + } + // Add Src elements into Dest node. for (const MDNode *op : NMD.operands()) { MDNode *DestMD = MapMetadata( @@ -1698,10 +1924,10 @@ std::unique_ptr Src, ArrayRef ValuesToLink, std::function AddLazyFor, DenseMap *ValIDToTempMDMap, - bool IsMetadataLinkingPostpass) { + bool IsMetadataLinkingPostpass, bool IsFunctionImport) { IRLinker TheIRLinker(Composite, IdentifiedStructTypes, std::move(Src), ValuesToLink, AddLazyFor, ValIDToTempMDMap, - IsMetadataLinkingPostpass); + IsMetadataLinkingPostpass, IsFunctionImport); bool RetCode = TheIRLinker.run(); Composite.dropTriviallyDeadConstantArrays(); return RetCode; Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -535,7 +535,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) { @@ -563,7 +563,7 @@ if (Mover.move( std::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,43 @@ 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, !tbaa !27 } 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, !20, !21, !28} +!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) +!20 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite6", scope: !21, file: !1, line: 100, size: 64, align: 64, elements: !5, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID6") +!21 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite7", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !22, vtableHolder: !"CompositeID4", templateParams: !2, identifier: "CompositeID7") +!22 = !{!23} +!23 = !DISubprogram(name: "func2", scope: !1, file: !1, line: 1158, type: !24, isLocal: false, isDefinition: false, scopeLine: 1158, flags: DIFlagPrototyped, isOptimized: true) +!24 = !DISubroutineType(types: !25) +!25 = !{!26} +!26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"CompositeID8", size: 64, align: 64) +!27 = !{!"CompositeID6"} +!28 = !DICompositeType(tag: DW_TAG_class_type, name: "Composite8", scope: !1, file: !1, line: 100, size: 64, align: 64, elements: !2, templateParams: !2, identifier: "CompositeID8") Index: test/Transforms/FunctionImport/funcimport_debug.ll =================================================================== --- test/Transforms/FunctionImport/funcimport_debug.ll +++ test/Transforms/FunctionImport/funcimport_debug.ll @@ -14,8 +14,34 @@ ; 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]+]], ![[RT4:[0-9]+]], ![[RT5:[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") +; CompositeID6 is referenced via a tbaa instruction attachment in the imported +; function and should be mapped in as a declaration. +; CHECK: ![[RT4]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite6", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID6") +; CompositeID7 is the scope of needed CompositeID6, and should be mapped in as +; a declaration. +; CHECK: ![[RT5]] = !DICompositeType(tag: DW_TAG_class_type, name: "Composite7", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 100, size: 64, align: 64, flags: DIFlagFwdDecl, identifier: "CompositeID7") +; CompositeID8 is only reached via the definition of CompositeID7, and should +; not be mapped in. + ; CHECK: ![[SPs2]] = !{![[FUNCSP:[0-9]+]]} ; CHECK: ![[FUNCSP]] = distinct !DISubprogram(name: "func" ; CHECK-NOT: distinct !DISubprogram