23 changes: 13 additions & 10 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARFCOMPILEUNIT_H
#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFCOMPILEUNIT_H

#include "DbgValueHistoryCalculator.h"
#include "DbgEntityHistoryCalculator.h"
#include "DwarfDebug.h"
#include "DwarfUnit.h"
#include "llvm/ADT/ArrayRef.h"
Expand Down Expand Up @@ -81,7 +81,7 @@ class DwarfCompileUnit final : public DwarfUnit {
const MCSymbol *BaseAddress = nullptr;

DenseMap<const MDNode *, DIE *> AbstractSPDies;
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables;
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;

/// DWO ID for correlating skeleton and split units.
uint64_t DWOId = 0;
Expand All @@ -98,10 +98,10 @@ class DwarfCompileUnit final : public DwarfUnit {
return DU->getAbstractSPDies();
}

DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> &getAbstractVariables() {
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
if (isDwoUnit() && !DD->shareAcrossDWOCUs())
return AbstractVariables;
return DU->getAbstractVariables();
return AbstractEntities;
return DU->getAbstractEntities();
}

public:
Expand Down Expand Up @@ -194,6 +194,9 @@ class DwarfCompileUnit final : public DwarfUnit {
DIE *constructVariableDIE(DbgVariable &DV, const LexicalScope &Scope,
DIE *&ObjectPointer);

/// Construct a DIE for the given DbgLabel.
DIE *constructLabelDIE(DbgLabel &DL, const LexicalScope &Scope);

/// A helper function to create children of a Scope DIE.
DIE *createScopeChildrenDIE(LexicalScope *Scope,
SmallVectorImpl<DIE *> &Children,
Expand All @@ -210,14 +213,12 @@ class DwarfCompileUnit final : public DwarfUnit {
DIE *constructImportedEntityDIE(const DIImportedEntity *Module);

void finishSubprogramDefinition(const DISubprogram *SP);
void finishVariableDefinition(const DbgVariable &Var);
void finishEntityDefinition(const DbgEntity *Entity);

/// Find abstract variable associated with Var.
using InlinedVariable = DbgValueHistoryMap::InlinedVariable;
DbgVariable *getExistingAbstractVariable(InlinedVariable IV,
const DILocalVariable *&Cleansed);
DbgVariable *getExistingAbstractVariable(InlinedVariable IV);
void createAbstractVariable(const DILocalVariable *Var, LexicalScope *Scope);
DbgEntity *getExistingAbstractEntity(const DINode *Node);
void createAbstractEntity(const DINode *Node, LexicalScope *Scope);

/// Set the skeleton unit associated with this unit.
void setSkeleton(DwarfCompileUnit &Skel) { Skeleton = &Skel; }
Expand Down Expand Up @@ -288,6 +289,8 @@ class DwarfCompileUnit final : public DwarfUnit {
void applySubprogramAttributesToDefinition(const DISubprogram *SP,
DIE &SPDie);

void applyLabelAttributes(const DbgLabel &Label, DIE &LabelDie);

/// getRangeLists - Get the vector of range lists.
const SmallVectorImpl<RangeSpanList> &getRangeLists() const {
return (Skeleton ? Skeleton : this)->CURangeLists;
Expand Down
135 changes: 90 additions & 45 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,12 @@ bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI,
}

bool DbgVariable::isBlockByrefVariable() const {
assert(Var && "Invalid complex DbgVariable!");
return Var->getType().resolve()->isBlockByrefStruct();
assert(getVariable() && "Invalid complex DbgVariable!");
return getVariable()->getType().resolve()->isBlockByrefStruct();
}

const DIType *DbgVariable::getType() const {
DIType *Ty = Var->getType().resolve();
DIType *Ty = getVariable()->getType().resolve();
// FIXME: isBlockByrefVariable should be reformulated in terms of complex
// addresses instead.
if (Ty->isBlockByrefStruct()) {
Expand Down Expand Up @@ -253,8 +253,8 @@ ArrayRef<DbgVariable::FrameIndexExpr> DbgVariable::getFrameIndexExprs() const {
void DbgVariable::addMMIEntry(const DbgVariable &V) {
assert(DebugLocListIndex == ~0U && !MInsn && "not an MMI entry");
assert(V.DebugLocListIndex == ~0U && !V.MInsn && "not an MMI entry");
assert(V.Var == Var && "conflicting variable");
assert(V.IA == IA && "conflicting inlined-at location");
assert(V.getVariable() == getVariable() && "conflicting variable");
assert(V.getInlinedAt() == getInlinedAt() && "conflicting inlined-at location");

assert(!FrameIndexExprs.empty() && "Expected an MMI entry");
assert(!V.FrameIndexExprs.empty() && "Expected an MMI entry");
Expand Down Expand Up @@ -727,16 +727,16 @@ void DwarfDebug::beginModule() {
}
}

void DwarfDebug::finishVariableDefinitions() {
for (const auto &Var : ConcreteVariables) {
DIE *VariableDie = Var->getDIE();
assert(VariableDie);
void DwarfDebug::finishEntityDefinitions() {
for (const auto &Entity : ConcreteEntities) {
DIE *Die = Entity->getDIE();
assert(Die);
// FIXME: Consider the time-space tradeoff of just storing the unit pointer
// in the ConcreteVariables list, rather than looking it up again here.
// in the ConcreteEntities list, rather than looking it up again here.
// DIE::getUnit isn't simple - it walks parent pointers, etc.
DwarfCompileUnit *Unit = CUDieMap.lookup(VariableDie->getUnitDie());
DwarfCompileUnit *Unit = CUDieMap.lookup(Die->getUnitDie());
assert(Unit);
Unit->finishVariableDefinition(*Var);
Unit->finishEntityDefinition(Entity.get());
}
}

Expand All @@ -754,7 +754,7 @@ void DwarfDebug::finalizeModuleInfo() {

finishSubprogramDefinitions();

finishVariableDefinitions();
finishEntityDefinitions();

// Include the DWO file name in the hash if there's more than one CU.
// This handles ThinLTO's situation where imported CUs may very easily be
Expand Down Expand Up @@ -916,25 +916,24 @@ void DwarfDebug::endModule() {
// FIXME: AbstractVariables.clear();
}

void DwarfDebug::ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable IV,
const MDNode *ScopeNode) {
const DILocalVariable *Cleansed = nullptr;
if (CU.getExistingAbstractVariable(IV, Cleansed))
void DwarfDebug::ensureAbstractEntityIsCreated(DwarfCompileUnit &CU,
const DINode *Node,
const MDNode *ScopeNode) {
if (CU.getExistingAbstractEntity(Node))
return;

CU.createAbstractVariable(Cleansed, LScopes.getOrCreateAbstractScope(
CU.createAbstractEntity(Node, LScopes.getOrCreateAbstractScope(
cast<DILocalScope>(ScopeNode)));
}

void DwarfDebug::ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU,
InlinedVariable IV, const MDNode *ScopeNode) {
const DILocalVariable *Cleansed = nullptr;
if (CU.getExistingAbstractVariable(IV, Cleansed))
void DwarfDebug::ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
const DINode *Node, const MDNode *ScopeNode) {
if (CU.getExistingAbstractEntity(Node))
return;

if (LexicalScope *Scope =
LScopes.findAbstractScope(cast_or_null<DILocalScope>(ScopeNode)))
CU.createAbstractVariable(Cleansed, Scope);
CU.createAbstractEntity(Node, Scope);
}

// Collect variable information from side table maintained by MF.
Expand All @@ -955,14 +954,14 @@ void DwarfDebug::collectVariableInfoFromMFTable(
if (!Scope)
continue;

ensureAbstractVariableIsCreatedIfScoped(TheCU, Var, Scope->getScopeNode());
ensureAbstractEntityIsCreatedIfScoped(TheCU, Var.first, Scope->getScopeNode());
auto RegVar = llvm::make_unique<DbgVariable>(Var.first, Var.second);
RegVar->initializeMMI(VI.Expr, VI.Slot);
if (DbgVariable *DbgVar = MFVars.lookup(Var))
DbgVar->addMMIEntry(*RegVar);
else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) {
MFVars.insert({Var, RegVar.get()});
ConcreteVariables.push_back(std::move(RegVar));
ConcreteEntities.push_back(std::move(RegVar));
}
}
}
Expand Down Expand Up @@ -1127,14 +1126,26 @@ DwarfDebug::buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
}
}

DbgVariable *DwarfDebug::createConcreteVariable(DwarfCompileUnit &TheCU,
LexicalScope &Scope,
InlinedVariable IV) {
ensureAbstractVariableIsCreatedIfScoped(TheCU, IV, Scope.getScopeNode());
ConcreteVariables.push_back(
llvm::make_unique<DbgVariable>(IV.first, IV.second));
InfoHolder.addScopeVariable(&Scope, ConcreteVariables.back().get());
return ConcreteVariables.back().get();
DbgEntity *DwarfDebug::createConcreteEntity(DwarfCompileUnit &TheCU,
LexicalScope &Scope,
const DINode *Node,
const DILocation *Location,
const MCSymbol *Sym) {
ensureAbstractEntityIsCreatedIfScoped(TheCU, Node, Scope.getScopeNode());
if (isa<const DILocalVariable>(Node)) {
ConcreteEntities.push_back(
llvm::make_unique<DbgVariable>(cast<const DILocalVariable>(Node),
Location));
InfoHolder.addScopeVariable(&Scope,
cast<DbgVariable>(ConcreteEntities.back().get()));
} else if (isa<const DILabel>(Node)) {
ConcreteEntities.push_back(
llvm::make_unique<DbgLabel>(cast<const DILabel>(Node),
Location, Sym));
InfoHolder.addScopeLabel(&Scope,
cast<DbgLabel>(ConcreteEntities.back().get()));
}
return ConcreteEntities.back().get();
}

/// Determine whether a *singular* DBG_VALUE is valid for the entirety of its
Expand Down Expand Up @@ -1196,9 +1207,9 @@ static bool validThroughout(LexicalScopes &LScopes,
}

// Find variables for each lexical scope.
void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU,
const DISubprogram *SP,
DenseSet<InlinedVariable> &Processed) {
void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU,
const DISubprogram *SP,
DenseSet<InlinedVariable> &Processed) {
// Grab the variable info that was squirreled away in the MMI side-table.
collectVariableInfoFromMFTable(TheCU, Processed);

Expand All @@ -1222,7 +1233,8 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU,
continue;

Processed.insert(IV);
DbgVariable *RegVar = createConcreteVariable(TheCU, *Scope, IV);
DbgVariable *RegVar = cast<DbgVariable>(createConcreteEntity(TheCU,
*Scope, IV.first, IV.second));

const MachineInstr *MInsn = Ranges.front().first;
assert(MInsn->isDebugValue() && "History must begin with debug value");
Expand Down Expand Up @@ -1255,13 +1267,44 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU,
Entry.finalize(*Asm, List, BT);
}

// Collect info for variables that were optimized out.
// For each InlinedLabel collected from DBG_LABEL instructions, convert to
// DWARF-related DbgLabel.
for (const auto &I : DbgLabels) {
InlinedLabel IL = I.first;
const MachineInstr *MI = I.second;
if (MI == nullptr)
continue;

LexicalScope *Scope = nullptr;
// Get inlined DILocation if it is inlined label.
if (const DILocation *IA = IL.second)
Scope = LScopes.findInlinedScope(IL.first->getScope(), IA);
else
Scope = LScopes.findLexicalScope(IL.first->getScope());
// If label scope is not found then skip this label.
if (!Scope)
continue;

/// At this point, the temporary label is created.
/// Save the temporary label to DbgLabel entity to get the
/// actually address when generating Dwarf DIE.
MCSymbol *Sym = getLabelBeforeInsn(MI);
createConcreteEntity(TheCU, *Scope, IL.first, IL.second, Sym);
}

// Collect info for variables/labels that were optimized out.
for (const DINode *DN : SP->getRetainedNodes()) {
LexicalScope *Scope = nullptr;
if (auto *DV = dyn_cast<DILocalVariable>(DN)) {
if (Processed.insert(InlinedVariable(DV, nullptr)).second)
if (LexicalScope *Scope = LScopes.findLexicalScope(DV->getScope()))
createConcreteVariable(TheCU, *Scope, InlinedVariable(DV, nullptr));
if (!Processed.insert(InlinedVariable(DV, nullptr)).second)
continue;
Scope = LScopes.findLexicalScope(DV->getScope());
} else if (auto *DL = dyn_cast<DILabel>(DN)) {
Scope = LScopes.findLexicalScope(DL->getScope());
}

if (Scope)
createConcreteEntity(TheCU, *Scope, DN, nullptr);
}
}

Expand Down Expand Up @@ -1424,7 +1467,7 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
}

DenseSet<InlinedVariable> ProcessedVars;
collectVariableInfo(TheCU, SP, ProcessedVars);
collectEntityInfo(TheCU, SP, ProcessedVars);

// Add the range of this function to the list of ranges for the CU.
TheCU.addRange(RangeSpan(Asm->getFunctionBegin(), Asm->getFunctionEnd()));
Expand Down Expand Up @@ -1452,10 +1495,11 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
// Collect info for variables that were optimized out.
if (!ProcessedVars.insert(InlinedVariable(DV, nullptr)).second)
continue;
ensureAbstractVariableIsCreated(TheCU, InlinedVariable(DV, nullptr),
DV->getScope());
ensureAbstractEntityIsCreated(TheCU, DV, DV->getScope());
assert(LScopes.getAbstractScopesList().size() == NumAbstractScopes
&& "ensureAbstractVariableIsCreated inserted abstract scopes");
&& "ensureAbstractEntityIsCreated inserted abstract scopes");
} else if (auto *DL = dyn_cast<DILabel>(DN)) {
ensureAbstractEntityIsCreated(TheCU, DL, DL->getScope());
}
}
constructAbstractSubprogramScopeDIE(TheCU, AScope);
Expand All @@ -1473,6 +1517,7 @@ void DwarfDebug::endFunctionImpl(const MachineFunction *MF) {
// DbgVariables except those that are also in AbstractVariables (since they
// can be used cross-function)
InfoHolder.getScopeVariables().clear();
InfoHolder.getScopeLabels().clear();
PrevLabel = nullptr;
CurFn = nullptr;
}
Expand Down
137 changes: 110 additions & 27 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARFDEBUG_H

#include "AddressPool.h"
#include "DbgValueHistoryCalculator.h"
#include "DbgEntityHistoryCalculator.h"
#include "DebugHandlerBase.h"
#include "DebugLocStream.h"
#include "DwarfFile.h"
Expand Down Expand Up @@ -61,6 +61,47 @@ class MCSymbol;
class MDNode;
class Module;

//===----------------------------------------------------------------------===//
/// This class is defined as the common parent of DbgVariable and DbgLabel
/// such that it could levarage polymorphism to extract common code for
/// DbgVariable and DbgLabel.
class DbgEntity {
const DINode *Entity;
const DILocation *InlinedAt;
DIE *TheDIE = nullptr;
unsigned SubclassID;

public:
enum DbgEntityKind {
DbgVariableKind,
DbgLabelKind
};

DbgEntity(const DINode *N, const DILocation *IA, unsigned ID)
: Entity(N), InlinedAt(IA), SubclassID(ID) {}
virtual ~DbgEntity() {}

/// Accessors.
/// @{
const DINode *getEntity() const { return Entity; }
const DILocation *getInlinedAt() const { return InlinedAt; }
DIE *getDIE() const { return TheDIE; }
unsigned getDbgEntityID() const { return SubclassID; }
/// @}

void setDIE(DIE &D) { TheDIE = &D; }

static bool classof(const DbgEntity *N) {
switch (N->getDbgEntityID()) {
default:
return false;
case DbgVariableKind:
case DbgLabelKind:
return true;
}
}
};

//===----------------------------------------------------------------------===//
/// This class is used to track local variable information.
///
Expand All @@ -73,10 +114,7 @@ class Module;
/// single instruction use \a MInsn and (optionally) a single entry of \a Expr.
///
/// Variables that have been optimized out use none of these fields.
class DbgVariable {
const DILocalVariable *Var; /// Variable Descriptor.
const DILocation *IA; /// Inlined at location.
DIE *TheDIE = nullptr; /// Variable DIE.
class DbgVariable : public DbgEntity {
unsigned DebugLocListIndex = ~0u; /// Offset in DebugLocs.
const MachineInstr *MInsn = nullptr; /// DBG_VALUE instruction.

Expand All @@ -93,7 +131,7 @@ class DbgVariable {
/// Creates a variable without any DW_AT_location. Call \a initializeMMI()
/// for MMI entries, or \a initializeDbgValue() for DBG_VALUE instructions.
DbgVariable(const DILocalVariable *V, const DILocation *IA)
: Var(V), IA(IA) {}
: DbgEntity(V, IA, DbgVariableKind) {}

/// Initialize from the MMI table.
void initializeMMI(const DIExpression *E, int FI) {
Expand All @@ -111,8 +149,9 @@ class DbgVariable {
assert(FrameIndexExprs.empty() && "Already initialized?");
assert(!MInsn && "Already initialized?");

assert(Var == DbgValue->getDebugVariable() && "Wrong variable");
assert(IA == DbgValue->getDebugLoc()->getInlinedAt() && "Wrong inlined-at");
assert(getVariable() == DbgValue->getDebugVariable() && "Wrong variable");
assert(getInlinedAt() == DbgValue->getDebugLoc()->getInlinedAt() &&
"Wrong inlined-at");

MInsn = DbgValue;
if (auto *E = DbgValue->getDebugExpression())
Expand All @@ -121,19 +160,18 @@ class DbgVariable {
}

// Accessors.
const DILocalVariable *getVariable() const { return Var; }
const DILocation *getInlinedAt() const { return IA; }
const DILocalVariable *getVariable() const {
return cast<DILocalVariable>(getEntity());
}

const DIExpression *getSingleExpression() const {
assert(MInsn && FrameIndexExprs.size() <= 1);
return FrameIndexExprs.size() ? FrameIndexExprs[0].Expr : nullptr;
}

void setDIE(DIE &D) { TheDIE = &D; }
DIE *getDIE() const { return TheDIE; }
void setDebugLocListIndex(unsigned O) { DebugLocListIndex = O; }
unsigned getDebugLocListIndex() const { return DebugLocListIndex; }
StringRef getName() const { return Var->getName(); }
StringRef getName() const { return getVariable()->getName(); }
const MachineInstr *getMInsn() const { return MInsn; }
/// Get the FI entries, sorted by fragment offset.
ArrayRef<FrameIndexExpr> getFrameIndexExprs() const;
Expand All @@ -143,23 +181,23 @@ class DbgVariable {
// Translate tag to proper Dwarf tag.
dwarf::Tag getTag() const {
// FIXME: Why don't we just infer this tag and store it all along?
if (Var->isParameter())
if (getVariable()->isParameter())
return dwarf::DW_TAG_formal_parameter;

return dwarf::DW_TAG_variable;
}

/// Return true if DbgVariable is artificial.
bool isArtificial() const {
if (Var->isArtificial())
if (getVariable()->isArtificial())
return true;
if (getType()->isArtificial())
return true;
return false;
}

bool isObjectPointer() const {
if (Var->isObjectPointer())
if (getVariable()->isObjectPointer())
return true;
if (getType()->isObjectPointer())
return true;
Expand All @@ -178,6 +216,45 @@ class DbgVariable {
bool isBlockByrefVariable() const;
const DIType *getType() const;

static bool classof(const DbgEntity *N) {
return N->getDbgEntityID() == DbgVariableKind;
}

private:
template <typename T> T *resolve(TypedDINodeRef<T> Ref) const {
return Ref.resolve();
}
};

//===----------------------------------------------------------------------===//
/// This class is used to track label information.
///
/// Labels are collected from \c DBG_LABEL instructions.
class DbgLabel : public DbgEntity {
const MCSymbol *Sym; /// Symbol before DBG_LABEL instruction.

public:
/// We need MCSymbol information to generate DW_AT_low_pc.
DbgLabel(const DILabel *L, const DILocation *IA, const MCSymbol *Sym = nullptr)
: DbgEntity(L, IA, DbgLabelKind), Sym(Sym) {}

/// Accessors.
/// @{
const DILabel *getLabel() const { return cast<DILabel>(getEntity()); }
const MCSymbol *getSymbol() const { return Sym; }

StringRef getName() const { return getLabel()->getName(); }
/// @}

/// Translate tag to proper Dwarf tag.
dwarf::Tag getTag() const {
return dwarf::DW_TAG_label;
}

static bool classof(const DbgEntity *N) {
return N->getDbgEntityID() == DbgLabelKind;
}

private:
template <typename T> T *resolve(TypedDINodeRef<T> Ref) const {
return Ref.resolve();
Expand Down Expand Up @@ -217,8 +294,8 @@ class DwarfDebug : public DebugHandlerBase {
/// Size of each symbol emitted (for those symbols that have a specific size).
DenseMap<const MCSymbol *, uint64_t> SymSize;

/// Collection of abstract variables.
SmallVector<std::unique_ptr<DbgVariable>, 64> ConcreteVariables;
/// Collection of abstract variables/labels.
SmallVector<std::unique_ptr<DbgEntity>, 64> ConcreteEntities;

/// Collection of DebugLocEntry. Stored in a linked list so that DIELocLists
/// can refer to them in spite of insertions into this list.
Expand Down Expand Up @@ -330,14 +407,20 @@ class DwarfDebug : public DebugHandlerBase {
}

using InlinedVariable = DbgValueHistoryMap::InlinedVariable;
using InlinedLabel = DbgLabelInstrMap::InlinedLabel;

void ensureAbstractVariableIsCreated(DwarfCompileUnit &CU, InlinedVariable IV,
const MDNode *Scope);
void ensureAbstractVariableIsCreatedIfScoped(DwarfCompileUnit &CU, InlinedVariable IV,
const MDNode *Scope);
void ensureAbstractEntityIsCreated(DwarfCompileUnit &CU,
const DINode *Node,
const MDNode *Scope);
void ensureAbstractEntityIsCreatedIfScoped(DwarfCompileUnit &CU,
const DINode *Node,
const MDNode *Scope);

DbgVariable *createConcreteVariable(DwarfCompileUnit &TheCU,
LexicalScope &Scope, InlinedVariable IV);
DbgEntity *createConcreteEntity(DwarfCompileUnit &TheCU,
LexicalScope &Scope,
const DINode *Node,
const DILocation *Location,
const MCSymbol *Sym = nullptr);

/// Construct a DIE for this abstract scope.
void constructAbstractSubprogramScopeDIE(DwarfCompileUnit &SrcCU, LexicalScope *Scope);
Expand All @@ -346,7 +429,7 @@ class DwarfDebug : public DebugHandlerBase {
void addAccelNameImpl(const DICompileUnit &CU, AccelTable<DataT> &AppleAccel,
StringRef Name, const DIE &Die);

void finishVariableDefinitions();
void finishEntityDefinitions();

void finishSubprogramDefinitions();

Expand Down Expand Up @@ -466,8 +549,8 @@ class DwarfDebug : public DebugHandlerBase {
unsigned Flags);

/// Populate LexicalScope entries with variables' info.
void collectVariableInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP,
DenseSet<InlinedVariable> &ProcessedVars);
void collectEntityInfo(DwarfCompileUnit &TheCU, const DISubprogram *SP,
DenseSet<InlinedVariable> &ProcessedVars);

/// Build the location list for all DBG_VALUEs in the
/// function that describe the same variable.
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,8 @@ bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) {
}
return true;
}

void DwarfFile::addScopeLabel(LexicalScope *LS, DbgLabel *Label) {
SmallVectorImpl<DbgLabel *> &Labels = ScopeLabels[LS];
Labels.push_back(Label);
}
18 changes: 15 additions & 3 deletions llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
namespace llvm {

class AsmPrinter;
class DbgEntity;
class DbgVariable;
class DbgLabel;
class DwarfCompileUnit;
class DwarfUnit;
class LexicalScope;
Expand Down Expand Up @@ -62,9 +64,13 @@ class DwarfFile {
/// Collection of DbgVariables of each lexical scope.
DenseMap<LexicalScope *, ScopeVars> ScopeVariables;

/// Collection of DbgLabels of each lexical scope.
using LabelList = SmallVector<DbgLabel *, 4>;
DenseMap<LexicalScope *, LabelList> ScopeLabels;

// Collection of abstract subprogram DIEs.
DenseMap<const MDNode *, DIE *> AbstractSPDies;
DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> AbstractVariables;
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> AbstractEntities;

/// 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
Expand Down Expand Up @@ -122,16 +128,22 @@ class DwarfFile {
/// \returns false if the variable was merged with a previous one.
bool addScopeVariable(LexicalScope *LS, DbgVariable *Var);

void addScopeLabel(LexicalScope *LS, DbgLabel *Label);

DenseMap<LexicalScope *, ScopeVars> &getScopeVariables() {
return ScopeVariables;
}

DenseMap<LexicalScope *, LabelList> &getScopeLabels() {
return ScopeLabels;
}

DenseMap<const MDNode *, DIE *> &getAbstractSPDies() {
return AbstractSPDies;
}

DenseMap<const MDNode *, std::unique_ptr<DbgVariable>> &getAbstractVariables() {
return AbstractVariables;
DenseMap<const DINode *, std::unique_ptr<DbgEntity>> &getAbstractEntities() {
return AbstractEntities;
}

void insertDIE(const MDNode *TypeMD, DIE *Die) {
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ void DwarfUnit::addSourceLine(DIE &Die, const DISubprogram *SP) {
addSourceLine(Die, SP->getLine(), SP->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DILabel *L) {
assert(L);

addSourceLine(Die, L->getLine(), L->getFile());
}

void DwarfUnit::addSourceLine(DIE &Die, const DIType *Ty) {
assert(Ty);

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ class DwarfUnit : public DIEUnit {
void addSourceLine(DIE &Die, const DILocalVariable *V);
void addSourceLine(DIE &Die, const DIGlobalVariable *G);
void addSourceLine(DIE &Die, const DISubprogram *SP);
void addSourceLine(DIE &Die, const DILabel *L);
void addSourceLine(DIE &Die, const DIType *Ty);
void addSourceLine(DIE &Die, const DIObjCProperty *Ty);

Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,17 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
DI.getVariable(), DI.getExpression());
return true;
}
case Intrinsic::dbg_label: {
const DbgLabelInst &DI = cast<DbgLabelInst>(CI);
assert(DI.getLabel() && "Missing label");

assert(DI.getLabel()->isValidLocationForIntrinsic(
MIRBuilder.getDebugLoc()) &&
"Expected inlined-at fields to agree");

MIRBuilder.buildDbgLabel(DI.getLabel());
return true;
}
case Intrinsic::vaend:
// No target I know of cares about va_end. Certainly no in-tree target
// does. Simplest intrinsic ever!
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ MachineInstrBuilder MachineIRBuilderBase::buildConstDbgValue(
return MIB.addImm(0).addMetadata(Variable).addMetadata(Expr);
}

MachineInstrBuilder MachineIRBuilderBase::buildDbgLabel(const MDNode *Label) {
assert(isa<DILabel>(Label) && "not a label");
assert(cast<DILabel>(Label)->isValidLocationForIntrinsic(State.DL) &&
"Expected inlined-at fields to agree");
auto MIB = buildInstr(TargetOpcode::DBG_LABEL);

return MIB.addMetadata(Label);
}

MachineInstrBuilder MachineIRBuilderBase::buildFrameIndex(unsigned Res,
int Idx) {
assert(getMRI()->getType(Res).isPointer() && "invalid operand type");
Expand Down
50 changes: 50 additions & 0 deletions llvm/test/DebugInfo/Generic/debug-label-inline.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
; RUN: llc -O2 -filetype=obj -o - %s | llvm-dwarfdump -v - | FileCheck %s
;
; CHECK: .debug_info contents:
; CHECK: [[LABEL_ORIGIN:0x[0-9a-zA-Z]+]]:{{ *}}DW_TAG_label
; CHECK-NEXT: DW_AT_name [DW_FORM_strp] {{.*}}"top"
; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label-inline.c
; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}8
; CHECK: DW_TAG_label
; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] {{.*}}{[[LABEL_ORIGIN]]} "top"
; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}}

source_filename = "debug-label-inline.c"

@ga = external local_unnamed_addr global i32, align 4
@gb = external local_unnamed_addr global i32, align 4

define i32 @f2() local_unnamed_addr #0 !dbg !4 {
entry:
%0 = load i32, i32* @ga, align 4, !dbg !1
%1 = load i32, i32* @gb, align 4, !dbg !1
call void @llvm.dbg.label(metadata !15), !dbg !17
%add.i = add nsw i32 %1, %0, !dbg !18
ret i32 %add.i, !dbg !1
}

declare void @llvm.dbg.label(metadata)
declare void @llvm.dbg.value(metadata, metadata, metadata)

attributes #0 = { nounwind readonly }

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !6, isOptimized: true, emissionKind: FullDebug, enums: !2)
!1 = !DILocation(line: 18, scope: !4)
!2 = !{}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!4 = distinct !DISubprogram(name: "f2", scope: !6, file: !6, line: 15, type: !7, isLocal: false, isDefinition: true, scopeLine: 15, isOptimized: true, unit: !0, retainedNodes: !2)
!6 = !DIFile(filename: "debug-label-inline.c", directory: "./")
!7 = !DISubroutineType(types: !8)
!8 = !{!10}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = distinct !DISubprogram(name: "f1", scope: !6, file: !6, line: 5, type: !12, isLocal: false, isDefinition: true, scopeLine: 5, isOptimized: true, unit: !0, retainedNodes: !14)
!12 = !DISubroutineType(types: !13)
!13 = !{!10, !10, !10}
!14 = !{!15}
!15 = !DILabel(scope: !11, name: "top", file: !6, line: 8)
!16 = distinct !DILocation(line: 18, scope: !4)
!17 = !DILocation(line: 8, scope: !11, inlinedAt: !16)
!18 = !DILocation(line: 9, scope: !11, inlinedAt: !16)
73 changes: 73 additions & 0 deletions llvm/test/DebugInfo/Generic/debug-label.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
; RUN: llc -fast-isel=false -O0 -filetype=obj -o - %s | llvm-dwarfdump -v - | FileCheck %s
;
; CHECK: .debug_info contents:
; CHECK: DW_TAG_label
; CHECK-NEXT: DW_AT_name [DW_FORM_strp] {{.*}}"top"
; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label.c
; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}4
; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}}
; CHECK: DW_TAG_label
; CHECK-NEXT: DW_AT_name [DW_FORM_strp] {{.*}}"done"
; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] {{.*}}debug-label.c
; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] {{.*}}7
; CHECK-NEXT: DW_AT_low_pc [DW_FORM_addr] {{.*}}{{0x[0-9a-f]+}}
;
; RUN: llc -fast-isel=false -O0 -o - %s | FileCheck %s -check-prefix=ASM
;
; ASM: [[TOP_LOW_PC:[.0-9a-zA-Z]+]]:{{[[:space:]].*}}DEBUG_LABEL: foo:top
; ASM: [[DONE_LOW_PC:[.0-9a-zA-Z]+]]:{{[[:space:]].*}}DEBUG_LABEL: foo:done
; ASM-LABEL: debug_info
; ASM: DW_TAG_label
; ASM-NEXT: DW_AT_name
; ASM-NEXT: 1 {{.*}} DW_AT_decl_file
; ASM-NEXT: 4 {{.*}} DW_AT_decl_line
; ASM-NEXT: [[TOP_LOW_PC]] {{.*}} DW_AT_low_pc
; ASM: DW_TAG_label
; ASM-NEXT: DW_AT_name
; ASM-NEXT: 1 {{.*}} DW_AT_decl_file
; ASM-NEXT: 7 {{.*}} DW_AT_decl_line
; ASM-NEXT: [[DONE_LOW_PC]] {{.*}} DW_AT_low_pc

source_filename = "debug-label.c"

define dso_local i32 @foo(i32 %a, i32 %b) !dbg !6 {
entry:
%a.addr = alloca i32, align 4
%b.addr = alloca i32, align 4
%sum = alloca i32, align 4
store i32 %a, i32* %a.addr, align 4
store i32 %b, i32* %b.addr, align 4
br label %top

top:
call void @llvm.dbg.label(metadata !10), !dbg !11
%0 = load i32, i32* %a.addr, align 4
%1 = load i32, i32* %b.addr, align 4
%add = add nsw i32 %0, %1
store i32 %add, i32* %sum, align 4
br label %done

done:
call void @llvm.dbg.label(metadata !12), !dbg !13
%2 = load i32, i32* %sum, align 4
ret i32 %2, !dbg !14
}

declare void @llvm.dbg.label(metadata)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!4}

!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "debug-label.c", directory: "./")
!2 = !{}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!6 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !7, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2)
!7 = !DISubroutineType(types: !8)
!8 = !{!9, !9, !9}
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!10 = !DILabel(scope: !6, name: "top", file: !1, line: 4)
!11 = !DILocation(line: 4, column: 1, scope: !6)
!12 = !DILabel(scope: !6, name: "done", file: !1, line: 7)
!13 = !DILocation(line: 7, column: 1, scope: !6)
!14 = !DILocation(line: 8, column: 3, scope: !6)