Skip to content

Commit a344c90

Browse files
committed
[DebugInfo] Add support for variadic DBG_INSTR_REFs in LiveDebugValues
Following support from the previous patches in this stack being added for variadic DBG_INSTR_REFs to exist, this patch modifies LiveDebugValues to handle those instructions. Support already exists for DBG_VALUE_LISTs, which covers most of the work needed to handle these instructions; this patch only modifies the transferDebugInstrRef function to correctly track them. Reviewed By: jmorse Differential Revision: https://reviews.llvm.org/D133927
1 parent 9e1a344 commit a344c90

File tree

8 files changed

+581
-86
lines changed

8 files changed

+581
-86
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,6 +2805,13 @@ class DIExpression : public MDNode {
28052805
static const DIExpression *
28062806
convertToVariadicExpression(const DIExpression *Expr);
28072807

2808+
/// If \p Expr is a valid single-location expression, i.e. it refers to only a
2809+
/// single debug operand at the start of the expression, then return that
2810+
/// expression in a non-variadic form by removing DW_OP_LLVM_arg from the
2811+
/// expression if it is present; otherwise returns std::nullopt.
2812+
static std::optional<const DIExpression *>
2813+
convertToNonVariadicExpression(const DIExpression *Expr);
2814+
28082815
/// Inserts the elements of \p Expr into \p Ops modified to a canonical form,
28092816
/// which uses DW_OP_LLVM_arg (i.e. is a variadic expression) and folds the
28102817
/// implied derefence from the \p IsIndirect flag into the expression. This

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,12 +1132,11 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
11321132
OS << " <- ";
11331133

11341134
const DIExpression *Expr = MI->getDebugExpression();
1135-
if (Expr->getNumElements() && Expr->isSingleLocationExpression() &&
1136-
Expr->expr_op_begin()->getOp() == dwarf::DW_OP_LLVM_arg) {
1137-
SmallVector<uint64_t> Ops(
1138-
make_range(Expr->elements_begin() + 2, Expr->elements_end()));
1139-
Expr = DIExpression::get(Expr->getContext(), Ops);
1140-
}
1135+
// First convert this to a non-variadic expression if possible, to simplify
1136+
// the output.
1137+
if (auto NonVariadicExpr = DIExpression::convertToNonVariadicExpression(Expr))
1138+
Expr = *NonVariadicExpr;
1139+
// Then, output the possibly-simplified expression.
11411140
if (Expr->getNumElements()) {
11421141
OS << '[';
11431142
ListSeparator LS;

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp

Lines changed: 143 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -630,12 +630,21 @@ class TransferTracker {
630630
if (!ShouldEmitDebugEntryValues)
631631
return false;
632632

633+
const DIExpression *DIExpr = Prop.DIExpr;
634+
633635
// We don't currently emit entry values for DBG_VALUE_LISTs.
634-
if (Prop.IsVariadic)
635-
return false;
636+
if (Prop.IsVariadic) {
637+
// If this debug value can be converted to be non-variadic, then do so;
638+
// otherwise give up.
639+
auto NonVariadicExpression =
640+
DIExpression::convertToNonVariadicExpression(DIExpr);
641+
if (!NonVariadicExpression)
642+
return false;
643+
DIExpr = *NonVariadicExpression;
644+
}
636645

637646
// Is the variable appropriate for entry values (i.e., is a parameter).
638-
if (!isEntryValueVariable(Var, Prop.DIExpr))
647+
if (!isEntryValueVariable(Var, DIExpr))
639648
return false;
640649

641650
// Is the value assigned to this variable still the entry value?
@@ -644,12 +653,12 @@ class TransferTracker {
644653

645654
// Emit a variable location using an entry value expression.
646655
DIExpression *NewExpr =
647-
DIExpression::prepend(Prop.DIExpr, DIExpression::EntryValue);
656+
DIExpression::prepend(DIExpr, DIExpression::EntryValue);
648657
Register Reg = MTracker->LocIdxToLocID[Num.getLoc()];
649658
MachineOperand MO = MachineOperand::CreateReg(Reg, false);
650659

651660
PendingDbgValues.push_back(
652-
emitMOLoc(MO, Var, {NewExpr, Prop.Indirect, Prop.IsVariadic}));
661+
emitMOLoc(MO, Var, {NewExpr, Prop.Indirect, false}));
653662
return true;
654663
}
655664

@@ -809,8 +818,8 @@ class TransferTracker {
809818
for (const auto &Var : ActiveMLocIt->second) {
810819
auto ActiveVLocIt = ActiveVLocs.find(Var);
811820
// Re-state the variable location: if there's no replacement then NewLoc
812-
// is None and a $noreg DBG_VALUE will be created. Otherwise, a DBG_VALUE
813-
// identifying the alternative location will be emitted.
821+
// is std::nullopt and a $noreg DBG_VALUE will be created. Otherwise, a
822+
// DBG_VALUE identifying the alternative location will be emitted.
814823
const DbgValueProperties &Properties = ActiveVLocIt->second.Properties;
815824

816825
// Produce the new list of debug ops - an empty list if no new location
@@ -1418,39 +1427,14 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) {
14181427
return true;
14191428
}
14201429

1421-
bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
1422-
const ValueTable *MLiveOuts,
1423-
const ValueTable *MLiveIns) {
1424-
if (!MI.isDebugRef())
1425-
return false;
1426-
1427-
// Only handle this instruction when we are building the variable value
1428-
// transfer function.
1429-
if (!VTracker && !TTracker)
1430-
return false;
1431-
1432-
unsigned InstNo = MI.getDebugOperand(0).getInstrRefInstrIndex();
1433-
unsigned OpNo = MI.getDebugOperand(0).getInstrRefOpIndex();
1434-
1435-
const DILocalVariable *Var = MI.getDebugVariable();
1436-
const DIExpression *Expr = MI.getDebugExpression();
1437-
const DILocation *DebugLoc = MI.getDebugLoc();
1438-
const DILocation *InlinedAt = DebugLoc->getInlinedAt();
1439-
assert(Var->isValidLocationForIntrinsic(DebugLoc) &&
1440-
"Expected inlined-at fields to agree");
1441-
1442-
DebugVariable V(Var, Expr, InlinedAt);
1443-
1444-
auto *Scope = LS.findLexicalScope(MI.getDebugLoc().get());
1445-
if (Scope == nullptr)
1446-
return true; // Handled by doing nothing. This variable is never in scope.
1447-
1448-
const MachineFunction &MF = *MI.getParent()->getParent();
1449-
1430+
std::optional<ValueIDNum> InstrRefBasedLDV::getValueForInstrRef(
1431+
unsigned InstNo, unsigned OpNo, MachineInstr &MI,
1432+
const ValueTable *MLiveOuts, const ValueTable *MLiveIns) {
14501433
// Various optimizations may have happened to the value during codegen,
14511434
// recorded in the value substitution table. Apply any substitutions to
14521435
// the instruction / operand number in this DBG_INSTR_REF, and collect
14531436
// any subregister extractions performed during optimization.
1437+
const MachineFunction &MF = *MI.getParent()->getParent();
14541438

14551439
// Create dummy substitution with Src set, for lookup.
14561440
auto SoughtSub =
@@ -1586,14 +1570,64 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
15861570
}
15871571
}
15881572

1589-
// We, we have a value number or std::nullopt. Tell the variable value tracker
1590-
// about it. The rest of this LiveDebugValues implementation acts exactly the
1591-
// same for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values
1592-
// that aren't immediately available).
1593-
DbgValueProperties Properties(Expr, false, true);
1573+
return NewID;
1574+
}
1575+
1576+
bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
1577+
const ValueTable *MLiveOuts,
1578+
const ValueTable *MLiveIns) {
1579+
if (!MI.isDebugRef())
1580+
return false;
1581+
1582+
// Only handle this instruction when we are building the variable value
1583+
// transfer function.
1584+
if (!VTracker && !TTracker)
1585+
return false;
1586+
1587+
const DILocalVariable *Var = MI.getDebugVariable();
1588+
const DIExpression *Expr = MI.getDebugExpression();
1589+
const DILocation *DebugLoc = MI.getDebugLoc();
1590+
const DILocation *InlinedAt = DebugLoc->getInlinedAt();
1591+
assert(Var->isValidLocationForIntrinsic(DebugLoc) &&
1592+
"Expected inlined-at fields to agree");
1593+
1594+
DebugVariable V(Var, Expr, InlinedAt);
1595+
1596+
auto *Scope = LS.findLexicalScope(MI.getDebugLoc().get());
1597+
if (Scope == nullptr)
1598+
return true; // Handled by doing nothing. This variable is never in scope.
1599+
15941600
SmallVector<DbgOpID> DbgOpIDs;
1595-
if (NewID)
1596-
DbgOpIDs.push_back(DbgOpStore.insert(*NewID));
1601+
for (const MachineOperand &MO : MI.debug_operands()) {
1602+
if (!MO.isDbgInstrRef()) {
1603+
assert(!MO.isReg() && "DBG_INSTR_REF should not contain registers");
1604+
DbgOpID ConstOpID = DbgOpStore.insert(DbgOp(MO));
1605+
DbgOpIDs.push_back(ConstOpID);
1606+
continue;
1607+
}
1608+
1609+
unsigned InstNo = MO.getInstrRefInstrIndex();
1610+
unsigned OpNo = MO.getInstrRefOpIndex();
1611+
1612+
// Default machine value number is <None> -- if no instruction defines
1613+
// the corresponding value, it must have been optimized out.
1614+
std::optional<ValueIDNum> NewID =
1615+
getValueForInstrRef(InstNo, OpNo, MI, MLiveOuts, MLiveIns);
1616+
// We have a value number or std::nullopt. If the latter, then kill the
1617+
// entire debug value.
1618+
if (NewID) {
1619+
DbgOpIDs.push_back(DbgOpStore.insert(*NewID));
1620+
} else {
1621+
DbgOpIDs.clear();
1622+
break;
1623+
}
1624+
}
1625+
1626+
// We have a DbgOpID for every value or for none. Tell the variable value
1627+
// tracker about it. The rest of this LiveDebugValues implementation acts
1628+
// exactly the same for DBG_INSTR_REFs as DBG_VALUEs (just, the former can
1629+
// refer to values that aren't immediately available).
1630+
DbgValueProperties Properties(Expr, false, true);
15971631
if (VTracker)
15981632
VTracker->defVar(MI, Properties, DbgOpIDs);
15991633

@@ -1602,40 +1636,84 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
16021636
if (!TTracker)
16031637
return true;
16041638

1639+
// Fetch the concrete DbgOps now, as we will need them later.
1640+
SmallVector<DbgOp> DbgOps;
1641+
for (DbgOpID OpID : DbgOpIDs) {
1642+
DbgOps.push_back(DbgOpStore.find(OpID));
1643+
}
1644+
16051645
// Pick a location for the machine value number, if such a location exists.
16061646
// (This information could be stored in TransferTracker to make it faster).
1607-
TransferTracker::LocationAndQuality FoundLoc;
1647+
SmallDenseMap<ValueIDNum, TransferTracker::LocationAndQuality> FoundLocs;
1648+
SmallVector<ValueIDNum> ValuesToFind;
1649+
// Initialized the preferred-location map with illegal locations, to be
1650+
// filled in later.
1651+
for (const DbgOp &Op : DbgOps) {
1652+
if (!Op.IsConst)
1653+
if (FoundLocs.insert({Op.ID, TransferTracker::LocationAndQuality()})
1654+
.second)
1655+
ValuesToFind.push_back(Op.ID);
1656+
}
1657+
16081658
for (auto Location : MTracker->locations()) {
16091659
LocIdx CurL = Location.Idx;
16101660
ValueIDNum ID = MTracker->readMLoc(CurL);
1611-
if (NewID && ID == NewID) {
1612-
// If this is the first location with that value, pick it. Otherwise,
1613-
// consider whether it's a "longer term" location.
1614-
std::optional<TransferTracker::LocationQuality> ReplacementQuality =
1615-
TTracker->getLocQualityIfBetter(CurL, FoundLoc.getQuality());
1616-
if (ReplacementQuality) {
1617-
FoundLoc =
1618-
TransferTracker::LocationAndQuality(CurL, *ReplacementQuality);
1619-
if (FoundLoc.isBest())
1661+
auto ValueToFindIt = find(ValuesToFind, ID);
1662+
if (ValueToFindIt == ValuesToFind.end())
1663+
continue;
1664+
auto &Previous = FoundLocs.find(ID)->second;
1665+
// If this is the first location with that value, pick it. Otherwise,
1666+
// consider whether it's a "longer term" location.
1667+
std::optional<TransferTracker::LocationQuality> ReplacementQuality =
1668+
TTracker->getLocQualityIfBetter(CurL, Previous.getQuality());
1669+
if (ReplacementQuality) {
1670+
Previous = TransferTracker::LocationAndQuality(CurL, *ReplacementQuality);
1671+
if (Previous.isBest()) {
1672+
ValuesToFind.erase(ValueToFindIt);
1673+
if (ValuesToFind.empty())
16201674
break;
16211675
}
16221676
}
16231677
}
16241678

16251679
SmallVector<ResolvedDbgOp> NewLocs;
1626-
if (!FoundLoc.isIllegal())
1627-
NewLocs.push_back(FoundLoc.getLoc());
1680+
for (const DbgOp &DbgOp : DbgOps) {
1681+
if (DbgOp.IsConst) {
1682+
NewLocs.push_back(DbgOp.MO);
1683+
continue;
1684+
}
1685+
LocIdx FoundLoc = FoundLocs.find(DbgOp.ID)->second.getLoc();
1686+
if (FoundLoc.isIllegal()) {
1687+
NewLocs.clear();
1688+
break;
1689+
}
1690+
NewLocs.push_back(FoundLoc);
1691+
}
16281692
// Tell transfer tracker that the variable value has changed.
16291693
TTracker->redefVar(MI, Properties, NewLocs);
16301694

1631-
// If there was a value with no location; but the value is defined in a
1632-
// later instruction in this block, this is a block-local use-before-def.
1633-
if (FoundLoc.isIllegal() && NewID && NewID->getBlock() == CurBB &&
1634-
NewID->getInst() > CurInst) {
1635-
SmallVector<DbgOp> UseBeforeDefLocs;
1636-
UseBeforeDefLocs.push_back(*NewID);
1637-
TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false, true},
1638-
UseBeforeDefLocs, NewID->getInst());
1695+
// If there were values with no location, but all such values are defined in
1696+
// later instructions in this block, this is a block-local use-before-def.
1697+
if (!DbgOps.empty() && NewLocs.empty()) {
1698+
bool IsValidUseBeforeDef = true;
1699+
uint64_t LastUseBeforeDef = 0;
1700+
for (auto ValueLoc : FoundLocs) {
1701+
ValueIDNum NewID = ValueLoc.first;
1702+
LocIdx FoundLoc = ValueLoc.second.getLoc();
1703+
if (!FoundLoc.isIllegal())
1704+
continue;
1705+
// If we have an value with no location that is not defined in this block,
1706+
// then it has no location in this block, leaving this value undefined.
1707+
if (NewID.getBlock() != CurBB || NewID.getInst() <= CurInst) {
1708+
IsValidUseBeforeDef = false;
1709+
break;
1710+
}
1711+
LastUseBeforeDef = std::max(LastUseBeforeDef, NewID.getInst());
1712+
}
1713+
if (IsValidUseBeforeDef) {
1714+
TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false, true},
1715+
DbgOps, LastUseBeforeDef);
1716+
}
16391717
}
16401718

16411719
// Produce a DBG_VALUE representing what this DBG_INSTR_REF meant.
@@ -4004,13 +4082,13 @@ std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(
40044082

40054083
// This function will be called twice per DBG_INSTR_REF, and might end up
40064084
// computing lots of SSA information: memoize it.
4007-
auto SeenDbgPHIIt = SeenDbgPHIs.find(&Here);
4085+
auto SeenDbgPHIIt = SeenDbgPHIs.find(std::make_pair(&Here, InstrNum));
40084086
if (SeenDbgPHIIt != SeenDbgPHIs.end())
40094087
return SeenDbgPHIIt->second;
40104088

40114089
std::optional<ValueIDNum> Result =
40124090
resolveDbgPHIsImpl(MF, MLiveOuts, MLiveIns, Here, InstrNum);
4013-
SeenDbgPHIs.insert({&Here, Result});
4091+
SeenDbgPHIs.insert({std::make_pair(&Here, InstrNum), Result});
40144092
return Result;
40154093
}
40164094

llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,8 @@ class InstrRefBasedLDV : public LDVImpl {
11561156
/// DBG_INSTR_REFs that call resolveDbgPHIs. These variable references solve
11571157
/// a mini SSA problem caused by DBG_PHIs being cloned, this collection caches
11581158
/// the result.
1159-
DenseMap<MachineInstr *, std::optional<ValueIDNum>> SeenDbgPHIs;
1159+
DenseMap<std::pair<MachineInstr *, unsigned>, std::optional<ValueIDNum>>
1160+
SeenDbgPHIs;
11601161

11611162
DbgOpIDMap DbgOpStore;
11621163

@@ -1194,6 +1195,14 @@ class InstrRefBasedLDV : public LDVImpl {
11941195
std::optional<SpillLocationNo>
11951196
extractSpillBaseRegAndOffset(const MachineInstr &MI);
11961197

1198+
/// For an instruction reference given by \p InstNo and \p OpNo in instruction
1199+
/// \p MI returns the Value pointed to by that instruction reference if any
1200+
/// exists, otherwise returns None.
1201+
std::optional<ValueIDNum> getValueForInstrRef(unsigned InstNo, unsigned OpNo,
1202+
MachineInstr &MI,
1203+
const ValueTable *MLiveOuts,
1204+
const ValueTable *MLiveIns);
1205+
11971206
/// Observe a single instruction while stepping through a block.
11981207
void process(MachineInstr &MI, const ValueTable *MLiveOuts,
11991208
const ValueTable *MLiveIns);

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,27 @@ DIExpression::convertToVariadicExpression(const DIExpression *Expr) {
14751475
return DIExpression::get(Expr->getContext(), NewOps);
14761476
}
14771477

1478+
std::optional<const DIExpression *>
1479+
DIExpression::convertToNonVariadicExpression(const DIExpression *Expr) {
1480+
// Check for `isValid` covered by `isSingleLocationExpression`.
1481+
if (!Expr->isSingleLocationExpression())
1482+
return std::nullopt;
1483+
1484+
// An empty expression is already non-variadic.
1485+
if (!Expr->getNumElements())
1486+
return Expr;
1487+
1488+
auto ElementsBegin = Expr->elements_begin();
1489+
// If Expr does not have a leading DW_OP_LLVM_arg then we don't need to do
1490+
// anything.
1491+
if (*ElementsBegin != dwarf::DW_OP_LLVM_arg)
1492+
return Expr;
1493+
1494+
SmallVector<uint64_t> NonVariadicOps(
1495+
make_range(ElementsBegin + 2, Expr->elements_end()));
1496+
return DIExpression::get(Expr->getContext(), NonVariadicOps);
1497+
}
1498+
14781499
void DIExpression::canonicalizeExpressionOps(SmallVectorImpl<uint64_t> &Ops,
14791500
const DIExpression *Expr,
14801501
bool IsIndirect) {

0 commit comments

Comments
 (0)