diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -61,11 +61,6 @@ /// The start of the unit macro info within macro section. MCSymbol *MacroLabelBegin; - using ImportedEntityList = SmallVector; - using ImportedEntityMap = DenseMap; - - ImportedEntityMap ImportedEntities; - /// GlobalNames - A map of globally visible named entities for this unit. StringMap GlobalNames; @@ -79,9 +74,14 @@ // ranges/locs. const MCSymbol *BaseAddress = nullptr; - DenseMap AbstractSPDies; + DenseMap LocalScopeDIEs; + DenseMap AbstractLocalScopeDIEs; DenseMap> AbstractEntities; + /// LocalScopesWithLocalDecls - A list of non-empty local scopes + /// (with declaraions of static locals, function-local types, or imports). + SmallPtrSet LocalScopesWithLocalDecls; + /// DWO ID for correlating skeleton and split units. uint64_t DWOId = 0; @@ -94,10 +94,10 @@ bool isDwoUnit() const override; - DenseMap &getAbstractSPDies() { + DenseMap &getAbstractScopeDIEs() { if (isDwoUnit() && !DD->shareAcrossDWOCUs()) - return AbstractSPDies; - return DU->getAbstractSPDies(); + return AbstractLocalScopeDIEs; + return DU->getAbstractScopeDIEs(); } DenseMap> &getAbstractEntities() { @@ -171,17 +171,6 @@ unsigned getOrCreateSourceID(const DIFile *File) override; - void addImportedEntity(const DIImportedEntity* IE) { - DIScope *Scope = IE->getScope(); - assert(Scope && "Invalid Scope encoding!"); - if (!isa(Scope)) - // No need to add imported enities that are not local declaration. - return; - - auto *LocalScope = cast(Scope)->getNonLexicalBlockFileScope(); - ImportedEntities[LocalScope].push_back(IE); - } - /// addRange - Add an address range to the list of ranges for this unit. void addRange(RangeSpan Range); @@ -223,6 +212,9 @@ void createBaseTypeDIEs(); + DIE *findLocalScopeDIE(const DIScope *S); + DIE *getOrCreateContextDIE(const DIScope *Ty) override; + /// Construct a DIE for this subprogram scope. DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope); @@ -261,8 +253,9 @@ void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE, SmallVector &Params); - /// Construct import_module DIE. - DIE *constructImportedEntityDIE(const DIImportedEntity *Module); + /// Construct DIE for an imported entity. + DIE *createImportedEntityDIE(const DIImportedEntity *IE); + void createAndAddImportedEntityDIE(const DIImportedEntity *IE); void finishSubprogramDefinition(const DISubprogram *SP); void finishEntityDefinition(const DbgEntity *Entity); @@ -359,6 +352,10 @@ bool hasDwarfPubSections() const; void addBaseTypeRef(DIEValueList &Die, int64_t Idx); + + void recordLocalScopeWithDecls(const DILocalScope *S) { + LocalScopesWithLocalDecls.insert(S); + } }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -558,8 +558,18 @@ // Emit lexical blocks. DIE *ScopeDIE = constructLexicalScopeDIE(Scope); assert(ScopeDIE && "Scope DIE should not be null."); - ParentScopeDIE.addChild(ScopeDIE); + + // Track abstract and concrete lexical block scopes. + if (Scope->isAbstractScope()) { + assert(!getAbstractScopeDIEs().count(DS) && + "Abstract DIE for this scope exists!"); + getAbstractScopeDIEs()[DS] = ScopeDIE; + } else if (!Scope->getInlinedAt()) { + assert(!LocalScopeDIEs.count(DS) && "Concrete DIE for this scope exists!"); + LocalScopeDIEs[DS] = ScopeDIE; + } + createAndAddScopeChildren(Scope, *ScopeDIE); } @@ -653,7 +663,7 @@ auto *InlinedSP = getDISubprogram(DS); // Find the subprogram's DwarfCompileUnit in the SPMap in case the subprogram // was inlined from another compile unit. - DIE *OriginDIE = getAbstractSPDies()[InlinedSP]; + DIE *OriginDIE = getAbstractScopeDIEs()[InlinedSP]; assert(OriginDIE && "Unable to find original DIE for an inlined subprogram."); auto ScopeDIE = DIE::get(DIEValueAllocator, dwarf::DW_TAG_inlined_subroutine); @@ -1017,6 +1027,15 @@ if (Scope) { assert(!Scope->getInlinedAt()); assert(!Scope->isAbstractScope()); + + // Track record in which CU this subprogram gets emitted. + DD->recordSPContainingCU(Sub, this); + + // Record the subrogram scope before creating child entities. + assert(!LocalScopeDIEs.count(Sub) && + "Concrete DIE for the subprogram exists!"); + LocalScopeDIEs[Sub] = &ScopeDIE; + // Collect lexical scope children first. // ObjectPointer might be a local (non-argument) local variable if it's a // block's synthetic this pointer. @@ -1052,27 +1071,18 @@ for (DbgVariable *DV : Locals) ScopeDIE.addChild(constructVariableDIE(*DV, *Scope, ObjectPointer)); - // Emit imported entities (skipped in gmlt-like data). - if (!includeMinimalInlineScopes()) { - for (const auto *IE : ImportedEntities[Scope->getScopeNode()]) - ScopeDIE.addChild(constructImportedEntityDIE(cast(IE))); - } - // Emit labels. for (DbgLabel *DL : DU->getScopeLabels().lookup(Scope)) ScopeDIE.addChild(constructLabelDIE(*DL, *Scope)); // Emit inner lexical scopes. - auto needToEmitLexicalScope = [this](LexicalScope *LS) { + auto needToEmitLexicalScope = [this](LexicalScope *LS) -> bool { if (isa(LS->getScopeNode())) return true; auto Vars = DU->getScopeVariables().lookup(LS); if (!Vars.Args.empty() || !Vars.Locals.empty()) return true; - if (!includeMinimalInlineScopes() && - !ImportedEntities[LS->getScopeNode()].empty()) - return true; - return false; + return LocalScopesWithLocalDecls.count(LS->getScopeNode()); }; for (LexicalScope *LS : Scope->getChildren()) { // If the lexical block doesn't have non-scope children, skip @@ -1088,11 +1098,10 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( LexicalScope *Scope) { - DIE *&AbsDef = getAbstractSPDies()[Scope->getScopeNode()]; - if (AbsDef) - return; auto *SP = cast(Scope->getScopeNode()); + if (getAbstractScopeDIEs().count(SP)) + return; DIE *ContextDIE; DwarfCompileUnit *ContextCU = this; @@ -1114,16 +1123,24 @@ ContextCU = DD->lookupCU(ContextDIE->getUnitDie()); } + // Track record in which CU this subprogram is emitted. + DD->recordSPContainingCU(SP, ContextCU); + // Passing null as the associated node because the abstract definition // shouldn't be found by lookup. - AbsDef = &ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, nullptr); - ContextCU->applySubprogramAttributesToDefinition(SP, *AbsDef); - ContextCU->addSInt(*AbsDef, dwarf::DW_AT_inline, + DIE &AbsDef = ContextCU->createAndAddDIE(dwarf::DW_TAG_subprogram, + *ContextDIE, nullptr); + + // Store the DIE before creating children. + getAbstractScopeDIEs()[SP] = &AbsDef; + + ContextCU->applySubprogramAttributesToDefinition(SP, AbsDef); + ContextCU->addSInt(AbsDef, dwarf::DW_AT_inline, DD->getDwarfVersion() <= 4 ? Optional() : dwarf::DW_FORM_implicit_const, dwarf::DW_INL_inlined); - if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, *AbsDef)) - ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer); + if (DIE *ObjectPointer = ContextCU->createAndAddScopeChildren(Scope, AbsDef)) + ContextCU->addDIEEntry(AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer); } bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const { @@ -1257,47 +1274,62 @@ } } -DIE *DwarfCompileUnit::constructImportedEntityDIE( - const DIImportedEntity *Module) { - DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)Module->getTag()); - insertDIE(Module, IMDie); +DIE *DwarfCompileUnit::createImportedEntityDIE(const DIImportedEntity *IE) { + DIE *IMDie = DIE::get(DIEValueAllocator, (dwarf::Tag)IE->getTag()); + insertDIE(IE, IMDie); + DIE *EntityDie; - auto *Entity = Module->getEntity(); + auto *Entity = IE->getEntity(); if (auto *NS = dyn_cast(Entity)) EntityDie = getOrCreateNameSpace(NS); else if (auto *M = dyn_cast(Entity)) EntityDie = getOrCreateModule(M); - else if (auto *SP = dyn_cast(Entity)) - EntityDie = getOrCreateSubprogramDIE(SP); - else if (auto *T = dyn_cast(Entity)) + else if (auto *SP = dyn_cast(Entity)) { + // If we have abstract subprogram created, refer it. + if (auto *AbsSPDie = getAbstractScopeDIEs().lookup(SP)) + EntityDie = AbsSPDie; + else + EntityDie = getOrCreateSubprogramDIE(SP); + } else if (auto *T = dyn_cast(Entity)) EntityDie = getOrCreateTypeDIE(T); else if (auto *GV = dyn_cast(Entity)) EntityDie = getOrCreateGlobalVariableDIE(GV, {}); else EntityDie = getDIE(Entity); assert(EntityDie); - addSourceLine(*IMDie, Module->getLine(), Module->getFile()); + + addSourceLine(*IMDie, IE->getLine(), IE->getFile()); addDIEEntry(*IMDie, dwarf::DW_AT_import, *EntityDie); - StringRef Name = Module->getName(); + StringRef Name = IE->getName(); if (!Name.empty()) addString(*IMDie, dwarf::DW_AT_name, Name); // This is for imported module with renamed entities (such as variables and // subprograms). - DINodeArray Elements = Module->getElements(); + DINodeArray Elements = IE->getElements(); for (const auto *Element : Elements) { if (!Element) continue; - IMDie->addChild( - constructImportedEntityDIE(cast(Element))); + IMDie->addChild(createImportedEntityDIE(cast(Element))); } - return IMDie; } +void DwarfCompileUnit::createAndAddImportedEntityDIE( + const DIImportedEntity *IE) { + + DIE *ContextDIE = getOrCreateContextDIE(IE->getScope()); + assert(ContextDIE && + "Could not get or create scope for the imported entity!"); + if (!ContextDIE) + return; + + ContextDIE->addChild(createImportedEntityDIE(IE)); +} + void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP) { DIE *D = getDIE(SP); - if (DIE *AbsSPDIE = getAbstractSPDies().lookup(SP)) { + if (DIE *AbsSPDIE = getAbstractScopeDIEs().lookup(SP)) { if (D) // If this subprogram has an abstract definition, reference that addDIEEntry(*D, dwarf::DW_AT_abstract_origin, *AbsSPDIE); @@ -1588,3 +1620,38 @@ Btr.Die = &Die; } } + +static DIE * +findLocalScopeDIE(const DILocalScope *LS, + DenseMap &ScopeDIEs) { + DIE *ScopeDIE = ScopeDIEs.lookup(LS); + if (isa(LS) && !ScopeDIE) + return nullptr; + if (!ScopeDIE) + return findLocalScopeDIE(cast(LS->getScope()), ScopeDIEs); + return ScopeDIE; +} + +DIE *DwarfCompileUnit::findLocalScopeDIE(const DIScope *S) { + auto *LScope = dyn_cast_or_null(S); + if (!LScope) + return nullptr; + + // Check if we have an abstract tree. + if (getAbstractScopeDIEs().count(LScope->getSubprogram())) + return ::findLocalScopeDIE(LScope, getAbstractScopeDIEs()); + + return ::findLocalScopeDIE(LScope, LocalScopeDIEs); +} + +DIE *DwarfCompileUnit::getOrCreateContextDIE(const DIScope *Context) { + if (auto *LScope = dyn_cast_or_null(Context)) { + if (DIE *ScopeDIE = findLocalScopeDIE(LScope)) + return ScopeDIE; + + // If nothing was found, fall back to DISubprogram and let + // DwarfUnit::getOrCreateContextDIE() create a new DIE for it. + Context = LScope->getSubprogram(); + } + return DwarfUnit::getOrCreateContextDIE(Context); +} diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -314,11 +314,16 @@ /// can refer to them in spite of insertions into this list. DebugLocStream DebugLocs; + /// Maps subprogram to its containing DwarfCompileUnit(s). + DenseMap> SPCUsMap; + + using SubprogramSetVector = + SetVector, + SmallPtrSet>; + /// This is a collection of subprogram MDNodes that are processed to /// create DIEs. - SetVector, - SmallPtrSet> - ProcessedSPNodes; + SubprogramSetVector ProcessedSPNodes; /// If nonnull, stores the current machine function we're processing. const MachineFunction *CurFn = nullptr; @@ -596,10 +601,6 @@ void finishUnitAttributes(const DICompileUnit *DIUnit, DwarfCompileUnit &NewCU); - /// Construct imported_module or imported_declaration DIE. - void constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, - const DIImportedEntity *N); - /// Register a source line with debug info. Returns the unique /// label that was emitted and which provides correspondence to the /// source line list. @@ -840,6 +841,9 @@ /// If the \p File has an MD5 checksum, return it as an MD5Result /// allocated in the MCContext. Optional getMD5AsBytes(const DIFile *File) const; + + /// Track records of CUs containg the given subprogram. + void recordSPContainingCU(const DISubprogram *SP, DwarfCompileUnit *CU); }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -513,7 +513,7 @@ // well into the name table. Only do that if we are going to actually emit // that name. if (SP->getLinkageName() != "" && SP->getName() != SP->getLinkageName() && - (useAllLinkageNames() || InfoHolder.getAbstractSPDies().lookup(SP))) + (useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(SP))) addAccelName(CU, SP->getLinkageName(), Die); // If this is an Objective-C selector name add it to the ObjC accelerator @@ -1064,6 +1064,45 @@ } } } + +// Collect local scopes that contain any local declarations +// (excluding local variables) to be sure they will be emitted +// (see DwarfCompileUnit::createAndAddScopeChildren() for details). +static void collectLocalScopesWithDeclsFromCU(const DICompileUnit *CUNode, + DwarfCompileUnit &CU) { + auto getLocalScope = [](const DIScope *S) -> const DILocalScope * { + if (!S) + return nullptr; + if (isa(S)) + S = S->getScope(); + if (const auto *LScope = dyn_cast_or_null(S)) + return LScope->getNonLexicalBlockFileScope(); + return nullptr; + }; + + for (auto *GVE : CUNode->getGlobalVariables()) + if (auto *LScope = getLocalScope(GVE->getVariable()->getScope())) + CU.recordLocalScopeWithDecls(LScope); + + for (auto *Ty : CUNode->getEnumTypes()) + if (auto *LScope = getLocalScope(Ty->getScope())) + CU.recordLocalScopeWithDecls(LScope); + + for (auto *Ty : CUNode->getRetainedTypes()) + if (DIType *RT = dyn_cast(Ty)) + if (auto *LScope = getLocalScope(RT->getScope())) + CU.recordLocalScopeWithDecls(LScope); + + for (auto *IE : CUNode->getImportedEntities()) + if (auto *LScope = getLocalScope(IE->getScope())) + CU.recordLocalScopeWithDecls(LScope); + + // FIXME: We know nothing about local records and typedefs here, + // since nothing but local variables (and members of local records) + // references them. So that they will be emitted in a first available + // parent scope DIE. +} + // Create new DwarfCompileUnit for the given metadata node with tag // DW_TAG_compile_unit. DwarfCompileUnit & @@ -1078,9 +1117,6 @@ DwarfCompileUnit &NewCU = *OwnedUnit; InfoHolder.addUnit(std::move(OwnedUnit)); - for (auto *IE : DIUnit->getImportedEntities()) - NewCU.addImportedEntity(IE); - // LTO with assembly output shares a single line table amongst multiple CUs. // To avoid the compilation directory being ambiguous, let the line table // explicitly describe the directory of all files, never relying on the @@ -1100,15 +1136,12 @@ CUMap.insert({DIUnit, &NewCU}); CUDieMap.insert({&NewCU.getUnitDie(), &NewCU}); - return NewCU; -} -void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU, - const DIImportedEntity *N) { - if (isa(N->getScope())) - return; - if (DIE *D = TheCU.getOrCreateContextDIE(N->getScope())) - D->addChild(TheCU.constructImportedEntityDIE(N)); + // Record local scopes, that have some globals (static locals), + // imports or types declared within. + collectLocalScopesWithDeclsFromCU(DIUnit, NewCU); + + return NewCU; } // Emit all Dwarf sections that should come prior to the content. Create @@ -1351,6 +1384,7 @@ assert(CurFn == nullptr); assert(CurMI == nullptr); + // Collect global variables info. DenseMap> GVMap; for (const GlobalVariable &Global : MMI->getModule()->globals()) { @@ -1360,6 +1394,23 @@ GVMap[GVE->getVariable()].push_back({&Global, GVE->getExpression()}); } + auto findCUAndApply = [this](const DIScope *S, DwarfCompileUnit *TheCU, + std::function F) { + // Create non-local entities in the current CU. + if (!S || !isa(S)) { + F(TheCU); + return; + } + // Create the given local entity for all the CUs its parent function + // was emitted. In most cases it should be a single source (where the + // function was defined) or destination (where the function was inlined) + // compile unit. But in the case of multiple compile units were linked + // together (like, in FullLTO) and split-dwarf enabled w/o allowing + // cross-CU references, there may be a source and multiple destination CUs. + for (auto *CU : SPCUsMap.lookup(cast(S)->getSubprogram())) + F(CU); + }; + for (DICompileUnit *CUNode : MMI->getModule()->debug_compile_units()) { auto *CU = CUMap.lookup(CUNode); @@ -1384,8 +1435,7 @@ // Global Variables. for (auto *GVE : CUNode->getGlobalVariables()) { // Don't bother adding DIGlobalVariableExpressions listed in the CU if we - // already know about the variable and it isn't adding a constant - // expression. + // already know about the variable and it isn't adding a const expression. auto &GVMapEntry = GVMap[GVE->getVariable()]; auto *Expr = GVE->getExpression(); if (!GVMapEntry.size() || (Expr && Expr->isConstant())) @@ -1396,21 +1446,29 @@ for (auto *GVE : CUNode->getGlobalVariables()) { DIGlobalVariable *GV = GVE->getVariable(); if (Processed.insert(GV).second) - CU->getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV])); + findCUAndApply(GV->getScope(), CU, [&](DwarfCompileUnit *U) { + U->getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV])); + }); } for (auto *Ty : CUNode->getEnumTypes()) - CU->getOrCreateTypeDIE(cast(Ty)); + findCUAndApply(Ty->getScope(), CU, [&](DwarfCompileUnit *U) { + U->getOrCreateTypeDIE(cast(Ty)); + }); - for (auto *Ty : CUNode->getRetainedTypes()) + for (auto *Ty : CUNode->getRetainedTypes()) { + // There is no point in force-emitting a forward declaration. if (DIType *RT = dyn_cast(Ty)) - // There is no point in force-emitting a forward declaration. - CU->getOrCreateTypeDIE(RT); + findCUAndApply(RT->getScope(), CU, + [&](DwarfCompileUnit *U) { U->getOrCreateTypeDIE(RT); }); + } - // Emit imported entities last so that the relevant context - // is already available. + // Emit imported entities last so that + // the relevant context is already available. for (auto *IE : CUNode->getImportedEntities()) - constructAndAddImportedEntityDIE(*CU, IE); + findCUAndApply(IE->getScope(), CU, [&](DwarfCompileUnit *U) { + U->createAndAddImportedEntityDIE(IE); + }); CU->createBaseTypeDIEs(); } @@ -3540,3 +3598,10 @@ std::copy(ChecksumString.begin(), ChecksumString.end(), CKMem.data()); return CKMem; } + +void DwarfDebug::recordSPContainingCU(const DISubprogram *SP, + DwarfCompileUnit *CU) { + // Skip CUs for which we don't want to create any local entities. + if (!CU->includeMinimalInlineScopes()) + SPCUsMap[SP].insert(CU); +} diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -26,6 +26,7 @@ class DbgVariable; class DbgLabel; class DINode; +class DILocalScope; class DwarfCompileUnit; class DwarfUnit; class LexicalScope; @@ -87,7 +88,7 @@ DenseMap ScopeLabels; // Collection of abstract subprogram DIEs. - DenseMap AbstractSPDies; + DenseMap AbstractLocalScopeDIEs; DenseMap> AbstractEntities; /// Maps MDNodes for type system with the corresponding DIEs. These DIEs can @@ -162,8 +163,8 @@ return ScopeLabels; } - DenseMap &getAbstractSPDies() { - return AbstractSPDies; + DenseMap &getAbstractScopeDIEs() { + return AbstractLocalScopeDIEs; } DenseMap> &getAbstractEntities() { diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -248,7 +248,7 @@ DIE *getOrCreateTypeDIE(const MDNode *TyNode); /// Get context owner's DIE. - DIE *getOrCreateContextDIE(const DIScope *Context); + virtual DIE *getOrCreateContextDIE(const DIScope *Context); /// Construct DIEs for types that contain vtables. void constructContainingTypeDIEs(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1222,7 +1222,7 @@ "decl has a linkage name and it is different"); if (DeclLinkageName.empty() && // Always emit it for abstract subprograms. - (DD->useAllLinkageNames() || DU->getAbstractSPDies().lookup(SP))) + (DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP))) addLinkageName(SPDie, LinkageName); if (!DeclDie) diff --git a/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll b/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll @@ -0,0 +1,73 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s +; REQUIRES: object-emission + +; namespace ns { +; inline __attribute__((always_inline)) +; void foo() { int a = 4; } +; } +; +; void goo() { +; using ns::foo; +; foo(); +; } + +; Ensure that imported declarations reference the correct subprograms even if +; those subprograms are inlined. + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_namespace +; CHECK: DW_AT_name ("ns") +; CHECK: [[FOO:0x.*]]: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: NULL +; CHECK: DW_TAG_base_type +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("goo") +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin ([[FOO]] +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: DW_TAG_imported_declaration +; CHECK: DW_AT_import ([[FOO]]) +; CHECK: NULL +; CHECK: NULL + +; Function Attrs: mustprogress noinline optnone uwtable +define dso_local void @_Z3goov() !dbg !4 { +entry: + %a.i = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %a.i, metadata !16, metadata !DIExpression()), !dbg !18 + store i32 4, i32* %a.i, align 4, !dbg !18 + ret void, !dbg !20 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!10, !11, !12, !13, !14} +!llvm.ident = !{!15} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "imported-inlined-declaration.cpp", directory: "") +!2 = !{!3} +!3 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !8, file: !1, line: 7) +!4 = distinct !DISubprogram(name: "goo", linkageName: "_Z3goov", scope: !1, file: !1, line: 6, type: !5, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !7) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{} +!8 = distinct !DISubprogram(name: "foo", linkageName: "_ZN2ns3fooEv", scope: !9, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !7) +!9 = !DINamespace(name: "ns", scope: null) +!10 = !{i32 7, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{i32 7, !"uwtable", i32 1} +!14 = !{i32 7, !"frame-pointer", i32 2} +!15 = !{!"clang version 14.0.0"} +!16 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 3, type: !17) +!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!18 = !DILocation(line: 3, column: 18, scope: !8, inlinedAt: !19) +!19 = distinct !DILocation(line: 8, column: 2, scope: !4) +!20 = !DILocation(line: 9, column: 1, scope: !4) diff --git a/llvm/test/DebugInfo/Generic/imported-name-inlined.ll b/llvm/test/DebugInfo/Generic/imported-name-inlined.ll --- a/llvm/test/DebugInfo/Generic/imported-name-inlined.ll +++ b/llvm/test/DebugInfo/Generic/imported-name-inlined.ll @@ -13,21 +13,17 @@ ; Ensure that top level imported declarations don't produce an extra degenerate ; concrete subprogram definition. -; FIXME: imported entities should only be emitted to the abstract origin if one is present - ; CHECK: DW_TAG_compile_unit ; CHECK: DW_TAG_subprogram ; CHECK: DW_AT_name ("f1") ; CHECK: DW_TAG_imported_declaration ; CHECK: NULL -; CHECK: DW_TAG_namespace -; CHECK: DW_TAG_subprogram -; CHECK: NULL ; CHECK: DW_TAG_subprogram ; CHECK: DW_AT_name ("f2") ; CHECK: DW_TAG_inlined_subroutine -; CHECK: DW_TAG_imported_declaration -; CHECK: NULL +; CHECK: NULL +; CHECK: DW_TAG_namespace +; CHECK: DW_TAG_subprogram ; CHECK: NULL ; CHECK: NULL diff --git a/llvm/test/DebugInfo/Generic/inlined-local-type.ll b/llvm/test/DebugInfo/Generic/inlined-local-type.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/inlined-local-type.ll @@ -0,0 +1,126 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s +; REQUIRES: object-emission + +; inline __attribute__((always_inline)) +; int removed() { struct A {int i;}; struct A a; return a.i++; } +; +; __attribute__((always_inline)) +; int not_removed() { struct B {int i;}; struct B b; return b.i++; } +; +; int foo() { return removed() + not_removed(); }} + +; Ensure that function-local types have the correct subprogram parent even if +; those subprograms are inlined. + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin ({{0x.*}} "not_removed") +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("removed") +; CHECK: [[A:0x.*]]: DW_TAG_structure_type +; CHECK: DW_AT_name ("A") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type ([[A]] "A") +; CHECK: NULL +; CHECK: DW_TAG_base_type +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("not_removed") +; CHECK: [[B:0x.*]]: DW_TAG_structure_type +; CHECK: DW_AT_name ("B") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type ([[B]] "B") +; CHECK: NULL +; CHECK: DW_TAG_subprogram +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +%struct.B = type { i32 } +%struct.A = type { i32 } + +define dso_local i32 @not_removed() !dbg !12 { + %1 = alloca %struct.B, align 4 + call void @llvm.dbg.declare(metadata %struct.B* %1, metadata !18, metadata !DIExpression()), !dbg !22 + %2 = getelementptr inbounds %struct.B, %struct.B* %1, i32 0, i32 0, !dbg !23 + %3 = load i32, i32* %2, align 4, !dbg !24 + %4 = add nsw i32 %3, 1, !dbg !24 + store i32 %4, i32* %2, align 4, !dbg !24 + ret i32 %3, !dbg !25 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +define dso_local i32 @foo() !dbg !26 { + %1 = alloca %struct.A, align 4 + %2 = alloca %struct.B, align 4 + call void @llvm.dbg.declare(metadata %struct.A* %1, metadata !27, metadata !DIExpression()), !dbg !32 + %3 = getelementptr inbounds %struct.A, %struct.A* %1, i32 0, i32 0, !dbg !34 + %4 = load i32, i32* %3, align 4, !dbg !35 + %5 = add nsw i32 %4, 1, !dbg !35 + store i32 %5, i32* %3, align 4, !dbg !35 + call void @llvm.dbg.declare(metadata %struct.B* %2, metadata !18, metadata !DIExpression()), !dbg !36 + %6 = getelementptr inbounds %struct.B, %struct.B* %2, i32 0, i32 0, !dbg !38 + %7 = load i32, i32* %6, align 4, !dbg !39 + %8 = add nsw i32 %7, 1, !dbg !39 + store i32 %8, i32* %6, align 4, !dbg !39 + %9 = add nsw i32 %4, %7, !dbg !40 + ret i32 %9, !dbg !41 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "inlined-local-type.cpp", directory: "") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 1, !"branch-target-enforcement", i32 0} +!6 = !{i32 1, !"sign-return-address", i32 0} +!7 = !{i32 1, !"sign-return-address-all", i32 0} +!8 = !{i32 1, !"sign-return-address-with-bkey", i32 0} +!9 = !{i32 7, !"uwtable", i32 1} +!10 = !{i32 7, !"frame-pointer", i32 1} +!11 = !{!"clang version 14.0.0"} +!12 = distinct !DISubprogram(name: "not_removed", scope: !13, file: !13, line: 5, type: !14, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !17) +!13 = !DIFile(filename: "inlined-local-type.cpp", directory: "") +!14 = !DISubroutineType(types: !15) +!15 = !{!16} +!16 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!17 = !{} +!18 = !DILocalVariable(name: "b", scope: !12, file: !13, line: 5, type: !19) +!19 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", scope: !12, file: !13, line: 5, size: 32, elements: !20) +!20 = !{!21} +!21 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !19, file: !13, line: 5, baseType: !16, size: 32) +!22 = !DILocation(line: 5, column: 49, scope: !12) +!23 = !DILocation(line: 5, column: 61, scope: !12) +!24 = !DILocation(line: 5, column: 62, scope: !12) +!25 = !DILocation(line: 5, column: 52, scope: !12) +!26 = distinct !DISubprogram(name: "foo", scope: !13, file: !13, line: 7, type: !14, scopeLine: 7, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !17) +!27 = !DILocalVariable(name: "a", scope: !28, file: !13, line: 2, type: !29) +!28 = distinct !DISubprogram(name: "removed", scope: !13, file: !13, line: 2, type: !14, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !17) +!29 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", scope: !28, file: !13, line: 2, size: 32, elements: !30) +!30 = !{!31} +!31 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !29, file: !13, line: 2, baseType: !16, size: 32) +!32 = !DILocation(line: 2, column: 45, scope: !28, inlinedAt: !33) +!33 = distinct !DILocation(line: 7, column: 20, scope: !26) +!34 = !DILocation(line: 2, column: 57, scope: !28, inlinedAt: !33) +!35 = !DILocation(line: 2, column: 58, scope: !28, inlinedAt: !33) +!36 = !DILocation(line: 5, column: 49, scope: !12, inlinedAt: !37) +!37 = distinct !DILocation(line: 7, column: 32, scope: !26) +!38 = !DILocation(line: 5, column: 61, scope: !12, inlinedAt: !37) +!39 = !DILocation(line: 5, column: 62, scope: !12, inlinedAt: !37) +!40 = !DILocation(line: 7, column: 30, scope: !26) +!41 = !DILocation(line: 7, column: 13, scope: !26) diff --git a/llvm/test/DebugInfo/Generic/inlined-static-var.ll b/llvm/test/DebugInfo/Generic/inlined-static-var.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/inlined-static-var.ll @@ -0,0 +1,93 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s +; REQUIRES: object-emission + +; inline __attribute__((always_inline)) +; int removed() { static int A; return A++; } +; +; __attribute__((always_inline)) +; int not_removed() { static int B; return B++; } +; +; int foo() { return removed() + not_removed(); } + +; Ensure that global variables belong to the correct subprograms even if those +; subprograms are inlined. + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin {{.*}} "_Z11not_removedv" +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("removed") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("A") +; CHECK: NULL +; CHECK: DW_TAG_base_type +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("not_removed") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("B") +; CHECK: NULL +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_TAG_inlined_subroutine +; CHECK: NULL +; CHECK: NULL + +@_ZZ11not_removedvE1A = internal global i32 0, align 4, !dbg !0 +@_ZZ7removedvE1A = linkonce_odr dso_local global i32 0, align 4, !dbg !10 + +define dso_local i32 @_Z11not_removedv() !dbg !2 { + %1 = load i32, i32* @_ZZ11not_removedvE1A, align 4, !dbg !24 + %2 = add nsw i32 %1, 1, !dbg !24 + store i32 %2, i32* @_ZZ11not_removedvE1A, align 4, !dbg !24 + ret i32 %1, !dbg !25 +} + +define dso_local i32 @_Z3foov() !dbg !26 { + %1 = load i32, i32* @_ZZ7removedvE1A, align 4, !dbg !27 + %2 = add nsw i32 %1, 1, !dbg !27 + store i32 %2, i32* @_ZZ7removedvE1A, align 4, !dbg !27 + %3 = load i32, i32* @_ZZ11not_removedvE1A, align 4, !dbg !29 + %4 = add nsw i32 %3, 1, !dbg !29 + store i32 %4, i32* @_ZZ11not_removedvE1A, align 4, !dbg !29 + %5 = add nsw i32 %1, %3, !dbg !31 + ret i32 %5, !dbg !32 +} + +!llvm.dbg.cu = !{!7} +!llvm.module.flags = !{!14, !15, !16, !17, !18, !19, !20, !21, !22} +!llvm.ident = !{!23} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "B", scope: !2, file: !3, line: 5, type: !6, isLocal: true, isDefinition: true) +!2 = distinct !DISubprogram(name: "not_removed", linkageName: "_Z11not_removedv", scope: !3, file: !3, line: 5, type: !4, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !13) +!3 = !DIFile(filename: "example.cpp", directory: "") +!4 = !DISubroutineType(types: !5) +!5 = !{!6} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !8, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false, nameTableKind: None) +!8 = !DIFile(filename: "example.cpp", directory: "") +!9 = !{!0, !10} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "A", scope: !12, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!12 = distinct !DISubprogram(name: "removed", linkageName: "_Z7removedv", scope: !3, file: !3, line: 2, type: !4, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !13) +!13 = !{} +!14 = !{i32 7, !"Dwarf Version", i32 4} +!15 = !{i32 2, !"Debug Info Version", i32 3} +!16 = !{i32 1, !"wchar_size", i32 4} +!17 = !{i32 1, !"branch-target-enforcement", i32 0} +!18 = !{i32 1, !"sign-return-address", i32 0} +!19 = !{i32 1, !"sign-return-address-all", i32 0} +!20 = !{i32 1, !"sign-return-address-with-bkey", i32 0} +!21 = !{i32 7, !"uwtable", i32 1} +!22 = !{i32 7, !"frame-pointer", i32 1} +!23 = !{!"clang version 14.0.0"} +!24 = !DILocation(line: 5, column: 43, scope: !2) +!25 = !DILocation(line: 5, column: 35, scope: !2) +!26 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 7, type: !4, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !13) +!27 = !DILocation(line: 2, column: 39, scope: !12, inlinedAt: !28) +!28 = distinct !DILocation(line: 7, column: 20, scope: !26) +!29 = !DILocation(line: 5, column: 43, scope: !2, inlinedAt: !30) +!30 = distinct !DILocation(line: 7, column: 32, scope: !26) +!31 = !DILocation(line: 7, column: 30, scope: !26) +!32 = !DILocation(line: 7, column: 13, scope: !26) diff --git a/llvm/test/DebugInfo/Generic/lexical-block-static-var.ll b/llvm/test/DebugInfo/Generic/lexical-block-static-var.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/lexical-block-static-var.ll @@ -0,0 +1,149 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s +; REQUIRES: object-emission + +; inline __attribute__((always_inline)) +; int removed() { +; { +; static int A; +; return A++; +; } +; } +; +; __attribute__((always_inline)) +; int not_removed() { +; { +; static int B; +; return B++; +; } +; } +; +; int foo() { +; { +; static int C; +; return ++C + removed() + not_removed(); +; } +; } + +; CHECK: DW_TAG_compile_unit + +; Out-of-line definition of `not_removed()`. +; The empty lexical block is created to match abstract origin. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin {{.*}} "_Z11not_removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: NULL + +; Abstract definition of `removed()` +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("removed") +; CHECK: DW_AT_inline (DW_INL_inlined) +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("A") +; CHECK: DW_AT_location (DW_OP_addr 0x0) +; CHECK: NULL +; CHECK: NULL +; CHECK: DW_TAG_base_type + +; Abstract definition of `not_removed()` +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("not_removed") +; CHECK: DW_AT_inline (DW_INL_inlined) +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("B") +; CHECK: DW_AT_location (DW_OP_addr 0x0) +; CHECK: NULL +; CHECK: NULL + +; Definition of foo(). +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_TAG_lexical_block +; CHECK: NULL +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_TAG_lexical_block +; CHECK: NULL +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("C") +; CHECK: DW_AT_location (DW_OP_addr 0x0) +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +$_ZZ7removedvE1A = comdat any + +@_ZZ11not_removedvE1B = internal global i32 0, align 4, !dbg !0 +@_ZZ3foovE1C = internal global i32 0, align 4, !dbg !10 +@_ZZ7removedvE1A = linkonce_odr dso_local global i32 0, comdat, align 4, !dbg !15 + +; Function Attrs: alwaysinline mustprogress nounwind uwtable +define dso_local i32 @_Z11not_removedv() #0 !dbg !4 { +entry: + %0 = load i32, i32* @_ZZ11not_removedvE1B, align 4, !dbg !25 + %inc = add nsw i32 %0, 1, !dbg !25 + store i32 %inc, i32* @_ZZ11not_removedvE1B, align 4, !dbg !25 + ret i32 %0, !dbg !26 +} + +; Function Attrs: mustprogress noinline optnone uwtable +define dso_local i32 @_Z3foov() #1 !dbg !13 { +entry: + %0 = load i32, i32* @_ZZ3foovE1C, align 4, !dbg !27 + %inc = add nsw i32 %0, 1, !dbg !27 + store i32 %inc, i32* @_ZZ3foovE1C, align 4, !dbg !27 + %1 = load i32, i32* @_ZZ7removedvE1A, align 4, !dbg !28 + %inc.i3 = add nsw i32 %1, 1, !dbg !28 + store i32 %inc.i3, i32* @_ZZ7removedvE1A, align 4, !dbg !28 + %add = add nsw i32 %inc, %1, !dbg !30 + %2 = load i32, i32* @_ZZ11not_removedvE1B, align 4, !dbg !31 + %inc.i = add nsw i32 %2, 1, !dbg !31 + store i32 %inc.i, i32* @_ZZ11not_removedvE1B, align 4, !dbg !31 + %add2 = add nsw i32 %add, %2, !dbg !33 + ret i32 %add2, !dbg !34 +} + +attributes #0 = { alwaysinline mustprogress nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress noinline optnone uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + +!llvm.dbg.cu = !{!8} +!llvm.module.flags = !{!19, !20, !21, !22, !23} +!llvm.ident = !{!24} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "B", scope: !2, file: !3, line: 13, type: !7, isLocal: true, isDefinition: true) +!2 = distinct !DILexicalBlock(scope: !4, file: !3, line: 12, column: 3) +!3 = !DIFile(filename: "test_static.cpp", directory: "/home/kbessonova/workspace/llvm/llvm-project/build") +!4 = distinct !DISubprogram(name: "not_removed", linkageName: "_Z11not_removedv", scope: !3, file: !3, line: 11, type: !5, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !14) +!5 = !DISubroutineType(types: !6) +!6 = !{!7} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 14.0.0 (git@github.com:llvm/llvm-project.git e1d09ac2d118825452bfc26e44565f7f4122fd6d)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false, nameTableKind: None) +!9 = !{!0, !10, !15} +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "C", scope: !12, file: !3, line: 20, type: !7, isLocal: true, isDefinition: true) +!12 = distinct !DILexicalBlock(scope: !13, file: !3, line: 19, column: 3) +!13 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 18, type: !5, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !14) +!14 = !{} +!15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression()) +!16 = distinct !DIGlobalVariable(name: "A", scope: !17, file: !3, line: 5, type: !7, isLocal: false, isDefinition: true) +!17 = distinct !DILexicalBlock(scope: !18, file: !3, line: 4, column: 3) +!18 = distinct !DISubprogram(name: "removed", linkageName: "_Z7removedv", scope: !3, file: !3, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !14) +!19 = !{i32 7, !"Dwarf Version", i32 4} +!20 = !{i32 2, !"Debug Info Version", i32 3} +!21 = !{i32 1, !"wchar_size", i32 4} +!22 = !{i32 7, !"uwtable", i32 1} +!23 = !{i32 7, !"frame-pointer", i32 2} +!24 = !{!"clang version 14.0.0 (git@github.com:llvm/llvm-project.git e1d09ac2d118825452bfc26e44565f7f4122fd6d)"} +!25 = !DILocation(line: 14, column: 13, scope: !2) +!26 = !DILocation(line: 14, column: 5, scope: !2) +!27 = !DILocation(line: 21, column: 12, scope: !12) +!28 = !DILocation(line: 6, column: 13, scope: !17, inlinedAt: !29) +!29 = distinct !DILocation(line: 21, column: 18, scope: !12) +!30 = !DILocation(line: 21, column: 16, scope: !12) +!31 = !DILocation(line: 14, column: 13, scope: !2, inlinedAt: !32) +!32 = distinct !DILocation(line: 21, column: 30, scope: !12) +!33 = !DILocation(line: 21, column: 28, scope: !12) +!34 = !DILocation(line: 21, column: 5, scope: !12) diff --git a/llvm/test/DebugInfo/Generic/lexical-block-types.ll b/llvm/test/DebugInfo/Generic/lexical-block-types.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/lexical-block-types.ll @@ -0,0 +1,422 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s +; REQUIRES: object-emission + +; inline __attribute__((always_inline)) +; void removed() { +; struct A1 { int i; }; +; typedef int Int1; +; { +; struct I1 { Int1 j; }; +; struct C1 { typedef char Char1; Char1 c; }; +; A1 a1; a1.i++; +; { +; I1 i1; i1.j++; +; C1 c1; c1.c++; +; } +; } +; } +; +; __attribute__((always_inline)) +; void not_removed() { +; struct A2 { int i; }; +; typedef int Int2; +; { +; struct I2 { Int2 j; }; +; struct C2 { typedef char Char2; Char2 c; }; +; A2 a2; a2.i++; +; { +; I2 i2; i2.j++; +; C2 c2; c2.c++; +; } +; } +; } +; +; void foo() { +; struct A3 { int i; }; +; typedef int Int3; +; { +; struct I3 { Int3 j; }; +; { +; struct C3 { typedef char Char3; Char3 c; }; +; A3 a3; a3.i++; +; { +; I3 i3; i3.j++; +; C3 c3; c3.c++; +; } +; } +; } +; removed(); +; not_removed(); +; } +; +; CHECK: DW_TAG_compile_unit + +; Out-of-line definition of `not_removed()` shouldn't contain any debug info for types. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin {{.*}} "_Z11not_removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "a2" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "i2" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "c2" +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +; Abstract definition of `removed()`. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("removed") +; CHECK: DW_AT_inline (DW_INL_inlined) + +; I1 and C1 defined in the first lexical block, typedef Char1 is a child of C1. +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a1") +; CHECK: DW_AT_type {{.*}} "A1" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type {{.*}} "I1" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type {{.*}} "C1" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("I1") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Int1" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("C1") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "C1::Char1" +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Char1") +; CHECK: NULL +; CHECK: NULL + +; A1 and typedef Int1 defined in subprogram scope. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("A1") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Int1") +; CHECK: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_TAG_base_type + +; Abstract definition of `not_removed()`. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("not_removed") +; CHECK: DW_AT_inline (DW_INL_inlined) + +; I2 and C2 defined in the first lexical block, typedef Char2 is a child of C2. +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a2") +; CHECK: DW_AT_type {{.*}} "A2" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("i2") +; CHECK: DW_AT_type {{.*}} "I2" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("c2") +; CHECK: DW_AT_type {{.*}} "C2" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("I2") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Int2" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("C2") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "C2::Char2" +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Char2") +; CHECK: NULL +; CHECK: NULL + +; A2 and typedef Int2 defined in subprogram scope. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("A2") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Int2") +; CHECK: NULL + +; Definition of `foo()`. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") + +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a3") +; CHECK: DW_AT_type {{.*}} "A3" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("i3") +; CHECK: DW_AT_type {{.*}} "I3" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("c3") +; CHECK: DW_AT_type {{.*}} "C3" +; CHECK: NULL + +; C3 has the inner lexical block scope, typedef Char3 is a child of C3. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("C3") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "C3::Char3" +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Char3") +; CHECK: NULL +; CHECK: NULL + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z7removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z11not_removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +; A3 and typedef Int3 defined in the subprogram scope. +; FIXME: I3 has subprogram scope here, but should be in the outer lexical block +; (which is ommitted). It wasn't placed correctly, because it's the only non-scope +; entity in the block and it isn't listed in retainedTypes; we simply wasn't aware +; about it while deciding whether to create a lexical block or not. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("A3") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("I3") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Int3" +; CHECK: NULL +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Int3") +; CHECK: NULL +; CHECK: NULL + +%struct.A2 = type { i32 } +%struct.I2 = type { i32 } +%struct.C2 = type { i8 } +%struct.A1 = type { i32 } +%struct.I1 = type { i32 } +%struct.C1 = type { i8 } +%struct.A3 = type { i32 } +%struct.I3 = type { i32 } +%struct.C3 = type { i8 } + +define dso_local void @_Z11not_removedv() !dbg !8 { +entry: + %a2 = alloca %struct.A2, align 4 + %i2 = alloca %struct.I2, align 4 + %c2 = alloca %struct.C2, align 1 + call void @llvm.dbg.declare(metadata %struct.A2* %a2, metadata !12, metadata !DIExpression()), !dbg !18 + %i = getelementptr inbounds %struct.A2, %struct.A2* %a2, i32 0, i32 0, !dbg !19 + %0 = load i32, i32* %i, align 4, !dbg !20 + %inc = add nsw i32 %0, 1, !dbg !20 + store i32 %inc, i32* %i, align 4, !dbg !20 + call void @llvm.dbg.declare(metadata %struct.I2* %i2, metadata !21, metadata !DIExpression()), !dbg !27 + %j = getelementptr inbounds %struct.I2, %struct.I2* %i2, i32 0, i32 0, !dbg !28 + %1 = load i32, i32* %j, align 4, !dbg !29 + %inc1 = add nsw i32 %1, 1, !dbg !29 + store i32 %inc1, i32* %j, align 4, !dbg !29 + call void @llvm.dbg.declare(metadata %struct.C2* %c2, metadata !30, metadata !DIExpression()), !dbg !36 + %c = getelementptr inbounds %struct.C2, %struct.C2* %c2, i32 0, i32 0, !dbg !37 + %2 = load i8, i8* %c, align 1, !dbg !38 + %inc2 = add i8 %2, 1, !dbg !38 + store i8 %inc2, i8* %c, align 1, !dbg !38 + ret void, !dbg !39 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +define dso_local void @_Z3foov() !dbg !40 { +entry: + %a1.i = alloca %struct.A1, align 4 + %i1.i = alloca %struct.I1, align 4 + %c1.i = alloca %struct.C1, align 1 + %a2.i = alloca %struct.A2, align 4 + %i2.i = alloca %struct.I2, align 4 + %c2.i = alloca %struct.C2, align 1 + %a3 = alloca %struct.A3, align 4 + %i3 = alloca %struct.I3, align 4 + %c3 = alloca %struct.C3, align 1 + call void @llvm.dbg.declare(metadata %struct.A3* %a3, metadata !41, metadata !DIExpression()), !dbg !47 + %i = getelementptr inbounds %struct.A3, %struct.A3* %a3, i32 0, i32 0, !dbg !48 + %0 = load i32, i32* %i, align 4, !dbg !49 + %inc = add nsw i32 %0, 1, !dbg !49 + store i32 %inc, i32* %i, align 4, !dbg !49 + call void @llvm.dbg.declare(metadata %struct.I3* %i3, metadata !50, metadata !DIExpression()), !dbg !56 + %j = getelementptr inbounds %struct.I3, %struct.I3* %i3, i32 0, i32 0, !dbg !57 + %1 = load i32, i32* %j, align 4, !dbg !58 + %inc1 = add nsw i32 %1, 1, !dbg !58 + store i32 %inc1, i32* %j, align 4, !dbg !58 + call void @llvm.dbg.declare(metadata %struct.C3* %c3, metadata !59, metadata !DIExpression()), !dbg !64 + %c = getelementptr inbounds %struct.C3, %struct.C3* %c3, i32 0, i32 0, !dbg !65 + %2 = load i8, i8* %c, align 1, !dbg !66 + %inc2 = add i8 %2, 1, !dbg !66 + store i8 %inc2, i8* %c, align 1, !dbg !66 + call void @llvm.dbg.declare(metadata %struct.A1* %a1.i, metadata !67, metadata !DIExpression()), !dbg !73 + %i.i3 = getelementptr inbounds %struct.A1, %struct.A1* %a1.i, i32 0, i32 0, !dbg !75 + %3 = load i32, i32* %i.i3, align 4, !dbg !76 + %inc.i4 = add nsw i32 %3, 1, !dbg !76 + store i32 %inc.i4, i32* %i.i3, align 4, !dbg !76 + call void @llvm.dbg.declare(metadata %struct.I1* %i1.i, metadata !77, metadata !DIExpression()), !dbg !83 + %j.i5 = getelementptr inbounds %struct.I1, %struct.I1* %i1.i, i32 0, i32 0, !dbg !84 + %4 = load i32, i32* %j.i5, align 4, !dbg !85 + %inc1.i6 = add nsw i32 %4, 1, !dbg !85 + store i32 %inc1.i6, i32* %j.i5, align 4, !dbg !85 + call void @llvm.dbg.declare(metadata %struct.C1* %c1.i, metadata !86, metadata !DIExpression()), !dbg !91 + %c.i7 = getelementptr inbounds %struct.C1, %struct.C1* %c1.i, i32 0, i32 0, !dbg !92 + %5 = load i8, i8* %c.i7, align 1, !dbg !93 + %inc2.i8 = add i8 %5, 1, !dbg !93 + store i8 %inc2.i8, i8* %c.i7, align 1, !dbg !93 + call void @llvm.dbg.declare(metadata %struct.A2* %a2.i, metadata !12, metadata !DIExpression()), !dbg !94 + %i.i = getelementptr inbounds %struct.A2, %struct.A2* %a2.i, i32 0, i32 0, !dbg !96 + %6 = load i32, i32* %i.i, align 4, !dbg !97 + %inc.i = add nsw i32 %6, 1, !dbg !97 + store i32 %inc.i, i32* %i.i, align 4, !dbg !97 + call void @llvm.dbg.declare(metadata %struct.I2* %i2.i, metadata !21, metadata !DIExpression()), !dbg !98 + %j.i = getelementptr inbounds %struct.I2, %struct.I2* %i2.i, i32 0, i32 0, !dbg !99 + %7 = load i32, i32* %j.i, align 4, !dbg !100 + %inc1.i = add nsw i32 %7, 1, !dbg !100 + store i32 %inc1.i, i32* %j.i, align 4, !dbg !100 + call void @llvm.dbg.declare(metadata %struct.C2* %c2.i, metadata !30, metadata !DIExpression()), !dbg !101 + %c.i = getelementptr inbounds %struct.C2, %struct.C2* %c2.i, i32 0, i32 0, !dbg !102 + %8 = load i8, i8* %c.i, align 1, !dbg !103 + %inc2.i = add i8 %8, 1, !dbg !103 + store i8 %inc2.i, i8* %c.i, align 1, !dbg !103 + ret void, !dbg !104 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 14.0.0"} +!8 = distinct !DISubprogram(name: "not_removed", linkageName: "_Z11not_removedv", scope: !1, file: !1, line: 17, type: !9, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !11) +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !{} +!12 = !DILocalVariable(name: "a2", scope: !13, file: !1, line: 23, type: !14) +!13 = distinct !DILexicalBlock(scope: !8, file: !1, line: 20, column: 3) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A2", scope: !8, file: !1, line: 18, size: 32, flags: DIFlagTypePassByValue, elements: !15) +!15 = !{!16} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !14, file: !1, line: 18, baseType: !17, size: 32) +!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!18 = !DILocation(line: 23, column: 8, scope: !13) +!19 = !DILocation(line: 23, column: 15, scope: !13) +!20 = !DILocation(line: 23, column: 16, scope: !13) +!21 = !DILocalVariable(name: "i2", scope: !22, file: !1, line: 25, type: !23) +!22 = distinct !DILexicalBlock(scope: !13, file: !1, line: 24, column: 5) +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "I2", scope: !13, file: !1, line: 21, size: 32, flags: DIFlagTypePassByValue, elements: !24) +!24 = !{!25} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !23, file: !1, line: 21, baseType: !26, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "Int2", scope: !8, file: !1, line: 19, baseType: !17) +!27 = !DILocation(line: 25, column: 10, scope: !22) +!28 = !DILocation(line: 25, column: 17, scope: !22) +!29 = !DILocation(line: 25, column: 18, scope: !22) +!30 = !DILocalVariable(name: "c2", scope: !22, file: !1, line: 26, type: !31) +!31 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C2", scope: !13, file: !1, line: 22, size: 8, flags: DIFlagTypePassByValue, elements: !32) +!32 = !{!33} +!33 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !31, file: !1, line: 22, baseType: !34, size: 8) +!34 = !DIDerivedType(tag: DW_TAG_typedef, name: "Char2", scope: !31, file: !1, line: 22, baseType: !35) +!35 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!36 = !DILocation(line: 26, column: 10, scope: !22) +!37 = !DILocation(line: 26, column: 17, scope: !22) +!38 = !DILocation(line: 26, column: 18, scope: !22) +!39 = !DILocation(line: 29, column: 1, scope: !8) +!40 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 31, type: !9, scopeLine: 31, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !11) +!41 = !DILocalVariable(name: "a3", scope: !42, file: !1, line: 38, type: !44) +!42 = distinct !DILexicalBlock(scope: !43, file: !1, line: 36, column: 5) +!43 = distinct !DILexicalBlock(scope: !40, file: !1, line: 34, column: 3) +!44 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A3", scope: !40, file: !1, line: 32, size: 32, flags: DIFlagTypePassByValue, elements: !45) +!45 = !{!46} +!46 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !44, file: !1, line: 32, baseType: !17, size: 32) +!47 = !DILocation(line: 38, column: 10, scope: !42) +!48 = !DILocation(line: 38, column: 17, scope: !42) +!49 = !DILocation(line: 38, column: 18, scope: !42) +!50 = !DILocalVariable(name: "i3", scope: !51, file: !1, line: 40, type: !52) +!51 = distinct !DILexicalBlock(scope: !42, file: !1, line: 39, column: 7) +!52 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "I3", scope: !43, file: !1, line: 35, size: 32, flags: DIFlagTypePassByValue, elements: !53) +!53 = !{!54} +!54 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !52, file: !1, line: 35, baseType: !55, size: 32) +!55 = !DIDerivedType(tag: DW_TAG_typedef, name: "Int3", scope: !40, file: !1, line: 33, baseType: !17) +!56 = !DILocation(line: 40, column: 12, scope: !51) +!57 = !DILocation(line: 40, column: 19, scope: !51) +!58 = !DILocation(line: 40, column: 20, scope: !51) +!59 = !DILocalVariable(name: "c3", scope: !51, file: !1, line: 41, type: !60) +!60 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C3", scope: !42, file: !1, line: 37, size: 8, flags: DIFlagTypePassByValue, elements: !61) +!61 = !{!62} +!62 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !60, file: !1, line: 37, baseType: !63, size: 8) +!63 = !DIDerivedType(tag: DW_TAG_typedef, name: "Char3", scope: !60, file: !1, line: 37, baseType: !35) +!64 = !DILocation(line: 41, column: 12, scope: !51) +!65 = !DILocation(line: 41, column: 19, scope: !51) +!66 = !DILocation(line: 41, column: 20, scope: !51) +!67 = !DILocalVariable(name: "a1", scope: !68, file: !1, line: 8, type: !70) +!68 = distinct !DILexicalBlock(scope: !69, file: !1, line: 5, column: 3) +!69 = distinct !DISubprogram(name: "removed", linkageName: "_Z7removedv", scope: !1, file: !1, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !11) +!70 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A1", scope: !69, file: !1, line: 3, size: 32, flags: DIFlagTypePassByValue, elements: !71, identifier: "_ZTSZ7removedvE2A1") +!71 = !{!72} +!72 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !70, file: !1, line: 3, baseType: !17, size: 32) +!73 = !DILocation(line: 8, column: 8, scope: !68, inlinedAt: !74) +!74 = distinct !DILocation(line: 45, column: 3, scope: !40) +!75 = !DILocation(line: 8, column: 15, scope: !68, inlinedAt: !74) +!76 = !DILocation(line: 8, column: 16, scope: !68, inlinedAt: !74) +!77 = !DILocalVariable(name: "i1", scope: !78, file: !1, line: 10, type: !79) +!78 = distinct !DILexicalBlock(scope: !68, file: !1, line: 9, column: 5) +!79 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "I1", scope: !68, file: !1, line: 6, size: 32, flags: DIFlagTypePassByValue, elements: !80, identifier: "_ZTSZ7removedvE2I1") +!80 = !{!81} +!81 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !79, file: !1, line: 6, baseType: !82, size: 32) +!82 = !DIDerivedType(tag: DW_TAG_typedef, name: "Int1", scope: !69, file: !1, line: 4, baseType: !17) +!83 = !DILocation(line: 10, column: 10, scope: !78, inlinedAt: !74) +!84 = !DILocation(line: 10, column: 17, scope: !78, inlinedAt: !74) +!85 = !DILocation(line: 10, column: 18, scope: !78, inlinedAt: !74) +!86 = !DILocalVariable(name: "c1", scope: !78, file: !1, line: 11, type: !87) +!87 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C1", scope: !68, file: !1, line: 7, size: 8, flags: DIFlagTypePassByValue, elements: !88, identifier: "_ZTSZ7removedvE2C1") +!88 = !{!89} +!89 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !87, file: !1, line: 7, baseType: !90, size: 8) +!90 = !DIDerivedType(tag: DW_TAG_typedef, name: "Char1", scope: !87, file: !1, line: 7, baseType: !35) +!91 = !DILocation(line: 11, column: 10, scope: !78, inlinedAt: !74) +!92 = !DILocation(line: 11, column: 17, scope: !78, inlinedAt: !74) +!93 = !DILocation(line: 11, column: 18, scope: !78, inlinedAt: !74) +!94 = !DILocation(line: 23, column: 8, scope: !13, inlinedAt: !95) +!95 = distinct !DILocation(line: 46, column: 3, scope: !40) +!96 = !DILocation(line: 23, column: 15, scope: !13, inlinedAt: !95) +!97 = !DILocation(line: 23, column: 16, scope: !13, inlinedAt: !95) +!98 = !DILocation(line: 25, column: 10, scope: !22, inlinedAt: !95) +!99 = !DILocation(line: 25, column: 17, scope: !22, inlinedAt: !95) +!100 = !DILocation(line: 25, column: 18, scope: !22, inlinedAt: !95) +!101 = !DILocation(line: 26, column: 10, scope: !22, inlinedAt: !95) +!102 = !DILocation(line: 26, column: 17, scope: !22, inlinedAt: !95) +!103 = !DILocation(line: 26, column: 18, scope: !22, inlinedAt: !95) +!104 = !DILocation(line: 47, column: 1, scope: !40) diff --git a/llvm/test/DebugInfo/Generic/namespace.ll b/llvm/test/DebugInfo/Generic/namespace.ll --- a/llvm/test/DebugInfo/Generic/namespace.ll +++ b/llvm/test/DebugInfo/Generic/namespace.ll @@ -22,15 +22,21 @@ ; CHECK: DW_TAG_formal_parameter ; CHECK: NULL +; CHECK: [[FUNC_FWD:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +; CHECK: DW_AT_name ("func_fwd") +; CHECK-NOT: DW_AT_declaration + +; CHECK: [[I:0x[0-9a-f]*]]:{{ *}}DW_TAG_variable +; CHECK: DW_AT_name ("i") +; CHECK: [[VAR_FWD:0x[0-9a-f]*]]:{{ *}}DW_TAG_variable +; CHECK: DW_AT_name ("var_fwd") + ; CHECK: [[FOO:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type ; CHECK: DW_AT_name ("foo") ; CHECK: DW_AT_declaration ; CHECK: [[BAR:0x[0-9a-f]*]]:{{ *}}DW_TAG_structure_type ; CHECK: DW_AT_name ("bar") -; CHECK: [[I:0x[0-9a-f]*]]:{{ *}}DW_TAG_variable -; CHECK: DW_AT_name ("i") - ; CHECK: [[BAZ:0x[0-9a-f]*]]:{{.*}}DW_TAG_typedef ; CHECK: DW_AT_name ("baz") @@ -41,13 +47,6 @@ ; CHECK: [[FUNC_DECL:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram ; CHECK: DW_AT_name ("func_decl") ; CHECK: DW_AT_declaration - -; CHECK: [[VAR_FWD:0x[0-9a-f]*]]:{{ *}}DW_TAG_variable -; CHECK: DW_AT_name ("var_fwd") - -; CHECK: [[FUNC_FWD:0x[0-9a-f]*]]:{{.*}}DW_TAG_subprogram -; CHECK: DW_AT_name ("func_fwd") -; CHECK-NOT: DW_AT_declaration ; CHECK: NULL ; CHECK: DW_TAG_imported_module @@ -62,6 +61,12 @@ ; CHECK: DW_AT_MIPS_linkage_name ; CHECK: DW_AT_name ("func") ; CHECK: DW_TAG_formal_parameter +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_imported_module +; CHECK: DW_AT_decl_file ([[F2]]) +; CHECK: DW_AT_decl_line (23) +; CHECK: DW_AT_import {{.*}} +; CHECK: NULL ; CHECK: DW_TAG_imported_module ; CHECK: DW_AT_decl_file ([[F2:.*]]) ; CHECK: DW_AT_decl_line (26) @@ -112,16 +117,10 @@ ; CHECK: DW_AT_decl_file ([[F2]]) ; CHECK: DW_AT_decl_line (37) ; CHECK: DW_AT_import ([[FUNC_FWD]]) -; CHECK: DW_TAG_lexical_block -; CHECK: DW_TAG_imported_module -; CHECK: DW_AT_decl_file ([[F2]]) -; CHECK: DW_AT_decl_line (23) -; CHECK: DW_AT_import {{.*}} -; CHECK: NULL ; CHECK: NULL -; CHECK: DW_TAG_base_type ; CHECK: DW_TAG_subprogram +; CHECK: DW_TAG_base_type ; CHECK: DW_TAG_imported_module ; CHECK: DW_AT_decl_file ([[F2:.*]]) ; CHECK: DW_AT_decl_line (18) diff --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import-fulllto.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import-fulllto.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import-fulllto.ll @@ -0,0 +1,229 @@ +; RUN: %llc_dwarf -O1 -filetype=obj -split-dwarf-file=%t.dwo < %s \ +; RUN: | llvm-dwarfdump -debug-info - \ +; RUN: | FileCheck %s --implicit-check-not "{{DW_TAG|NULL}}" --check-prefixes=CHECK,CHECK-NEW + +; This test demonstrates a case where mupliple compile units get linked into +; a single module and compiled with split-dwarf enabled, but without allowing +; cross-CU references (e.g. FullLTO + split-dwarf). +; This ends up in multiple CUs in the DWO file. + +; The function 'foo()' that defined in test.cpp and inlined cu1.cpp and cu2.cpp, +; expected to be emitted in all the CUs: +; * out-of-line def in test.cpp, +; * abstract origin + inlined instance in cu1.cpp and cu2.cpp. + +; Before D113741, the imported entity that belongs foo() gets emitted only for +; out-of-line def of 'foo()' in test.cpp (see, CHECK prefix). + +; After D113741, the imported entity is emitted 3 times, for all instances of 'foo()' +; except inlined ones (see, CHECK-NEW prefix). + +; $ cat test.cpp + +; namespace nn { +; int A = 42; +; } +; +; int foo() { using nn::A; return A; } +; +; int bar(); +; int far(); +; +; int main() { +; return nn::A > 0 ? bar() : far(); +; } + +; $ cat cu1.cpp + +; int foo(); +; +; int far() { return foo(); } + +; $ cat cu2.cpp + +; int foo(); +; +; int bar() { return foo(); } + +; CHECK: .debug_info contents: + +; CHECK: DW_TAG_skeleton_unit +; CHECK: DW_AT_dwo_name +; CHECK: DW_TAG_skeleton_unit +; CHECK: DW_AT_dwo_name +; CHECK: DW_TAG_skeleton_unit +; CHECK: DW_AT_dwo_name + +; CHECK: .debug_info.dwo contents: + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_name ("test.cpp") +; CHECK: DW_AT_dwo_name + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") + +; CHECK: DW_TAG_imported_declaration +; CHECK: NULL + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("main") + +; CHECK: DW_TAG_namespace +; CHECK: DW_AT_name ("nn") + +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("A") +; CHECK: DW_AT_linkage_name ("_ZN2nn1AE") +; CHECK: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("int") + +; CHECK: NULL + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_name ("cu1.cpp") +; CHECK: DW_AT_dwo_name + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") + +; CHECK-NEW: DW_TAG_imported_declaration +; CHECK-NEW: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("int") + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("far") + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z3foov" +; CHECK: NULL + +; CHECK-NEW: DW_TAG_namespace +; CHECK-NEW: DW_AT_name ("nn") + +; CHECK-NEW: DW_TAG_variable +; CHECK-NEW: DW_AT_name ("A") +; CHECK-NEW: DW_AT_linkage_name ("_ZN2nn1AE") +; CHECK-NEW: NULL + +; CHECK: NULL + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_name ("cu2.cpp") +; CHECK: DW_AT_dwo_name + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") + +; CHECK-NEW: DW_TAG_imported_declaration +; CHECK-NEW: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("int") + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("bar") + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z3foov" +; CHECK: NULL + +; CHECK-NEW: DW_TAG_namespace +; CHECK-NEW: DW_AT_name ("nn") + +; CHECK-NEW: DW_TAG_variable +; CHECK-NEW: DW_AT_name ("A") +; CHECK-NEW: DW_AT_linkage_name ("_ZN2nn1AE") +; CHECK-NEW: NULL + +; CHECK: NULL + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@_ZN2nn1AE = dso_local global i32 42, align 4, !dbg !0 + +define dso_local noundef i32 @_Z3foov() !dbg !19 { + %1 = load i32, ptr @_ZN2nn1AE, align 4, !dbg !25 + ret i32 %1, !dbg !26 +} + +define dso_local noundef i32 @main() !dbg !27 { + %1 = alloca i32, align 4 + store i32 0, ptr %1, align 4 + %2 = load i32, ptr @_ZN2nn1AE, align 4, !dbg !28 + %3 = icmp sgt i32 %2, 0, !dbg !29 + br i1 %3, label %4, label %6, !dbg !28 + +4: ; preds = %0 + %5 = call noundef i32 @_Z3barv(), !dbg !30 + br label %8, !dbg !28 + +6: ; preds = %0 + %7 = call noundef i32 @_Z3farv(), !dbg !31 + br label %8, !dbg !28 + +8: ; preds = %6, %4 + %9 = phi i32 [ %5, %4 ], [ %7, %6 ], !dbg !28 + ret i32 %9, !dbg !32 +} + +define dso_local noundef i32 @_Z3farv() !dbg !33 { + %1 = load i32, ptr @_ZN2nn1AE, align 4, !dbg !34 + ret i32 %1, !dbg !36 +} + +define dso_local noundef i32 @_Z3barv() !dbg !37 { + %1 = load i32, ptr @_ZN2nn1AE, align 4, !dbg !38 + ret i32 %1, !dbg !40 +} + +!llvm.dbg.cu = !{!5, !7, !9} +!llvm.ident = !{!11, !11, !11} +!llvm.module.flags = !{!12, !13, !14, !15, !16, !17, !18} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "A", linkageName: "_ZN2nn1AE", scope: !2, file: !3, line: 2, type: !4, isLocal: false, isDefinition: true) +!2 = !DINamespace(name: "nn", scope: null) +!3 = !DIFile(filename: "test.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "bc42e2769243cd177f7a4e1b304da410") +!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "LLVM.org clang version 15.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !6, splitDebugInlining: false, nameTableKind: None, imports: !23) +!6 = !{!0} +!7 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !8, producer: "LLVM.org clang version 15.0.0 (git@github.com:llvm/llvm-project.git 8a3d730f71fed987488372b84927849026a9013e)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!8 = !DIFile(filename: "cu1.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "020b93a3e57440bb48c0510b5151bae0") +!9 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !10, producer: "LLVM.org clang version 15.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!10 = !DIFile(filename: "cu2.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "195dd4b1e73b8cc9eb119c68a68596f5") +!11 = !{!"LLVM.org clang version 15.0.0"} +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"PIC Level", i32 2} +!16 = !{i32 7, !"PIE Level", i32 2} +!17 = !{i32 7, !"uwtable", i32 2} +!18 = !{i32 7, !"frame-pointer", i32 2} +!19 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 5, type: !20, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22) +!20 = !DISubroutineType(types: !21) +!21 = !{!4} +!22 = !{} +!23 = !{!24} +!24 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !19, entity: !1, file: !3, line: 5) +!25 = !DILocation(line: 5, column: 33, scope: !19) +!26 = !DILocation(line: 5, column: 26, scope: !19) +!27 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 10, type: !20, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22) +!28 = !DILocation(line: 11, column: 10, scope: !27) +!29 = !DILocation(line: 11, column: 16, scope: !27) +!30 = !DILocation(line: 11, column: 22, scope: !27) +!31 = !DILocation(line: 11, column: 30, scope: !27) +!32 = !DILocation(line: 11, column: 3, scope: !27) +!33 = distinct !DISubprogram(name: "far", linkageName: "_Z3farv", scope: !8, file: !8, line: 3, type: !20, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !22) +!34 = !DILocation(line: 5, column: 33, scope: !19, inlinedAt: !35) +!35 = distinct !DILocation(line: 3, column: 20, scope: !33) +!36 = !DILocation(line: 3, column: 13, scope: !33) +!37 = distinct !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !10, file: !10, line: 3, type: !20, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !9, retainedNodes: !22) +!38 = !DILocation(line: 5, column: 33, scope: !19, inlinedAt: !39) +!39 = distinct !DILocation(line: 3, column: 20, scope: !37) +!40 = !DILocation(line: 3, column: 13, scope: !37) diff --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import.ll @@ -0,0 +1,77 @@ +; RUN: %llc_dwarf -O1 -filetype=obj -split-dwarf-file=%t.dwo < %s | llvm-dwarfdump -debug-info - | FileCheck %s --implicit-check-not "{{DW_TAG|NULL}}" +; REQUIRES: object-emission + +; CHECK-LABEL: debug_info contents +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_GNU_dwo_name +; CHECK: DW_AT_GNU_dwo_id +; CHECK: DW_TAG_subprogram +; CHECK: DW_TAG_inlined_subroutine +; CHECK: NULL +; CHECK: NULL + +; CHECK: DW_TAG_compile_unit +; CHECK-NOT: DW_AT_GNU_dwo_name +; CHECK-NOT: DW_AT_GNU_dwo_id +; CHECK: DW_TAG_subprogram +; CHECK: NULL + +; CHECK-LABEL: debug_info.dwo contents + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_TAG_subprogram +; CHECK: DW_TAG_imported_declaration +; CHECK: NULL +; CHECK: DW_TAG_subprogram +; CHECK: DW_TAG_inlined_subroutine +; CHECK: NULL +; CHECK: DW_TAG_namespace +; CHECK: DW_TAG_structure_type +; CHECK: NULL +; CHECK: DW_TAG_base_type +; CHECK: NULL + +%"struct.ns::t1" = type { i8 } + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +declare dso_local void @_Z3pinv() local_unnamed_addr + +define dso_local i32 @main() local_unnamed_addr !dbg !18 { +entry: + call void @llvm.dbg.declare(metadata %"struct.ns::t1"* undef, metadata !22, metadata !DIExpression()), !dbg !23 + call void @_Z3pinv(), !dbg !25 + ret i32 0, !dbg !26 +} + +!llvm.dbg.cu = !{!0, !10} +!llvm.ident = !{!12, !12} +!llvm.module.flags = !{!13, !14, !15, !16, !17} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !2, splitDebugInlining: true, nameTableKind: GNU) +!1 = !DIFile(filename: "a.cpp", directory: "/") +!2 = !{!3} +!3 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !4, entity: !8, file: !1, line: 3) +!4 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !7) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{} +!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", scope: !9, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t1E") +!9 = !DINamespace(name: "ns", scope: null) +!10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !11, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: true, nameTableKind: GNU) +!11 = !DIFile(filename: "b.cpp", directory: "/") +!12 = !{!"clang version 14.0.0"} +!13 = !{i32 7, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{i32 7, !"uwtable", i32 1} +!17 = !{i32 7, !"frame-pointer", i32 2} +!18 = distinct !DISubprogram(name: "main", scope: !11, file: !11, line: 2, type: !19, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !7) +!19 = !DISubroutineType(types: !20) +!20 = !{!21} +!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!22 = !DILocalVariable(name: "v1", scope: !4, file: !1, line: 3, type: !8) +!23 = !DILocation(line: 3, column: 37, scope: !4, inlinedAt: !24) +!24 = distinct !DILocation(line: 3, column: 3, scope: !18) +!25 = !DILocation(line: 3, column: 41, scope: !4, inlinedAt: !24) +!26 = !DILocation(line: 4, column: 1, scope: !18) diff --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import2.ll @@ -0,0 +1,40 @@ +; RUN: %llc_dwarf -split-dwarf-file=%t.dwo < %s | FileCheck %s + +; Ensure function-local DW_TAG_imported_declaration get skipped if parent subprogram was not emitted. +; CHECK-NOT: DW_TAG_imported_declaration + +define void @f1() !dbg !13 { +lbl: + ret void, !dbg !16 +} + +define void @f2() !dbg !22 { +lbl: + ret void, !dbg !23 +} + +!llvm.dbg.cu = !{!0, !2, !10} +!llvm.module.flags = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, emissionKind: FullDebug) +!1 = !DIFile(filename: "a.cc", directory: "") +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, imports: !4) +!3 = !DIFile(filename: "b.cc", directory: "") +!4 = !{!5} +!5 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !6, entity: !7) +!6 = !DISubprogram(scope: null, spFlags: DISPFlagOptimized) +!7 = !DINamespace(scope: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{} +!10 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !11, emissionKind: FullDebug) +!11 = !DIFile(filename: "c.cc", directory: "") +!12 = !{i32 2, !"Debug Info Version", i32 3} +!13 = distinct !DISubprogram(scope: null, type: !8, spFlags: DISPFlagDefinition, unit: !0) +!16 = !DILocation(line: 0, scope: !17, inlinedAt: !18) +!17 = distinct !DISubprogram(scope: null, unit: !10) +!18 = !DILocation(line: 0, scope: !21) +!21 = !DILexicalBlockFile(scope: !13, discriminator: 0) +!22 = distinct !DISubprogram(scope: null, type: !8, spFlags: DISPFlagDefinition, unit: !0) +!23 = !DILocation(line: 0, scope: !24, inlinedAt: !25) +!24 = distinct !DISubprogram(scope: null, unit: !2) +!25 = !DILocation(line: 0, scope: !22) diff --git a/llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll b/llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/split-dwarf-local-import3.ll @@ -0,0 +1,72 @@ +; RUN: %llc_dwarf -O1 -filetype=obj -split-dwarf-file=%t.dwo < %s | llvm-dwarfdump -debug-info - | FileCheck %s --implicit-check-not "{{DW_TAG|NULL}}" + +; FIXME: the test demonstrates missing imported entity issue. +; 'foo()' that has the local imported entity 'nn::A' gets inlined into a different CU. +; The destination CU knows nothing about local imported entities of 'foo()', thus +; doesn't emit them ('ImportedEntities' map belongs to the source CU of 'foo()'). + +; D113741 doesn't fix this, cause it relies on LocalScopesWithLocalDecls which +; is also a DwarfCompileUnit-local set. + +; CHECK-LABEL: .debug_info contents: + +; CHECK: DW_TAG_skeleton_unit +; CHECK: DW_AT_dwo_name + +; CHECK-LABEL: .debug_info.dwo contents: + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_name ("test.cpp") +; CHECK: DW_AT_dwo_name + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") + +; FIXME: DW_TAG_imported_declaration +; FIXME: The imported declaration of nn::A is missed here. + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("int") + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("main") + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin (0x0000001a "_Z3foov") + +; CHECK: NULL + +; CHECK: NULL + +define dso_local noundef i32 @main() local_unnamed_addr !dbg !20 { +entry: + ret i32 42, !dbg !21 +} + +!llvm.dbg.cu = !{!0, !2} +!llvm.module.flags = !{!13, !14, !15, !16, !17, !18} +!llvm.ident = !{!19, !19} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "test.dwo", emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: GNU) +!1 = !DIFile(filename: "test.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "e7c2808ee27614e496499d55e4b37962") +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 15.0.0", isOptimized: true, runtimeVersion: 0, splitDebugFilename: "cu1.dwo", emissionKind: FullDebug, imports: !4, splitDebugInlining: false, nameTableKind: GNU) +!3 = !DIFile(filename: "cu1.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "c0b84240ef5682b87083b33cf9038171") +!4 = !{!5} +!5 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !6, entity: !11, file: !3, line: 5) +!6 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !3, file: !3, line: 5, type: !7, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !10) +!7 = !DISubroutineType(types: !8) +!8 = !{!9} +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{} +!11 = distinct !DIGlobalVariable(name: "A", linkageName: "_ZN2nn1AE", scope: !12, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true) +!12 = !DINamespace(name: "nn", scope: null) +!13 = !{i32 7, !"Dwarf Version", i32 5} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{i32 7, !"PIC Level", i32 2} +!17 = !{i32 7, !"PIE Level", i32 2} +!18 = !{i32 7, !"uwtable", i32 2} +!19 = !{!"clang version 15.0.0"} +!20 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !7, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !10) +!21 = !DILocation(line: 4, column: 3, scope: !6, inlinedAt: !22) +!22 = !DILocation(line: 4, column: 3, scope: !20) diff --git a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll --- a/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll +++ b/llvm/test/Instrumentation/InstrProfiling/debug-info-correlate.ll @@ -20,7 +20,7 @@ define void @_Z3foov() !dbg !12 { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 12345678, i32 2, i32 0) - ret void + ret void, !dbg !17 } declare void @llvm.instrprof.increment(i8*, i64, i32, i32) @@ -46,6 +46,7 @@ !14 = !DISubroutineType(types: !15) !15 = !{null} !16 = !{} +!17 = !DILocation(line: 1, scope: !12) ; CHECK-DWARF: DW_TAG_compile_unit ; CHECK-DWARF: DW_TAG_subprogram