diff --git a/llvm/include/llvm/CodeGen/LexicalScopes.h b/llvm/include/llvm/CodeGen/LexicalScopes.h index 993df54c05ad5..848a4a4ce2433 100644 --- a/llvm/include/llvm/CodeGen/LexicalScopes.h +++ b/llvm/include/llvm/CodeGen/LexicalScopes.h @@ -199,12 +199,18 @@ class LexicalScopes { return I != LexicalScopeMap.end() ? &I->second : nullptr; } + bool currentFunctionHasInlinedScopes() { + return !InlinedLexicalScopeMap.empty(); + } + /// Find or create an abstract lexical scope. LLVM_ABI LexicalScope *getOrCreateAbstractScope(const DILocalScope *Scope); - /// Get function to which the given subprogram is attached, if exists. - const Function *getFunction(const DISubprogram *SP) const { - return FunctionMap.lookup(SP); + /// Get functions to which the given subprogram is attached. + const SmallPtrSet * + getFunctions(const DISubprogram *SP) const { + auto I = FunctionMap.find(SP); + return I == FunctionMap.end() ? nullptr : &I->second; } private: @@ -218,6 +224,15 @@ class LexicalScopes { : nullptr; } + /// Create abstract lexical scope for local scopes used by multiple + /// functions, if needed. + void ensureAbstractLexicalScopeIsCreated(const DILocalScope *Scope) { + const DISubprogram *SP = Scope->getSubprogram(); + const auto *Fns = getFunctions(SP); + if (!Fns || Fns->size() != 1) + getOrCreateAbstractScope(Scope); + } + /// Find or create a regular lexical scope. LexicalScope *getOrCreateRegularScope(const DILocalScope *Scope); @@ -237,7 +252,7 @@ class LexicalScopes { const MachineFunction *MF = nullptr; /// Mapping between DISubprograms and IR functions. - DenseMap FunctionMap; + DenseMap> FunctionMap; /// Tracks the scopes in the current function. // Use an unordered_map to ensure value pointer validity over insertion. diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 12d749ce56f06..9bc395fcf1e79 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1658,9 +1658,9 @@ void CodeViewDebug::addToUDTs(const DIType *Ty) { formatNestedName(ParentScopeNames, getPrettyScopeName(Ty)); if (ClosestSubprogram == nullptr) { - GlobalUDTs.emplace_back(std::move(FullyQualifiedName), Ty); + GlobalUDTs[Ty] = std::move(FullyQualifiedName); } else if (ClosestSubprogram == CurrentSubprogram) { - LocalUDTs.emplace_back(std::move(FullyQualifiedName), Ty); + LocalUDTs[Ty] = std::move(FullyQualifiedName); } // TODO: What if the ClosestSubprogram is neither null or the current @@ -2698,6 +2698,12 @@ TypeIndex CodeViewDebug::getTypeIndex(const DIType *Ty, const DIType *ClassTy) { if (!Ty) return TypeIndex::Void(); + if (Ty->getTag() == dwarf::DW_TAG_typedef) { + // Ensure that UDT is added even if the (local) type has been translated + // during processing of the previous function. + addToUDTs(Ty); + } + // Check if we've already translated this type. Don't try to do a // get-or-create style insertion that caches the hash lookup across the // lowerType call. It will update the TypeIndices map. @@ -2787,6 +2793,10 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) { return FwdDeclTI; } + // Ensure that UDT is added even if the (local) type has been translated + // during processing of the previous function. + addToUDTs(CTy); + // Check if we've already translated the complete record type. // Insert the type with a null TypeIndex to signify that the type is currently // being lowered. @@ -3217,20 +3227,19 @@ void CodeViewDebug::emitEndSymbolRecord(SymbolKind EndKind) { OS.emitInt16(uint16_t(EndKind)); // Record Kind } -void CodeViewDebug::emitDebugInfoForUDTs( - const std::vector> &UDTs) { +template +void CodeViewDebug::emitDebugInfoForUDTs(Range &&UDTs) { #ifndef NDEBUG size_t OriginalSize = UDTs.size(); #endif - for (const auto &UDT : UDTs) { - const DIType *T = UDT.second; + for (const auto &[T, Name] : UDTs) { assert(shouldEmitUdt(T)); MCSymbol *UDTRecordEnd = beginSymbolRecord(SymbolKind::S_UDT); OS.AddComment("Type"); OS.emitInt32(getCompleteTypeIndex(T).getIndex()); assert(OriginalSize == UDTs.size() && "getCompleteTypeIndex found new UDTs!"); - emitNullTerminatedSymbolName(OS, UDT.first); + emitNullTerminatedSymbolName(OS, Name); endSymbolRecord(UDTRecordEnd); } } diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index c2b878e52e1c3..f4c5a5bb1625c 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -306,8 +306,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { // The UDTs we have seen while processing types; each entry is a pair of type // index and type name. - std::vector> LocalUDTs; - std::vector> GlobalUDTs; + MapVector LocalUDTs; + MapVector GlobalUDTs; using FileToFilepathMapTy = std::map; FileToFilepathMapTy FileToFilepathMap; @@ -352,8 +352,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { void emitDebugInfoForRetainedTypes(); - void emitDebugInfoForUDTs( - const std::vector> &UDTs); + template void emitDebugInfoForUDTs(Range &&UDTs); void collectDebugInfoForGlobals(); void emitDebugInfoForGlobals(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 518121e200190..a801b1e400ad9 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -178,7 +178,7 @@ unsigned DwarfCompileUnit::getOrCreateSourceID(const DIFile *File) { DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( const DIGlobalVariable *GV, ArrayRef GlobalExprs) { // Check for pre-existence. - if (DIE *Die = getDIE(GV)) + if (DIE *Die = getDIEs(GV).getVariableDIE(GV)) return Die; assert(GV); @@ -795,7 +795,9 @@ DIE *DwarfCompileUnit::constructLexicalScopeDIE(LexicalScope *Scope) { DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV, bool Abstract) { auto *VariableDie = DIE::get(DIEValueAllocator, DV.getTag()); - insertDIE(DV.getVariable(), VariableDie); + getDIEs(DV.getVariable()) + .getLVs() + .insertDIE(DV.getVariable(), &DV, VariableDie, Abstract); DV.setDIE(*VariableDie); // Abstract variables don't get common attributes later, so apply them now. if (Abstract) { @@ -1010,7 +1012,9 @@ DIE *DwarfCompileUnit::constructVariableDIE(DbgVariable &DV, DIE *DwarfCompileUnit::constructLabelDIE(DbgLabel &DL, const LexicalScope &Scope) { auto LabelDie = DIE::get(DIEValueAllocator, DL.getTag()); - insertDIE(DL.getLabel(), LabelDie); + getDIEs(DL.getLabel()) + .getLabels() + .insertDIE(DL.getLabel(), &DL, LabelDie, Scope.isAbstractScope()); DL.setDIE(*LabelDie); if (Scope.isAbstractScope()) @@ -1472,8 +1476,9 @@ DIE *DwarfCompileUnit::getOrCreateImportedEntityDIE( return IMDie; } -void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP) { - DIE *D = getDIE(SP); +void DwarfCompileUnit::finishSubprogramDefinition(const DISubprogram *SP, + const Function *F) { + DIE *D = getDIEs(SP).getLocalScopes().getConcreteDIE(SP, F); if (DIE *AbsSPDIE = getAbstractScopeDIEs().lookup(SP)) { if (D) // If this subprogram has an abstract definition, reference that @@ -1834,14 +1839,16 @@ DIE *DwarfCompileUnit::getOrCreateSubprogramDIE(const DISubprogram *SP, const Function *F, bool Minimal) { if (!F && SP->isDefinition()) { - F = DD->getLexicalScopes().getFunction(SP); + const auto *Fs = DD->getLexicalScopes().getFunctions(SP); - if (!F) { + if (!Fs || Fs->size() != 1) { // SP may belong to another CU. Determine the CU similarly // to DwarfDebug::constructAbstractSubprogramScopeDIE. return &DD->getOrCreateAbstractSubprogramCU(SP, *this) .getOrCreateAbstractSubprogramDIE(SP); } + + F = *Fs->begin(); } return DwarfUnit::getOrCreateSubprogramDIE(SP, F, Minimal); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index a3bbc8364599d..b0dcc3e432a03 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -79,16 +79,10 @@ class DwarfCompileUnit final : public DwarfUnit { // List of concrete lexical block scopes belong to subprograms within this CU. DenseMap LexicalBlockDIEs; - // List of abstract local scopes (either DISubprogram or DILexicalBlock). - DenseMap AbstractLocalScopeDIEs; - SmallPtrSet FinalizedAbstractSubprograms; - // List of inlined lexical block scopes that belong to subprograms within this // CU. DenseMap> InlinedLocalScopeDIEs; - DenseMap> AbstractEntities; - /// DWO ID for correlating skeleton and split units. uint64_t DWOId = 0; @@ -126,22 +120,20 @@ class DwarfCompileUnit final : public DwarfUnit { bool isDwoUnit() const override; - DenseMap &getAbstractScopeDIEs() { - if (isDwoUnit() && !DD->shareAcrossDWOCUs()) - return AbstractLocalScopeDIEs; - return DU->getAbstractScopeDIEs(); + DwarfInfoHolder &getDIEs(const DINode *N) { return DwarfUnit::getDIEs(N); } + + DwarfInfoHolder &getDIEs() { return getDIEs(nullptr); } + + DwarfInfoHolder::AbstractScopeMapT &getAbstractScopeDIEs() { + return getDIEs().getLocalScopes().getAbstractDIEs(); } DenseMap> &getAbstractEntities() { - if (isDwoUnit() && !DD->shareAcrossDWOCUs()) - return AbstractEntities; - return DU->getAbstractEntities(); + return getDIEs().getAbstractEntities(); } auto &getFinalizedAbstractSubprograms() { - if (isDwoUnit() && !DD->shareAcrossDWOCUs()) - return FinalizedAbstractSubprograms; - return DU->getFinalizedAbstractSubprograms(); + return getDIEs().getFinalizedAbstractSubprograms(); } void finishNonUnitTypeDIE(DIE& D, const DICompositeType *CTy) override; @@ -327,7 +319,7 @@ class DwarfCompileUnit final : public DwarfUnit { DIE *getOrCreateImportedEntityDIE(const DIImportedEntity *IE); DIE *constructImportedEntityDIE(const DIImportedEntity *IE); - void finishSubprogramDefinition(const DISubprogram *SP); + void finishSubprogramDefinition(const DISubprogram *SP, const Function *F); void finishEntityDefinition(const DbgEntity *Entity); void attachLexicalScopesAbstractOrigins(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index d751a7f9f01ef..865e7b7d6d376 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -502,7 +502,8 @@ void DwarfDebug::addSubprogramNames( // well into the name table. Only do that if we are going to actually emit // that name. if (LinkageName != "" && SP->getName() != LinkageName && - (useAllLinkageNames() || InfoHolder.getAbstractScopeDIEs().lookup(SP))) + (useAllLinkageNames() || + InfoHolder.getDIEs().getLocalScopes().getAbstractDIEs().lookup(SP))) addAccelName(Unit, NameTableKind, LinkageName, Die); // If this is an Objective-C selector name add it to the ObjC accelerator @@ -1263,11 +1264,13 @@ void DwarfDebug::finishEntityDefinitions() { } void DwarfDebug::finishSubprogramDefinitions() { - for (const DISubprogram *SP : ProcessedSPNodes) { + for (auto SPF : ProcessedSPNodes) { + const DISubprogram *SP = SPF.first; assert(SP->getUnit()->getEmissionKind() != DICompileUnit::NoDebug); - forBothCUs( - getOrCreateDwarfCompileUnit(SP->getUnit()), - [&](DwarfCompileUnit &CU) { CU.finishSubprogramDefinition(SP); }); + forBothCUs(getOrCreateDwarfCompileUnit(SP->getUnit()), + [&](DwarfCompileUnit &CU) { + CU.finishSubprogramDefinition(SP, SPF.second); + }); } } @@ -2747,7 +2750,7 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { // is still needed as we need its source location. if (!TheCU.getCUNode()->getDebugInfoForProfiling() && TheCU.getCUNode()->getEmissionKind() == DICompileUnit::LineTablesOnly && - LScopes.getAbstractScopesList().empty() && !IsDarwin) { + !LScopes.currentFunctionHasInlinedScopes() && !IsDarwin) { for (const auto &R : Asm->MBBSectionRanges) addArangeLabel(SymbolCU(&TheCU, R.second.BeginLabel)); @@ -2784,11 +2787,11 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) { constructAbstractSubprogramScopeDIE(TheCU, AScope); } - ProcessedSPNodes.insert(SP); + ProcessedSPNodes.insert(std::make_pair(SP, &F)); DIE &ScopeDIE = TheCU.constructSubprogramScopeDIE(SP, F, FnScope, FunctionLineTableLabel); if (auto *SkelCU = TheCU.getSkeleton()) - if (!LScopes.getAbstractScopesList().empty() && + if (LScopes.currentFunctionHasInlinedScopes() && TheCU.getCUNode()->getSplitDebugInlining()) SkelCU->constructSubprogramScopeDIE(SP, F, FnScope, FunctionLineTableLabel); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h index 1a1b28a6fc035..42ac225e2d17e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -373,7 +373,8 @@ class DwarfDebug : public DebugHandlerBase { /// This is a collection of subprogram MDNodes that are processed to /// create DIEs. - SmallSetVector ProcessedSPNodes; + SmallSetVector, 16> + ProcessedSPNodes; /// Map function-local imported entities to their parent local scope /// (either DILexicalBlock or DISubprogram) for a processed function diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h index ef1524d875c84..94d4e5f0b7f05 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -15,9 +15,12 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/DIE.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/Support/Allocator.h" +#include #include #include +#include #include namespace llvm { @@ -26,9 +29,6 @@ class AsmPrinter; class DbgEntity; class DbgVariable; class DbgLabel; -class DINode; -class DILocalScope; -class DISubprogram; class DwarfCompileUnit; class DwarfUnit; class LexicalScope; @@ -53,6 +53,144 @@ struct RangeSpanList { SmallVector Ranges; }; +/// Tracks abstract and concrete DIEs for debug info entities of a certain type. +template class DINodeInfoHolder { +public: + using AbstractMapT = DenseMap; + using ConcreteMapT = + DenseMap>; + +private: + AbstractMapT AbstractMap; + ConcreteMapT ConcreteMap; + +public: + void insertAbstractDIE(const DINodeT *N, DIE *D) { + auto [_, Inserted] = AbstractMap.try_emplace(N, D); + assert(Inserted && "Duplicate abstract DIE for debug info node"); + } + + void insertConcreteDIE(const DINodeT *N, const DbgEntityT *E, DIE *D) { + auto [_, Inserted] = ConcreteMap[N].try_emplace(E, D); + assert(Inserted && "Duplicate concrete DIE for debug info node"); + } + + void insertDIE(const DINodeT *N, const DbgEntityT *E, DIE *D, bool Abstract) { + if (Abstract) + insertAbstractDIE(N, D); + else + insertConcreteDIE(N, E, D); + } + + DIE *getAbstractDIE(const DINodeT *N) const { return AbstractMap.lookup(N); } + + std::optional< + std::reference_wrapper> + getConcreteDIEs(const DINodeT *N) const { + if (auto I = ConcreteMap.find(N); I != ConcreteMap.end()) + return std::make_optional(std::ref(I->second)); + return std::nullopt; + } + + DIE *getConcreteDIE(const DINodeT *N, const DbgEntityT *E) const { + if (auto I = getConcreteDIEs(N)) + return I->get().lookup(E); + return nullptr; + } + + DIE *getAnyConcreteDIE(const DINodeT *N) const { + if (auto I = getConcreteDIEs(N)) + return I->get().empty() ? nullptr : I->get().begin()->second; + return nullptr; + } + + /// Returns abstract DIE for the entity. + /// If no abstract DIE was created, returns any concrete DIE for the entity. + DIE *getDIE(const DINodeT *N) const { + if (DIE *D = getAbstractDIE(N)) + return D; + + return getAnyConcreteDIE(N); + } + + AbstractMapT &getAbstractDIEs() { return AbstractMap; } +}; + +/// Tracks DIEs for debug info entites. +/// These DIEs can be shared across CUs, that is why we keep the map here +/// instead of in DwarfCompileUnit. +class DwarfInfoHolder { +public: + using LocalScopeHolderT = DINodeInfoHolder; + using AbstractScopeMapT = LocalScopeHolderT::AbstractMapT; + +private: + /// DIEs of local DbgVariables. + DINodeInfoHolder LVHolder; + /// DIEs of labels. + DINodeInfoHolder LabelHolder; + DenseMap> AbstractEntities; + /// DIEs of abstract local scopes and concrete non-inlined subprograms. + /// Inlined subprograms and concrete lexical blocks are not stored here. + LocalScopeHolderT LSHolder; + /// Keeps track of abstract subprograms to populate them only once. + // FIXME: merge creation and population of abstract scopes. + SmallPtrSet FinalizedAbstractSubprograms; + + /// Other DINodes with the corresponding DIEs. + DenseMap MDNodeToDieMap; + +public: + void insertDIE(const DINode *N, DIE *Die) { + assert((!isa(N) && !isa(N) && + !isa(N)) && + "Use getLabels().insertDIE() for labels or getLVs().insertDIE() for " + "local variables, or getSubprogram().insertDIE() for subprograms."); + auto [_, Inserted] = MDNodeToDieMap.try_emplace(N, Die); + assert((Inserted || isa(N)) && + "DIE for this DINode has already been added"); + } + + void insertDIE(DIE *D) { MDNodeToDieMap.try_emplace(nullptr, D); } + + DIE *getDIE(const DINode *N) const { + DIE *D = MDNodeToDieMap.lookup(N); + assert((!D || (!isa(N) && !isa(N) && + !isa(N))) && + "Use getLabels().getDIE() for labels or getLVs().getDIE() for " + "local variables, or getLocalScopes().getDIE() for local scopes."); + return D; + } + + auto &getLVs() { return LVHolder; } + auto &getLVs() const { return LVHolder; } + + auto &getLabels() { return LabelHolder; } + auto &getLabels() const { return LabelHolder; } + + auto &getLocalScopes() { return LSHolder; } + auto &getLocalScopes() const { return LSHolder; } + + /// For a global variable, returns DIE of the variable. + /// + /// For a local variable, returns abstract DIE of the variable. + /// If no abstract DIE was created, returns any concrete DIE of the variable. + DIE *getVariableDIE(const DIVariable *V) const { + if (auto *LV = dyn_cast(V)) + if (DIE *D = getLVs().getDIE(LV)) + return D; + return getDIE(V); + } + + DenseMap> &getAbstractEntities() { + return AbstractEntities; + } + + auto &getFinalizedAbstractSubprograms() { + return FinalizedAbstractSubprograms; + } +}; + class DwarfFile { // Target of Dwarf emission, used for sizing of abbreviations. AsmPrinter *Asm; @@ -93,17 +231,7 @@ class DwarfFile { using LabelList = SmallVector; DenseMap ScopeLabels; - // Collection of abstract subprogram DIEs. - DenseMap AbstractLocalScopeDIEs; - DenseMap> AbstractEntities; - /// Keeps track of abstract subprograms to populate them only once. - // FIXME: merge creation and population of abstract scopes. - SmallPtrSet FinalizedAbstractSubprograms; - - /// Maps MDNodes for type system with the corresponding DIEs. These DIEs can - /// be shared across CUs, that is why we keep the map here instead - /// of in DwarfCompileUnit. - DenseMap DITypeNodeToDieMap; + DwarfInfoHolder InfoHolder; public: DwarfFile(AsmPrinter *AP, StringRef Pref, BumpPtrAllocator &DA); @@ -171,25 +299,7 @@ class DwarfFile { return ScopeLabels; } - DenseMap &getAbstractScopeDIEs() { - return AbstractLocalScopeDIEs; - } - - DenseMap> &getAbstractEntities() { - return AbstractEntities; - } - - auto &getFinalizedAbstractSubprograms() { - return FinalizedAbstractSubprograms; - } - - void insertDIE(const MDNode *TypeMD, DIE *Die) { - DITypeNodeToDieMap.insert(std::make_pair(TypeMD, Die)); - } - - DIE *getDIE(const MDNode *TypeMD) { - return DITypeNodeToDieMap.lookup(TypeMD); - } + DwarfInfoHolder &getDIEs() { return InfoHolder; } }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index aa078f3f81d49..b0d0fa147b3fc 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -188,28 +188,16 @@ bool DwarfUnit::isShareableAcrossCUs(const DINode *D) const { // together. if (isDwoUnit() && !DD->shareAcrossDWOCUs()) return false; - return (isa(D) || - (isa(D) && !cast(D)->isDefinition())) && - !DD->generateTypeUnits(); -} - -DIE *DwarfUnit::getDIE(const DINode *D) const { - if (isShareableAcrossCUs(D)) - return DU->getDIE(D); - return MDNodeToDieMap.lookup(D); + return !D || ((isa(D) || (isa(D) && + !cast(D)->isDefinition())) && + !DD->generateTypeUnits()); } void DwarfUnit::insertDIE(const DINode *Desc, DIE *D) { - if (isShareableAcrossCUs(Desc)) { - DU->insertDIE(Desc, D); - return; - } - MDNodeToDieMap.insert(std::make_pair(Desc, D)); + getDIEs(Desc).insertDIE(Desc, D); } -void DwarfUnit::insertDIE(DIE *D) { - MDNodeToDieMap.insert(std::make_pair(nullptr, D)); -} +void DwarfUnit::insertDIE(DIE *D) { InfoHolder.insertDIE(D); } void DwarfUnit::addFlag(DIE &Die, dwarf::Attribute Attribute) { if (DD->getDwarfVersion() >= 4) @@ -424,6 +412,14 @@ DIE &DwarfUnit::createAndAddDIE(dwarf::Tag Tag, DIE &Parent, const DINode *N) { return Die; } +DIE &DwarfUnit::createAndAddSubprogramDIE(DIE &Parent, const DISubprogram *SP, + const Function *F) { + DIE &Die = + Parent.addChild(DIE::get(DIEValueAllocator, dwarf::DW_TAG_subprogram)); + getDIEs(SP).getLocalScopes().insertConcreteDIE(SP, F, &Die); + return Die; +} + void DwarfUnit::addBlock(DIE &Die, dwarf::Attribute Attribute, DIELoc *Loc) { Loc->computeSize(Asm->getDwarfFormParams()); DIELocs.push_back(Loc); // Memoize so we can call the destructor later on. @@ -803,7 +799,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) { addString(Buffer, dwarf::DW_AT_name, Name); if (DIVariable *Var = STy->getStringLength()) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_string_length, *VarDIE); } else if (DIExpression *Expr = STy->getStringLengthExp()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1122,8 +1118,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { constructTypeDIE(VariantPart, Composite); } } else if (Tag == dwarf::DW_TAG_namelist) { - auto *Var = dyn_cast(Element); - auto *VarDIE = getDIE(Var); + auto *Var = dyn_cast(Element); + auto *VarDIE = getDIEs(Var).getVariableDIE(Var); if (VarDIE) { DIE &ItemDie = createAndAddDIE(dwarf::DW_TAG_namelist_item, Buffer); addDIEEntry(ItemDie, dwarf::DW_AT_namelist_item, *VarDIE); @@ -1185,7 +1181,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) { Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { if (auto *Var = dyn_cast_or_null(CTy->getRawSizeInBits())) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_bit_size, *VarDIE); } else if (auto *Exp = dyn_cast_or_null(CTy->getRawSizeInBits())) { @@ -1340,6 +1336,19 @@ DIE *DwarfUnit::getOrCreateModule(const DIModule *M) { return &MDie; } +DIE *DwarfUnit::getExistingSubprogramDIE(const DISubprogram *SP, + const Function *F) const { + if (!F) { + if (DIE *SPDie = getDIEs(SP).getLocalScopes().getAnyConcreteDIE(SP)) + return SPDie; + } else { + if (DIE *SPDie = getDIEs(SP).getLocalScopes().getConcreteDIE(SP, F)) + return SPDie; + } + + return nullptr; +} + DIE *DwarfUnit::getOrCreateSubprogramDIE(const DISubprogram *SP, const Function *FnHint, bool Minimal) { // Construct the context before querying for the existence of the DIE in case @@ -1348,7 +1357,7 @@ DIE *DwarfUnit::getOrCreateSubprogramDIE(const DISubprogram *SP, DIE *ContextDIE = getOrCreateSubprogramContextDIE(SP, shouldPlaceInUnitDIE(SP, Minimal)); - if (DIE *SPDie = getDIE(SP)) + if (DIE *SPDie = getExistingSubprogramDIE(SP, FnHint)) return SPDie; if (auto *SPDecl = SP->getDeclaration()) { @@ -1360,13 +1369,13 @@ DIE *DwarfUnit::getOrCreateSubprogramDIE(const DISubprogram *SP, // FIXME: Should the creation of definition subprogram DIE during // the creation of declaration subprogram DIE be allowed? // See https://github.com/llvm/llvm-project/pull/154636. - if (DIE *SPDie = getDIE(SP)) + if (DIE *SPDie = getExistingSubprogramDIE(SP, FnHint)) return SPDie; } } // DW_TAG_inlined_subroutine may refer to this DIE. - DIE &SPDie = createAndAddDIE(dwarf::DW_TAG_subprogram, *ContextDIE, SP); + DIE &SPDie = createAndAddSubprogramDIE(*ContextDIE, SP, FnHint); // Stop here and fill this in later, depending on whether or not this // subprogram turns out to have inlined instances or not. @@ -1392,7 +1401,8 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP, if (DefinitionArgs[0] != nullptr && DeclArgs[0] != DefinitionArgs[0]) addType(SPDie, DefinitionArgs[0]); - DeclDie = getDIE(SPDecl); + DeclDie = + getDIEs(SPDecl).getLocalScopes().getConcreteDIE(SPDecl, nullptr); assert(DeclDie && "This DIE should've already been constructed when the " "definition DIE was created in " "getOrCreateSubprogramDIE"); @@ -1416,7 +1426,8 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP, StringRef LinkageName = SP->getLinkageName(); // Always emit linkage name for abstract subprograms. if (DeclLinkageName != LinkageName && - (DD->useAllLinkageNames() || DU->getAbstractScopeDIEs().lookup(SP))) + (DD->useAllLinkageNames() || + DU->getDIEs().getLocalScopes().getAbstractDIEs().lookup(SP))) addLinkageName(SPDie, LinkageName); if (!DeclDie) @@ -1586,7 +1597,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &DW_Subrange, const DISubrangeType *SR, auto AddBoundTypeEntry = [&](dwarf::Attribute Attr, DISubrangeType::BoundType Bound) -> void { if (auto *BV = dyn_cast_if_present(Bound)) { - if (auto *VarDIE = getDIE(BV)) + if (auto *VarDIE = getDIEs(BV).getVariableDIE(BV)) addDIEEntry(DW_Subrange, Attr, *VarDIE); } else if (auto *BE = dyn_cast_if_present(Bound)) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1628,7 +1639,7 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR) { auto AddBoundTypeEntry = [&](dwarf::Attribute Attr, DISubrange::BoundType Bound) -> void { if (auto *BV = dyn_cast_if_present(Bound)) { - if (auto *VarDIE = getDIE(BV)) + if (auto *VarDIE = getDIEs(BV).getVariableDIE(BV)) addDIEEntry(DW_Subrange, Attr, *VarDIE); } else if (auto *BE = dyn_cast_if_present(Bound)) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1670,7 +1681,7 @@ void DwarfUnit::constructGenericSubrangeDIE(DIE &Buffer, auto AddBoundTypeEntry = [&](dwarf::Attribute Attr, DIGenericSubrange::BoundType Bound) -> void { if (auto *BV = dyn_cast_if_present(Bound)) { - if (auto *VarDIE = getDIE(BV)) + if (auto *VarDIE = getDIEs(BV).getVariableDIE(BV)) addDIEEntry(DwGenericSubrange, Attr, *VarDIE); } else if (auto *BE = dyn_cast_if_present(Bound)) { if (BE->isConstant() && @@ -1749,7 +1760,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } if (DIVariable *Var = CTy->getDataLocation()) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_data_location, *VarDIE); } else if (DIExpression *Expr = CTy->getDataLocationExp()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1760,7 +1771,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } if (DIVariable *Var = CTy->getAssociated()) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_associated, *VarDIE); } else if (DIExpression *Expr = CTy->getAssociatedExp()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1771,7 +1782,7 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { } if (DIVariable *Var = CTy->getAllocated()) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_allocated, *VarDIE); } else if (DIExpression *Expr = CTy->getAllocatedExp()) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1896,7 +1907,7 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { if (DT->getRawSizeInBits() == nullptr) { // No size, just ignore. } else if (auto *Var = dyn_cast(DT->getRawSizeInBits())) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(MemberDie, dwarf::DW_AT_bit_size, *VarDIE); } else if (auto *Exp = dyn_cast(DT->getRawSizeInBits())) { DIELoc *Loc = new (DIEValueAllocator) DIELoc; @@ -1921,7 +1932,7 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) { // See https://dwarfstd.org/issues/250501.1.html if (auto *Var = dyn_cast_or_null(DT->getRawOffsetInBits())) { if (!Asm->TM.Options.DebugStrictDwarf || DD->getDwarfVersion() >= 6) { - if (auto *VarDIE = getDIE(Var)) + if (auto *VarDIE = getDIEs(Var).getVariableDIE(Var)) addDIEEntry(MemberDie, dwarf::DW_AT_data_bit_offset, *VarDIE); } } else if (auto *Expr = diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 9288d7edbf156..626e08964a875 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -61,7 +61,7 @@ class DwarfUnit : public DIEUnit { /// Tracks the mapping of unit level debug information variables to debug /// information entries. - DenseMap MDNodeToDieMap; + DwarfInfoHolder InfoHolder; /// A list of all the DIEBlocks in use. std::vector DIEBlocks; @@ -139,7 +139,7 @@ class DwarfUnit : public DIEUnit { /// We delegate the request to DwarfDebug when the MDNode can be part of the /// type system, since DIEs for the type system can be shared across CUs and /// the mappings are kept in DwarfDebug. - DIE *getDIE(const DINode *D) const; + DIE *getDIE(const DINode *D) const { return getDIEs(D).getDIE(D); } /// Returns a fresh newly allocated DIELoc. DIELoc *getDIELoc() { return new (DIEValueAllocator) DIELoc; } @@ -153,6 +153,18 @@ class DwarfUnit : public DIEUnit { void insertDIE(DIE *D); + const DwarfInfoHolder &getDIEs(const DINode *N) const { + if (isShareableAcrossCUs(N)) + return DU->getDIEs(); + + return InfoHolder; + } + + DwarfInfoHolder &getDIEs(const DINode *N) { + return const_cast( + const_cast(this)->getDIEs(N)); + } + /// Add a flag that is true to the DIE. void addFlag(DIE &Die, dwarf::Attribute Attribute); @@ -286,6 +298,8 @@ class DwarfUnit : public DIEUnit { /// Create a DIE with the given Tag, add the DIE to its parent, and /// call insertDIE if MD is not null. DIE &createAndAddDIE(dwarf::Tag Tag, DIE &Parent, const DINode *N = nullptr); + DIE &createAndAddSubprogramDIE(DIE &Parent, const DISubprogram *SP, + const Function *F); bool useSegmentedStringOffsetsTable() const { return DD->useSegmentedStringOffsetsTable(); @@ -387,6 +401,9 @@ class DwarfUnit : public DIEUnit { void constructTemplateValueParameterDIE(DIE &Buffer, const DITemplateValueParameter *TVP); + DIE *getExistingSubprogramDIE(const DISubprogram *SP, + const Function *FnHint) const; + /// Return the default lower bound for an array. /// /// If the DWARF version doesn't handle the language, return -1. diff --git a/llvm/lib/CodeGen/LexicalScopes.cpp b/llvm/lib/CodeGen/LexicalScopes.cpp index 9fc9ac9a66d41..49100fa153135 100644 --- a/llvm/lib/CodeGen/LexicalScopes.cpp +++ b/llvm/lib/CodeGen/LexicalScopes.cpp @@ -61,19 +61,28 @@ void LexicalScopes::initialize(const Module &M) { for (const Function &F : M) { DISubprogram *SP = F.getSubprogram(); if (SP && (!SP->getUnit() || !skipUnit(SP->getUnit()))) - FunctionMap[SP] = &F; + FunctionMap[SP].insert(&F); } } void LexicalScopes::scanFunction(const MachineFunction &Fn) { resetFunction(); // Don't attempt any lexical scope creation for a NoDebug compile unit. - if (skipUnit(Fn.getFunction().getSubprogram()->getUnit())) + const Function &IRFunc = Fn.getFunction(); + const DISubprogram *SP = IRFunc.getSubprogram(); + if (skipUnit(SP->getUnit())) return; + + // A new subprogram may be created during Codegen after module scan. + FunctionMap[SP].insert(&IRFunc); + MF = &Fn; SmallVector MIRanges; DenseMap MI2ScopeMap; extractLexicalScopes(MIRanges, MI2ScopeMap); + // If no scopes were extracted, abstract scope is still needed + // for a subprogram attached to multiple functions. + ensureAbstractLexicalScopeIsCreated(SP); if (CurrentFnLexicalScope) { constructScopeNest(CurrentFnLexicalScope); assignInstructionRanges(MIRanges, MI2ScopeMap); @@ -167,6 +176,8 @@ LexicalScope *LexicalScopes::getOrCreateLexicalScope(const DILocalScope *Scope, return getOrCreateInlinedScope(Scope, IA); } + // Parent DISubprogram may be attached by multiple functions. + ensureAbstractLexicalScopeIsCreated(Scope); return getOrCreateRegularScope(Scope); } diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index c9ff86b7df16b..f674ba5b820cc 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -336,9 +336,6 @@ class Verifier : public InstVisitor, VerifierSupport { /// Keep track of the metadata nodes that have been checked already. SmallPtrSet MDNodes; - /// Keep track which DISubprogram is attached to which function. - DenseMap DISubprogramAttachments; - /// Track all DICompileUnits visited. SmallPtrSet CUVisited; @@ -485,7 +482,6 @@ class Verifier : public InstVisitor, VerifierSupport { verifyCompileUnits(); verifyDeoptimizeCallingConvs(); - DISubprogramAttachments.clear(); return !Broken; } @@ -3145,11 +3141,6 @@ void Verifier::visitFunction(const Function &F) { "function definition may only have a distinct !dbg attachment", &F); - auto *SP = cast(I.second); - const Function *&AttachedTo = DISubprogramAttachments[SP]; - CheckDI(!AttachedTo || AttachedTo == &F, - "DISubprogram attached to more than one function", SP, &F); - AttachedTo = &F; AllowLocs = AreDebugLocsAllowed::Yes; break; } diff --git a/llvm/test/DebugInfo/COFF/shared-sp.ll b/llvm/test/DebugInfo/COFF/shared-sp.ll new file mode 100644 index 0000000000000..5e985a5a9d07e --- /dev/null +++ b/llvm/test/DebugInfo/COFF/shared-sp.ll @@ -0,0 +1,129 @@ +; RUN: llc -filetype=obj < %s -o - 2>&1 | llvm-readobj - --codeview | FileCheck %s + +; Check that when DISubprogram is attached to two functions, CodeView is +; produced correctly. + +; CHECK: Subsection [ +; CHECK: GlobalProcIdSym { +; CHECK: Kind: S_GPROC32_ID (0x1147) +; CHECK: FunctionType: foo (0x1002) +; CHECK: CodeOffset: foo+0x0 +; CHECK: Flags [ (0x80) +; CHECK: HasOptimizedDebugInfo (0x80) +; CHECK: ] +; CHECK: DisplayName: foo +; CHECK: LinkageName: foo +; CHECK: } +; CHECK: LocalSym { +; CHECK: Kind: S_LOCAL (0x113E) +; CHECK: Type: int (0x74) +; CHECK: Flags [ (0x0) +; CHECK: ] +; CHECK: VarName: a +; CHECK: } +; CHECK: LocalSym { +; CHECK: Kind: S_LOCAL (0x113E) +; CHECK: Type: foo::bar (0x1005) +; CHECK: Flags [ (0x0) +; CHECK: ] +; CHECK: VarName: c +; CHECK: } +; CHECK: UDTSym { +; CHECK: Kind: S_UDT (0x1108) +; CHECK: Type: foo::bar (0x1005) +; CHECK: UDTName: foo::bar +; CHECK: } +; CHECK: ] +; CHECK: Subsection [ +; CHECK: GlobalProcIdSym { +; CHECK: Kind: S_GPROC32_ID (0x1147) +; CHECK: FunctionType: foo (0x1002) +; CHECK: CodeOffset: foo_clone+0x0 +; CHECK: Flags [ (0x80) +; CHECK: HasOptimizedDebugInfo (0x80) +; CHECK: ] +; CHECK: DisplayName: foo +; CHECK: LinkageName: foo_clone +; CHECK: } +; CHECK: LocalSym { +; CHECK: Kind: S_LOCAL (0x113E) +; CHECK: Type: int (0x74) +; CHECK: Flags [ (0x0) +; CHECK: ] +; CHECK: VarName: a +; CHECK: } +; CHECK: LocalSym { +; CHECK: Kind: S_LOCAL (0x113E) +; CHECK: Type: foo::bar (0x1005) +; CHECK: Flags [ (0x0) +; CHECK: ] +; CHECK: VarName: c +; CHECK: } +; CHECK: UDTSym { +; CHECK: Kind: S_UDT (0x1108) +; CHECK: Type: foo::bar (0x1005) +; CHECK: UDTName: foo::bar +; CHECK: } +; CHECK: ] + +; ModuleID = 'shared-sp.ll' +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.29.30133" + +!0 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !2, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !{}) +!1 = !DIFile(filename: "example.c", directory: "/") +!2 = !DISubroutineType(types: !3) +!3 = !{!5} +!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + +; Local variable. +!10 = !DILocalVariable(name: "a", scope: !0, file: !1, line: 2, type: !5) + +; DICompositeType local to foo. +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", scope: !0, file: !1, line: 2, size: 32, elements: !12) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !11, file: !1, line: 2, baseType: !5, size: 32) + +; Local variable of type struct bar, local to foo. +!14 = !DILocalVariable(name: "c", scope: !0, file: !1, line: 2, type: !11) + +!101 = !DILocation(line: 2, column: 5, scope: !0) +!102 = !DILocation(line: 3, column: 1, scope: !0) +!103 = !DILocation(line: 2, column: 12, scope: !0) + +!llvm.dbg.cu = !{!4} +!llvm.module.flags = !{!29, !30} + +!29 = !{i32 2, !"CodeView", i32 1} +!30 = !{i32 2, !"Debug Info Version", i32 3} + +define i32 @foo() !dbg !0 { +entry: + ; Local variable 'a' debug info. + %a.addr = alloca i32, align 4, !dbg !101 + #dbg_declare(ptr %a.addr, !10, !DIExpression(), !101) + store i32 42, ptr %a.addr, align 4, !dbg !101 + + ; Local variable 'c' (struct bar) debug info. + %c.addr = alloca %struct.bar, align 4, !dbg !103 + #dbg_declare(ptr %c.addr, !14, !DIExpression(), !103) + + ret i32 42, !dbg !102 +} + +define i32 @foo_clone() !dbg !0 { +entry: + ; Local variable 'a' debug info. + %a.addr = alloca i32, align 4, !dbg !101 + #dbg_declare(ptr %a.addr, !10, !DIExpression(), !101) + store i32 42, ptr %a.addr, align 4, !dbg !101 + + ; Local variable 'c' (struct bar) debug info. + %c.addr = alloca %struct.bar, align 4, !dbg !103 + #dbg_declare(ptr %c.addr, !14, !DIExpression(), !103) + + ret i32 42, !dbg !102 +} + +%struct.bar = type { i32 } diff --git a/llvm/test/DebugInfo/COFF/udts-complete.ll b/llvm/test/DebugInfo/COFF/udts-complete.ll index e5ee8521ab489..50000c793ac29 100644 --- a/llvm/test/DebugInfo/COFF/udts-complete.ll +++ b/llvm/test/DebugInfo/COFF/udts-complete.ll @@ -33,10 +33,10 @@ ; CHECK: Mod 0000 | `.debug$S`: ; CHECK: 0 | S_GDATA32 [size = 20] `gv` ; CHECK: type = 0x1002 (Foo), addr = 0000:0000 -; CHECK: 0 | S_UDT [size = 12] `Bar` -; CHECK: original type = 0x1002 ; CHECK: 0 | S_UDT [size = 12] `Baz` ; CHECK: original type = 0x1002 +; CHECK: 0 | S_UDT [size = 12] `Bar` +; CHECK: original type = 0x1002 ; CHECK: 0 | S_UDT [size = 12] `Foo` ; CHECK: original type = 0x1002 diff --git a/llvm/test/DebugInfo/COFF/udts-fixpoint.ll b/llvm/test/DebugInfo/COFF/udts-fixpoint.ll index c070135edfda8..294d0afc0481d 100644 --- a/llvm/test/DebugInfo/COFF/udts-fixpoint.ll +++ b/llvm/test/DebugInfo/COFF/udts-fixpoint.ll @@ -16,11 +16,11 @@ ; Check that there are only two typedefs, a and c. ; CHECK: .short 4360 # Record kind: S_UDT ; CHECK: .long {{.*}} # Type -; CHECK: .asciz "a" +; CHECK: .asciz "c" ; CHECK: .p2align 2 ; CHECK: .short 4360 # Record kind: S_UDT ; CHECK: .long {{.*}} # Type -; CHECK: .asciz "c" +; CHECK: .asciz "a" ; CHECK: .p2align 2 ; No other S_UDTs. ; CHECK-NOT: S_UDT diff --git a/llvm/test/DebugInfo/X86/namelist1.ll b/llvm/test/DebugInfo/X86/namelist1.ll index 92c0777f3422e..22d0f3631e8aa 100644 --- a/llvm/test/DebugInfo/X86/namelist1.ll +++ b/llvm/test/DebugInfo/X86/namelist1.ll @@ -2,7 +2,10 @@ ; DW_TAG_namelist_item attributes are emitted correctly. ; ; RUN: llc -O0 -mtriple=x86_64-unknown-linux-gnu %s -filetype=obj -o %t.o -; RUN: llvm-dwarfdump %t.o | FileCheck %s +; RUN: llvm-dwarfdump %t.o | FileCheck %s --implicit-check-not=DW_TAG_subprogram +; +; Ensure that a single DW_TAG_subprogram is produced. +; CHECK: DW_TAG_subprogram ; ; CHECK: [[ITEM1:0x.+]]: DW_TAG_variable ; CHECK: DW_AT_name ("a") diff --git a/llvm/test/DebugInfo/X86/shared-empty-sp.ll b/llvm/test/DebugInfo/X86/shared-empty-sp.ll new file mode 100644 index 0000000000000..925efa2a22d0c --- /dev/null +++ b/llvm/test/DebugInfo/X86/shared-empty-sp.ll @@ -0,0 +1,48 @@ +; RUN: llc -filetype=obj < %s -o %t 2>&1 | FileCheck --allow-empty --implicit-check-not='warning:' %s +; RUN: llvm-dwarfdump -verify %t +; RUN: llvm-dwarfdump %t | FileCheck %s --check-prefix=DWARF --implicit-check-not=DW_TAG + +; DWARF: DW_TAG_compile_unit + +; Abstract subprogram. +; DWARF: [[FOO:.*]]: DW_TAG_subprogram +; DWARF: DW_AT_name ("foo" +; DWARF: DW_AT_inline (DW_INL_inlined) + +; Concrete subprogram. +; DWARF: DW_TAG_subprogram +; DWARF: DW_AT_abstract_origin ([[FOO]] + +; Concrete subprogram. +; DWARF: DW_TAG_subprogram +; DWARF: DW_AT_abstract_origin ([[FOO]] + +; Check that when DISubprogram is attached to two empty functions (with no lexical scopes), +; they get different DW_TAG_subprograms. + +; ModuleID = 'example' + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64--linux" + +!0 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !2, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !{}) +!1 = !DIFile(filename: "example.c", directory: "/") +!2 = !DISubroutineType(types: !4) +!4 = !{} + +!3 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) + +!llvm.dbg.cu = !{!3} +!llvm.module.flags = !{!30} + +!30 = !{i32 1, !"Debug Info Version", i32 3} + +define void @foo() !dbg !0 { +entry: + ret void +} + +define void @foo_clone() !dbg !0 { +entry: + ret void +} diff --git a/llvm/test/DebugInfo/X86/shared-sp.ll b/llvm/test/DebugInfo/X86/shared-sp.ll new file mode 100644 index 0000000000000..34a6186d79e69 --- /dev/null +++ b/llvm/test/DebugInfo/X86/shared-sp.ll @@ -0,0 +1,98 @@ +; RUN: llc -filetype=obj < %s -o %t 2>&1 | FileCheck --allow-empty --implicit-check-not='warning:' %s +; RUN: llvm-dwarfdump -verify %t +; RUN: llvm-dwarfdump %t | FileCheck %s --check-prefix=DWARF --implicit-check-not=DW_TAG + +; Check that when DISubprogram is attached to two functions, DWARF is produced +; correctly. + +; DWARF: DW_TAG_compile_unit + +; Abstract subprogram. +; DWARF: [[FOO:.*]]: DW_TAG_subprogram +; DWARF: DW_AT_name ("foo" +; DWARF: DW_AT_inline (DW_INL_inlined) +; DWARF: [[A:.*]]: DW_TAG_variable +; DWARF: DW_AT_name ("a" +; DWARF: DW_TAG_structure_type +; DWARF: DW_TAG_member +; DWARF: [[C:.*]]: DW_TAG_variable +; DWARF: DW_AT_name ("c" + +; DWARF: DW_TAG_base_type + +; Concrete subprogram. +; DWARF: DW_TAG_subprogram +; DWARF: DW_AT_abstract_origin ([[FOO]] +; DWARF: DW_TAG_variable +; DWARF: DW_AT_abstract_origin ([[A]] +; DWARF: DW_TAG_variable +; DWARF: DW_AT_abstract_origin ([[C]] + +; Concrete subprogram. +; DWARF: DW_TAG_subprogram +; DWARF: DW_AT_abstract_origin ([[FOO]] +; DWARF: DW_TAG_variable +; DWARF: DW_AT_abstract_origin ([[A]] +; DWARF: DW_TAG_variable +; DWARF: DW_AT_abstract_origin ([[C]] + +; ModuleID = 'shared-sp.ll' +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64--linux" + +!0 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !2, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !{}) +!1 = !DIFile(filename: "example.c", directory: "/") +!2 = !DISubroutineType(types: !3) +!3 = !{!5} +!4 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) +!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + +; Local variable. +!10 = !DILocalVariable(name: "a", scope: !0, file: !1, line: 2, type: !5) + +; DICompositeType local to foo. +!11 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", scope: !0, file: !1, line: 2, size: 32, elements: !12) +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "m", scope: !11, file: !1, line: 2, baseType: !5, size: 32) + +; Local variable of type struct bar, local to foo. +!14 = !DILocalVariable(name: "c", scope: !0, file: !1, line: 2, type: !11) + +!101 = !DILocation(line: 2, column: 5, scope: !0) +!102 = !DILocation(line: 3, column: 1, scope: !0) +!103 = !DILocation(line: 2, column: 12, scope: !0) + +!llvm.dbg.cu = !{!4} +!llvm.module.flags = !{!30} + +!30 = !{i32 2, !"Debug Info Version", i32 3} + +define i32 @foo() !dbg !0 { +entry: + ; Local variable 'a' debug info. + %a.addr = alloca i32, align 4, !dbg !101 + #dbg_declare(ptr %a.addr, !10, !DIExpression(), !101) + store i32 42, ptr %a.addr, align 4, !dbg !101 + + ; Local variable 'c' (struct bar) debug info. + %c.addr = alloca %struct.bar, align 4, !dbg !103 + #dbg_declare(ptr %c.addr, !14, !DIExpression(), !103) + + ret i32 42, !dbg !102 +} + +define i32 @foo_clone() !dbg !0 { +entry: + ; Local variable 'a' debug info. + %a.addr = alloca i32, align 4, !dbg !101 + #dbg_declare(ptr %a.addr, !10, !DIExpression(), !101) + store i32 42, ptr %a.addr, align 4, !dbg !101 + + ; Local variable 'c' (struct bar) debug info. + %c.addr = alloca %struct.bar, align 4, !dbg !103 + #dbg_declare(ptr %c.addr, !14, !DIExpression(), !103) + + ret i32 42, !dbg !102 +} + +%struct.bar = type { i32 } diff --git a/llvm/test/Verifier/metadata-function-dbg.ll b/llvm/test/Verifier/metadata-function-dbg.ll index 23ac6f31c9e1a..79a7e99959cc0 100644 --- a/llvm/test/Verifier/metadata-function-dbg.ll +++ b/llvm/test/Verifier/metadata-function-dbg.ll @@ -11,16 +11,6 @@ define void @f2() !dbg !4 !dbg !4 { unreachable } -; CHECK: DISubprogram attached to more than one function -define void @f3() !dbg !4 { - unreachable -} - -; CHECK: DISubprogram attached to more than one function -define void @f4() !dbg !4 { - unreachable -} - ; CHECK-NOT: !dbg ; CHECK: function !dbg attachment must be a subprogram ; CHECK-NEXT: ptr @bar diff --git a/llvm/unittests/CodeGen/LexicalScopesTest.cpp b/llvm/unittests/CodeGen/LexicalScopesTest.cpp index 0c6b9326bcfd4..cd9a1d13a190f 100644 --- a/llvm/unittests/CodeGen/LexicalScopesTest.cpp +++ b/llvm/unittests/CodeGen/LexicalScopesTest.cpp @@ -140,6 +140,7 @@ TEST_F(LexicalScopesTest, FlatLayout) { LS.resetFunction(); EXPECT_EQ(LS.getCurrentFunctionScope(), nullptr); + LS.initialize(Mod); LS.scanFunction(*MF); EXPECT_FALSE(LS.empty()); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); @@ -183,6 +184,7 @@ TEST_F(LexicalScopesTest, BlockScopes) { BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); EXPECT_EQ(FuncScope->getDesc(), OurFunc); @@ -218,6 +220,7 @@ TEST_F(LexicalScopesTest, InlinedScopes) { BuildMI(*MBB4, MBB4->end(), InlinedLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); auto &Children = FuncScope->getChildren(); @@ -253,6 +256,7 @@ TEST_F(LexicalScopesTest, FuncWithEmptyGap) { BuildMI(*MBB4, MBB4->end(), OutermostLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); @@ -274,6 +278,7 @@ TEST_F(LexicalScopesTest, FuncWithRealGap) { MachineInstr *LastI = BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get()); ASSERT_NE(BlockScope, nullptr); @@ -307,6 +312,7 @@ TEST_F(LexicalScopesTest, NotNested) { MachineInstr *FourthI = BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get()); @@ -345,6 +351,7 @@ TEST_F(LexicalScopesTest, TestDominates) { BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get()); @@ -387,6 +394,7 @@ TEST_F(LexicalScopesTest, TestGetBlocks) { BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get()); @@ -444,6 +452,7 @@ TEST_F(LexicalScopesTest, TestMetaInst) { BuildMI(*MBB4, MBB4->end(), InBlockLoc, BeanInst); LexicalScopes LS; + LS.initialize(Mod); LS.scanFunction(*MF); LexicalScope *FuncScope = LS.getCurrentFunctionScope(); LexicalScope *BlockScope = LS.findLexicalScope(InBlockLoc.get()); @@ -475,9 +484,111 @@ TEST_F(LexicalScopesTest, TestFunctionScan) { LexicalScopes LS; LS.initialize(Mod); - ASSERT_EQ(LS.getFunction(OurFunc), &MF->getFunction()); - ASSERT_EQ(LS.getFunction(Func2), &MF2->getFunction()); - ASSERT_EQ(LS.getFunction(UnattachedFunc), nullptr); + auto Fs = LS.getFunctions(OurFunc); + ASSERT_NE(Fs, nullptr); + ASSERT_EQ(Fs->size(), 1u); + ASSERT_EQ(*Fs->begin(), &MF->getFunction()); + + Fs = LS.getFunctions(Func2); + ASSERT_NE(Fs, nullptr); + ASSERT_EQ(Fs->size(), 1u); + ASSERT_EQ(*Fs->begin(), &MF2->getFunction()); + + Fs = LS.getFunctions(UnattachedFunc); + ASSERT_EQ(Fs, nullptr); +} + +// Test function map creation for subprogram attached to multiple functions. +// Ensure that abstract lexical scopes for subprograms attached to multiple +// functions are created. +TEST_F(LexicalScopesTest, TestRepeatingSubprogram) { + BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst); + + std::unique_ptr MF2 = + createMachineFunction(Ctx, Mod, "Test.1"); + auto &F2 = MF2->getFunction(); + F2.setSubprogram(OurFunc); + auto BB1_2 = BasicBlock::Create(Ctx, "a", &F2); + IRBuilder<> IRB1_2(BB1_2); + IRB1_2.CreateRetVoid(); + auto *MBB1_2 = MF->CreateMachineBasicBlock(BB1_2); + MF2->insert(MF2->end(), MBB1_2); + BuildMI(*MBB1_2, MBB1_2->end(), InBlockLoc, BeanInst); + + std::unique_ptr FooMF = + createMachineFunction(Ctx, Mod, "Foo"); + auto BB = BasicBlock::Create(Ctx, "a", &FooMF->getFunction()); + IRBuilder<> IRB(BB); + IRB.CreateRetVoid(); + auto FooMBB = FooMF->CreateMachineBasicBlock(BB); + FooMF->insert(FooMF->end(), FooMBB); + + DIBuilder DIB(Mod, true, OurCU); + auto OurSubT = DIB.createSubroutineType(DIB.getOrCreateTypeArray({})); + DISubprogram *FooFunc = + DIB.createFunction(OurCU, "Foo", "", OurFile, 1, OurSubT, 1, + DINode::FlagZero, DISubprogram::SPFlagDefinition); + FooMF->getFunction().setSubprogram(FooFunc); + DIB.finalize(); + + BuildMI(*FooMBB, FooMBB->end(), DILocation::get(Ctx, 10, 20, FooFunc), + BeanInst); + + LexicalScopes LS; + LS.initialize(Mod); + + auto Fs = LS.getFunctions(OurFunc); + ASSERT_NE(Fs, nullptr); + ASSERT_EQ(Fs->size(), 2u); + ASSERT_TRUE(Fs->contains(&MF->getFunction())); + ASSERT_TRUE(Fs->contains(&MF2->getFunction())); + + Fs = LS.getFunctions(FooFunc); + ASSERT_NE(Fs, nullptr); + ASSERT_EQ(Fs->size(), 1u); + ASSERT_TRUE(Fs->contains(&FooMF->getFunction())); + + LS.scanFunction(*MF); + EXPECT_FALSE(LS.currentFunctionHasInlinedScopes()); + EXPECT_EQ(LS.getAbstractScopesList().size(), 1u); + EXPECT_EQ(LS.getAbstractScopesList()[0]->getScopeNode(), OurFunc); + + LS.scanFunction(*MF2); + EXPECT_FALSE(LS.currentFunctionHasInlinedScopes()); + EXPECT_EQ(LS.getAbstractScopesList().size(), 1u); + EXPECT_EQ(LS.getAbstractScopesList()[0]->getScopeNode(), OurFunc); + + LS.scanFunction(*FooMF); + EXPECT_FALSE(LS.currentFunctionHasInlinedScopes()); + EXPECT_EQ(LS.getAbstractScopesList().size(), 0u); + EXPECT_NE(LS.findLexicalScope(FooFunc), nullptr); +} + +// Test that if a DISubprogram is attached to two functions, +// an abstract lexical block is created after scanning a first function. +TEST_F(LexicalScopesTest, TestRepeatingLexicalBlocks) { + BuildMI(*MBB1, MBB1->end(), InBlockLoc, BeanInst); + + std::unique_ptr MF2 = createMachineFunction(Ctx, Mod, "Foo"); + auto BB = BasicBlock::Create(Ctx, "a", &MF2->getFunction()); + IRBuilder<> IRB(BB); + IRB.CreateRetVoid(); + auto MBB = MF2->CreateMachineBasicBlock(BB); + MF2->insert(MF2->end(), MBB); + + MF2->getFunction().setSubprogram(OurFunc); + + BuildMI(*MBB, MBB->end(), InBlockLoc, BeanInst); + + LexicalScopes LS; + LS.initialize(Mod); + LS.scanFunction(*MF2); + EXPECT_NE(LS.findAbstractScope(OurFunc), nullptr); + EXPECT_NE(LS.findAbstractScope(OurBlock), nullptr); + + LS.scanFunction(*MF); + EXPECT_NE(LS.findAbstractScope(OurFunc), nullptr); + EXPECT_NE(LS.findAbstractScope(OurBlock), nullptr); } } // anonymous namespace