[llvm] 75b622a - Reland [DwarfDebug] Support emitting function-local declaration for a lexical block
Kristina Bessonova via llvm-commits
llvm-commits at lists.llvm.org
Sun Dec 5 03:57:14 PST 2021
Author: Kristina Bessonova
Date: 2021-12-05T13:56:45+02:00
New Revision: 75b622a7959479ccdb758ebe0973061b7b4fcacd
URL: https://github.com/llvm/llvm-project/commit/75b622a7959479ccdb758ebe0973061b7b4fcacd
DIFF: https://github.com/llvm/llvm-project/commit/75b622a7959479ccdb758ebe0973061b7b4fcacd.diff
LOG: Reland [DwarfDebug] Support emitting function-local declaration for a lexical block
This is another attempt to make function-local declarations
(like static variables, structs/classes and other) be correctly
emitted within a lexical (bracketed) block.
Fixes https://bugs.llvm.org/show_bug.cgi?id=19238.
Reviewed By: dblaikie
Differential Revision: https://reviews.llvm.org/D113741
Added:
llvm/test/DebugInfo/Generic/import-inlined-declaration.ll
llvm/test/DebugInfo/Generic/inlined-local-type.ll
llvm/test/DebugInfo/Generic/inlined-static-var.ll
llvm/test/DebugInfo/Generic/lexical_block_static.ll
llvm/test/DebugInfo/Generic/lexical_block_types.ll
Modified:
llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
llvm/test/DebugInfo/Generic/imported-name-inlined.ll
llvm/test/DebugInfo/Generic/namespace.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index 0d2736178f0f7..38f0ed501cb13 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -551,8 +551,18 @@ void DwarfCompileUnit::constructScopeDIE(LexicalScope *Scope,
// 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);
}
@@ -646,7 +656,7 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope) {
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);
@@ -1001,6 +1011,12 @@ DIE &DwarfCompileUnit::constructSubprogramScopeDIE(const DISubprogram *Sub,
if (Scope) {
assert(!Scope->getInlinedAt());
assert(!Scope->isAbstractScope());
+
+ // Remember the subrogram 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.
@@ -1036,27 +1052,18 @@ DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
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<DIImportedEntity>(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<DISubprogram>(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
@@ -1072,11 +1079,10 @@ DIE *DwarfCompileUnit::createAndAddScopeChildren(LexicalScope *Scope,
void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
LexicalScope *Scope) {
- DIE *&AbsDef = getAbstractSPDies()[Scope->getScopeNode()];
- if (AbsDef)
- return;
auto *SP = cast<DISubprogram>(Scope->getScopeNode());
+ if (auto *SPDie = getAbstractScopeDIEs().lookup(SP))
+ return;
DIE *ContextDIE;
DwarfCompileUnit *ContextCU = this;
@@ -1100,14 +1106,19 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE(
// 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::Form>()
: 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 {
@@ -1241,47 +1252,61 @@ void DwarfCompileUnit::constructCallSiteParmEntryDIEs(
}
}
-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<DINamespace>(Entity))
EntityDie = getOrCreateNameSpace(NS);
else if (auto *M = dyn_cast<DIModule>(Entity))
EntityDie = getOrCreateModule(M);
- else if (auto *SP = dyn_cast<DISubprogram>(Entity))
- EntityDie = getOrCreateSubprogramDIE(SP);
- else if (auto *T = dyn_cast<DIType>(Entity))
+ else if (auto *SP = dyn_cast<DISubprogram>(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<DIType>(Entity))
EntityDie = getOrCreateTypeDIE(T);
else if (auto *GV = dyn_cast<DIGlobalVariable>(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<DIImportedEntity>(Element)));
+ IMDie->addChild(createImportedEntityDIE(cast<DIImportedEntity>(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);
@@ -1571,3 +1596,38 @@ void DwarfCompileUnit::createBaseTypeDIEs() {
Btr.Die = &Die;
}
}
+
+static DIE *
+findLocalScopeDIE(const DILocalScope *LS,
+ DenseMap<const DILocalScope *, DIE *> &ScopeDIEs) {
+ DIE *ScopeDIE = ScopeDIEs.lookup(LS);
+ if (isa<DISubprogram>(LS) && !ScopeDIE)
+ return nullptr;
+ if (!ScopeDIE)
+ return findLocalScopeDIE(cast<DILocalScope>(LS->getScope()), ScopeDIEs);
+ return ScopeDIE;
+}
+
+DIE *DwarfCompileUnit::findLocalScopeDIE(const DIScope *S) {
+ auto *LScope = dyn_cast_or_null<DILocalScope>(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<DILocalScope>(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/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
index fb03982b5e4a2..251bc4bea68b3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
@@ -62,11 +62,6 @@ class DwarfCompileUnit final : public DwarfUnit {
/// The start of the unit macro info within macro section.
MCSymbol *MacroLabelBegin;
- using ImportedEntityList = SmallVector<const MDNode *, 8>;
- using ImportedEntityMap = DenseMap<const MDNode *, ImportedEntityList>;
-
- ImportedEntityMap ImportedEntities;
-
/// GlobalNames - A map of globally visible named entities for this unit.
StringMap<const DIE *> GlobalNames;
@@ -80,9 +75,14 @@ class DwarfCompileUnit final : public DwarfUnit {
// ranges/locs.
const MCSymbol *BaseAddress = nullptr;
- DenseMap<const MDNode *, DIE *> AbstractSPDies;
+ DenseMap<const DILocalScope *, DIE *> LocalScopeDIEs;
+ DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
+ /// LocalScopesWithLocalDecls - A list of non-empty local scopes
+ /// (with declaraions of static locals, function-local types, or imports).
+ SmallPtrSet<const DILocalScope *, 8> LocalScopesWithLocalDecls;
+
/// DWO ID for correlating skeleton and split units.
uint64_t DWOId = 0;
@@ -92,10 +92,10 @@ class DwarfCompileUnit final : public DwarfUnit {
bool isDwoUnit() const override;
- DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
+ DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
- return AbstractSPDies;
- return DU->getAbstractSPDies();
+ return AbstractLocalScopeDIEs;
+ return DU->getAbstractScopeDIEs();
}
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
@@ -169,17 +169,6 @@ class DwarfCompileUnit final : public DwarfUnit {
unsigned getOrCreateSourceID(const DIFile *File) override;
- void addImportedEntity(const DIImportedEntity* IE) {
- DIScope *Scope = IE->getScope();
- assert(Scope && "Invalid Scope encoding!");
- if (!isa<DILocalScope>(Scope))
- // No need to add imported enities that are not local declaration.
- return;
-
- auto *LocalScope = cast<DILocalScope>(Scope)->getNonLexicalBlockFileScope();
- ImportedEntities[LocalScope].push_back(IE);
- }
-
/// addRange - Add an address range to the list of ranges for this unit.
void addRange(RangeSpan Range);
@@ -221,6 +210,9 @@ class DwarfCompileUnit final : public DwarfUnit {
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);
@@ -259,8 +251,9 @@ class DwarfCompileUnit final : public DwarfUnit {
void constructCallSiteParmEntryDIEs(DIE &CallSiteDIE,
SmallVector<DbgCallSiteParam, 4> &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);
@@ -357,6 +350,10 @@ class DwarfCompileUnit final : public DwarfUnit {
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/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 1943df0422e81..c4795fdea9142 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -516,7 +516,7 @@ void DwarfDebug::addSubprogramNames(const DICompileUnit &CU,
// 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
@@ -1067,6 +1067,45 @@ void DwarfDebug::finishUnitAttributes(const DICompileUnit *DIUnit,
}
}
}
+
+// 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<DICommonBlock>(S))
+ S = S->getScope();
+ if (const auto *LScope = dyn_cast_or_null<DILocalScope>(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<DIType>(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 &
@@ -1081,9 +1120,6 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
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
@@ -1103,15 +1139,12 @@ DwarfDebug::getOrCreateDwarfCompileUnit(const DICompileUnit *DIUnit) {
CUMap.insert({DIUnit, &NewCU});
CUDieMap.insert({&NewCU.getUnitDie(), &NewCU});
- return NewCU;
-}
-void DwarfDebug::constructAndAddImportedEntityDIE(DwarfCompileUnit &TheCU,
- const DIImportedEntity *N) {
- if (isa<DILocalScope>(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
@@ -1354,6 +1387,7 @@ void DwarfDebug::endModule() {
assert(CurFn == nullptr);
assert(CurMI == nullptr);
+ // Collect global variables info.
DenseMap<DIGlobalVariable *, SmallVector<DwarfCompileUnit::GlobalExpr, 1>>
GVMap;
for (const GlobalVariable &Global : MMI->getModule()->globals()) {
@@ -1413,7 +1447,7 @@ void DwarfDebug::endModule() {
// Emit imported entities last so that the relevant context
// is already available.
for (auto *IE : CUNode->getImportedEntities())
- constructAndAddImportedEntityDIE(*CU, IE);
+ CU->createAndAddImportedEntityDIE(IE);
CU->createBaseTypeDIEs();
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index 4e1a1b1e068df..d4372bc24c042 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -316,11 +316,13 @@ class DwarfDebug : public DebugHandlerBase {
/// can refer to them in spite of insertions into this list.
DebugLocStream DebugLocs;
+ using SubprogramSetVector =
+ SetVector<const DISubprogram *, SmallVector<const DISubprogram *, 16>,
+ SmallPtrSet<const DISubprogram *, 16>>;
+
/// This is a collection of subprogram MDNodes that are processed to
/// create DIEs.
- SetVector<const DISubprogram *, SmallVector<const DISubprogram *, 16>,
- SmallPtrSet<const DISubprogram *, 16>>
- ProcessedSPNodes;
+ SubprogramSetVector ProcessedSPNodes;
/// If nonnull, stores the current machine function we're processing.
const MachineFunction *CurFn = nullptr;
@@ -598,10 +600,6 @@ class DwarfDebug : public DebugHandlerBase {
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.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
index 79a6ce7801b70..464f4f048016d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
@@ -26,6 +26,7 @@ class DbgEntity;
class DbgVariable;
class DbgLabel;
class DINode;
+class DILocalScope;
class DwarfCompileUnit;
class DwarfUnit;
class LexicalScope;
@@ -87,7 +88,7 @@ class DwarfFile {
DenseMap<LexicalScope *, LabelList> ScopeLabels;
// Collection of abstract subprogram DIEs.
- DenseMap<const MDNode *, DIE *> AbstractSPDies;
+ DenseMap<const DILocalScope *, DIE *> AbstractLocalScopeDIEs;
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;
/// Maps MDNodes for type system with the corresponding DIEs. These DIEs can
@@ -162,8 +163,8 @@ class DwarfFile {
return ScopeLabels;
}
- DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
- return AbstractSPDies;
+ DenseMap<const DILocalScope *, DIE *> &getAbstractScopeDIEs() {
+ return AbstractLocalScopeDIEs;
}
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 976e359051443..cea866e22664c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1200,7 +1200,7 @@ bool DwarfUnit::applySubprogramDefinitionAttributes(const DISubprogram *SP,
"decl has a linkage name and it is
diff erent");
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/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 8140279adaef8..2d0821c90109d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -247,7 +247,7 @@ class DwarfUnit : public DIEUnit {
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/test/DebugInfo/Generic/import-inlined-declaration.ll b/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll
new file mode 100644
index 0000000000000..471526b1395c6
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/import-inlined-declaration.ll
@@ -0,0 +1,72 @@
+; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s
+
+; 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
index a3aaaff66f851..a26b687b1f674 100644
--- 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
index 0000000000000..b3f3f80c07d29
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/inlined-local-type.ll
@@ -0,0 +1,125 @@
+; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s
+
+; 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
index 0000000000000..60c986fc2b648
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/inlined-static-var.ll
@@ -0,0 +1,92 @@
+; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s
+
+; 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
+
+ at _ZZ11not_removedvE1A = internal global i32 0, align 4, !dbg !0
+ at _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.ll b/llvm/test/DebugInfo/Generic/lexical_block_static.ll
new file mode 100644
index 0000000000000..42c3cb10d303c
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/lexical_block_static.ll
@@ -0,0 +1,143 @@
+; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s
+
+; 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
+; 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
+; 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
+; CHECK: NULL
+; CHECK: NULL
+; CHECK: NULL
+
+$_ZZ7removedvE1A = comdat any
+
+ at _ZZ11not_removedvE1B = internal global i32 0, align 4, !dbg !0
+ at _ZZ3foovE1C = internal global i32 0, align 4, !dbg !10
+ at _ZZ7removedvE1A = linkonce_odr dso_local global i32 0, comdat, align 4, !dbg !15
+
+define dso_local i32 @_Z11not_removedv() !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
+}
+
+define dso_local i32 @_Z3foov() !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
+}
+
+!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: "/")
+!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 at 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 at github.com:llvm/llvm-project.git)"}
+!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
index 0000000000000..1d4e9e7eb3e7d
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/lexical_block_types.ll
@@ -0,0 +1,421 @@
+; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s
+
+; 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
index 6998e69b33d97..7b9bf9b531b82 100644
--- 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)
More information about the llvm-commits
mailing list