Skip to content

Commit

Permalink
[DebugInfo] Support representation of multiple location operands in S…
Browse files Browse the repository at this point in the history
…DDbgValue

This patch modifies the class that represents debug values during ISel,
SDDbgValue, to support multiple location operands (to represent a dbg.value that
uses a DIArgList). Part of this class's functionality has been split off into a
new class, SDDbgOperand.

The new class SDDbgOperand represents a single value, corresponding to an SSA
value or MachineOperand in the IR and MIR respectively. Members of SDDbgValue
that were previously related to that specific value (as opposed to the
variable or DIExpression), such as the Kind enum, have been moved to
SDDbgOperand. SDDbgValue now contains an array of SDDbgOperand instead, allowing
it to hold more than one of these values.

All changes outside SDDbgValue are simply updates to use the new interface.

Differential Revision: https://reviews.llvm.org/D88585
  • Loading branch information
SLTozer committed Mar 8, 2021
1 parent 7cdcb4a commit 9525af7
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 93 deletions.
29 changes: 17 additions & 12 deletions llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
Expand Up @@ -701,11 +701,12 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
if (auto *InstrRef = EmitDbgInstrRef(SD, VRBaseMap))
return InstrRef;

if (SD->getKind() == SDDbgValue::FRAMEIX) {
SDDbgOperand SDOperand = SD->getLocationOps()[0];
if (SDOperand.getKind() == SDDbgOperand::FRAMEIX) {
// Stack address; this needs to be lowered in target-dependent fashion.
// EmitTargetCodeForFrameDebugValue is responsible for allocation.
auto FrameMI = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE))
.addFrameIndex(SD->getFrameIx());
.addFrameIndex(SDOperand.getFrameIx());
if (SD->isIndirect())
// Push [fi + 0] onto the DIExpression stack.
FrameMI.addImm(0);
Expand All @@ -717,9 +718,9 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
// Otherwise, we're going to create an instruction here.
const MCInstrDesc &II = TII->get(TargetOpcode::DBG_VALUE);
MachineInstrBuilder MIB = BuildMI(*MF, DL, II);
if (SD->getKind() == SDDbgValue::SDNODE) {
SDNode *Node = SD->getSDNode();
SDValue Op = SDValue(Node, SD->getResNo());
if (SDOperand.getKind() == SDDbgOperand::SDNODE) {
SDNode *Node = SDOperand.getSDNode();
SDValue Op = SDValue(Node, SDOperand.getResNo());
// It's possible we replaced this SDNode with other(s) and therefore
// didn't generate code for it. It's better to catch these cases where
// they happen and transfer the debug info, but trying to guarantee that
Expand All @@ -731,10 +732,10 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
else
AddOperand(MIB, Op, (*MIB).getNumOperands(), &II, VRBaseMap,
/*IsDebug=*/true, /*IsClone=*/false, /*IsCloned=*/false);
} else if (SD->getKind() == SDDbgValue::VREG) {
MIB.addReg(SD->getVReg(), RegState::Debug);
} else if (SD->getKind() == SDDbgValue::CONST) {
const Value *V = SD->getConst();
} else if (SDOperand.getKind() == SDDbgOperand::VREG) {
MIB.addReg(SDOperand.getVReg(), RegState::Debug);
} else if (SDOperand.getKind() == SDDbgOperand::CONST) {
const Value *V = SDOperand.getConst();
if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
if (CI->getBitWidth() > 64)
MIB.addCImm(CI);
Expand Down Expand Up @@ -770,14 +771,18 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
MachineInstr *
InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD,
DenseMap<SDValue, Register> &VRBaseMap) {
// No support for instruction references for variadic values yet.
if (SD->isVariadic())
return nullptr;
SDDbgOperand DbgOperand = SD->getLocationOps()[0];
// Instruction referencing is still in a prototype state: for now we're only
// going to support SDNodes within a block. Copies are not supported, they
// don't actually define a value.
if (SD->getKind() != SDDbgValue::SDNODE)
if (DbgOperand.getKind() != SDDbgOperand::SDNODE)
return nullptr;

SDNode *Node = SD->getSDNode();
SDValue Op = SDValue(Node, SD->getResNo());
SDNode *Node = DbgOperand.getSDNode();
SDValue Op = SDValue(Node, DbgOperand.getResNo());
DenseMap<SDValue, Register>::iterator I = VRBaseMap.find(Op);
if (I==VRBaseMap.end())
return nullptr; // undef value: let EmitDbgValue produce a DBG_VALUE $noreg.
Expand Down
171 changes: 119 additions & 52 deletions llvm/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h
Expand Up @@ -25,94 +25,161 @@ class SDNode;
class Value;
class raw_ostream;

/// Holds the information from a dbg_value node through SDISel.
/// We do not use SDValue here to avoid including its header.
class SDDbgValue {
/// Holds the information for a single machine location through SDISel; either
/// an SDNode, a constant, a stack location, or a virtual register.
class SDDbgOperand {
public:
enum DbgValueKind {
SDNODE = 0, ///< Value is the result of an expression.
CONST = 1, ///< Value is a constant.
FRAMEIX = 2, ///< Value is contents of a stack location.
VREG = 3 ///< Value is a virtual register.
enum Kind {
SDNODE = 0, ///< Value is the result of an expression.
CONST = 1, ///< Value is a constant.
FRAMEIX = 2, ///< Value is contents of a stack location.
VREG = 3 ///< Value is a virtual register.
};
Kind getKind() const { return kind; }

/// Returns the SDNode* for a register ref
SDNode *getSDNode() const {
assert(kind == SDNODE);
return u.s.Node;
}

/// Returns the ResNo for a register ref
unsigned getResNo() const {
assert(kind == SDNODE);
return u.s.ResNo;
}

/// Returns the Value* for a constant
const Value *getConst() const {
assert(kind == CONST);
return u.Const;
}

/// Returns the FrameIx for a stack object
unsigned getFrameIx() const {
assert(kind == FRAMEIX);
return u.FrameIx;
}

/// Returns the Virtual Register for a VReg
unsigned getVReg() const {
assert(kind == VREG);
return u.VReg;
}

static SDDbgOperand fromNode(SDNode *Node, unsigned ResNo) {
return SDDbgOperand(Node, ResNo);
}
static SDDbgOperand fromFrameIdx(unsigned FrameIdx) {
return SDDbgOperand(FrameIdx, FRAMEIX);
}
static SDDbgOperand fromVReg(unsigned VReg) {
return SDDbgOperand(VReg, VREG);
}
static SDDbgOperand fromConst(const Value *Const) {
return SDDbgOperand(Const);
}

bool operator!=(const SDDbgOperand &Other) const { return !(*this == Other); }
bool operator==(const SDDbgOperand &Other) const {
if (kind != Other.kind)
return false;
switch (kind) {
case SDNODE:
return getSDNode() == Other.getSDNode() && getResNo() == Other.getResNo();
case CONST:
return getConst() == Other.getConst();
case VREG:
return getVReg() == Other.getVReg();
case FRAMEIX:
return getFrameIx() == Other.getFrameIx();
default:
llvm_unreachable("unknown kind");
}
}

private:
Kind kind;
union {
struct {
SDNode *Node; ///< Valid for expressions.
unsigned ResNo; ///< Valid for expressions.
SDNode *Node; ///< Valid for expressions.
unsigned ResNo; ///< Valid for expressions.
} s;
const Value *Const; ///< Valid for constants.
unsigned FrameIx; ///< Valid for stack objects.
unsigned VReg; ///< Valid for registers.
const Value *Const; ///< Valid for constants.
unsigned FrameIx; ///< Valid for stack objects.
unsigned VReg; ///< Valid for registers.
} u;
DIVariable *Var;
DIExpression *Expr;
DebugLoc DL;
unsigned Order;
enum DbgValueKind kind;
bool IsIndirect;
bool Invalid = false;
bool Emitted = false;

public:
/// Constructor for non-constants.
SDDbgValue(DIVariable *Var, DIExpression *Expr, SDNode *N, unsigned R,
bool indir, DebugLoc dl, unsigned O)
: Var(Var), Expr(Expr), DL(std::move(dl)), Order(O), IsIndirect(indir) {
kind = SDNODE;
SDDbgOperand(SDNode *N, unsigned R) : kind(SDNODE) {
u.s.Node = N;
u.s.ResNo = R;
}

/// Constructor for constants.
SDDbgValue(DIVariable *Var, DIExpression *Expr, const Value *C, DebugLoc dl,
unsigned O)
: Var(Var), Expr(Expr), DL(std::move(dl)), Order(O), IsIndirect(false) {
kind = CONST;
u.Const = C;
}

SDDbgOperand(const Value *C) : kind(CONST) { u.Const = C; }
/// Constructor for virtual registers and frame indices.
SDDbgValue(DIVariable *Var, DIExpression *Expr, unsigned VRegOrFrameIdx,
bool IsIndirect, DebugLoc DL, unsigned Order,
enum DbgValueKind Kind)
: Var(Var), Expr(Expr), DL(DL), Order(Order), IsIndirect(IsIndirect) {
SDDbgOperand(unsigned VRegOrFrameIdx, Kind Kind) : kind(Kind) {
assert((Kind == VREG || Kind == FRAMEIX) &&
"Invalid SDDbgValue constructor");
kind = Kind;
if (kind == VREG)
u.VReg = VRegOrFrameIdx;
else
u.FrameIx = VRegOrFrameIdx;
}
};

/// Holds the information from a dbg_value node through SDISel.
/// We do not use SDValue here to avoid including its header.
class SDDbgValue {
public:
// FIXME: These SmallVector sizes were chosen without any kind of performance
// testing.
using LocOpVector = SmallVector<SDDbgOperand, 2>;
using SDNodeVector = SmallVector<SDNode *, 2>;

private:
LocOpVector LocationOps;
SDNodeVector SDNodes;
DIVariable *Var;
DIExpression *Expr;
DebugLoc DL;
unsigned Order;
bool IsIndirect;
bool IsVariadic;
bool Invalid = false;
bool Emitted = false;

/// Returns the kind.
DbgValueKind getKind() const { return kind; }
public:
SDDbgValue(DIVariable *Var, DIExpression *Expr, ArrayRef<SDDbgOperand> L,
ArrayRef<SDNode *> Dependencies, bool IsIndirect, DebugLoc DL,
unsigned O, bool IsVariadic)
: LocationOps(L.begin(), L.end()),
SDNodes(Dependencies.begin(), Dependencies.end()), Var(Var), Expr(Expr),
DL(DL), Order(O), IsIndirect(IsIndirect), IsVariadic(IsVariadic) {
assert(IsVariadic || L.size() == 1);
assert(!(IsVariadic && IsIndirect));
}

/// Returns the DIVariable pointer for the variable.
DIVariable *getVariable() const { return Var; }

/// Returns the DIExpression pointer for the expression.
DIExpression *getExpression() const { return Expr; }

/// Returns the SDNode* for a register ref
SDNode *getSDNode() const { assert (kind==SDNODE); return u.s.Node; }
ArrayRef<SDDbgOperand> getLocationOps() const { return LocationOps; }

/// Returns the ResNo for a register ref
unsigned getResNo() const { assert (kind==SDNODE); return u.s.ResNo; }
LocOpVector copyLocationOps() const { return LocationOps; }

/// Returns the Value* for a constant
const Value *getConst() const { assert (kind==CONST); return u.Const; }
// Returns the SDNodes which this SDDbgValue depends on.
ArrayRef<SDNode *> getSDNodes() const { return SDNodes; }

/// Returns the FrameIx for a stack object
unsigned getFrameIx() const { assert (kind==FRAMEIX); return u.FrameIx; }

/// Returns the Virtual Register for a VReg
unsigned getVReg() const { assert (kind==VREG); return u.VReg; }
SDNodeVector copySDNodes() const { return SDNodes; }

/// Returns whether this is an indirect value.
bool isIndirect() const { return IsIndirect; }

bool isVariadic() const { return IsVariadic; }

/// Returns the DebugLoc.
DebugLoc getDebugLoc() const { return DL; }

Expand Down
20 changes: 13 additions & 7 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Expand Up @@ -8449,7 +8449,8 @@ SDDbgValue *SelectionDAG::getDbgValue(DIVariable *Var, DIExpression *Expr,
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
return new (DbgInfo->getAlloc())
SDDbgValue(Var, Expr, N, R, IsIndirect, DL, O);
SDDbgValue(Var, Expr, SDDbgOperand::fromNode(N, R), N, IsIndirect, DL, O,
/*IsVariadic=*/false);
}

/// Constant
Expand All @@ -8459,7 +8460,9 @@ SDDbgValue *SelectionDAG::getConstantDbgValue(DIVariable *Var,
const DebugLoc &DL, unsigned O) {
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
return new (DbgInfo->getAlloc()) SDDbgValue(Var, Expr, C, DL, O);
return new (DbgInfo->getAlloc()) SDDbgValue(
Var, Expr, SDDbgOperand::fromConst(C), {}, /*IsIndirect=*/false, DL, O,
/*IsVariadic=*/false);
}

/// FrameIndex
Expand All @@ -8471,7 +8474,8 @@ SDDbgValue *SelectionDAG::getFrameIndexDbgValue(DIVariable *Var,
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
return new (DbgInfo->getAlloc())
SDDbgValue(Var, Expr, FI, IsIndirect, DL, O, SDDbgValue::FRAMEIX);
SDDbgValue(Var, Expr, SDDbgOperand::fromFrameIdx(FI), {}, IsIndirect, DL,
O, /*IsVariadic=*/false);
}

/// VReg
Expand All @@ -8482,7 +8486,8 @@ SDDbgValue *SelectionDAG::getVRegDbgValue(DIVariable *Var,
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
return new (DbgInfo->getAlloc())
SDDbgValue(Var, Expr, VReg, IsIndirect, DL, O, SDDbgValue::VREG);
SDDbgValue(Var, Expr, SDDbgOperand::fromVReg(VReg), {}, IsIndirect, DL, O,
/*IsVariadic=*/false);
}

void SelectionDAG::transferDbgValues(SDValue From, SDValue To,
Expand All @@ -8503,13 +8508,14 @@ void SelectionDAG::transferDbgValues(SDValue From, SDValue To,

SmallVector<SDDbgValue *, 2> ClonedDVs;
for (SDDbgValue *Dbg : GetDbgValues(FromNode)) {
if (Dbg->getKind() != SDDbgValue::SDNODE || Dbg->isInvalidated())
SDDbgOperand DbgOperand = Dbg->getLocationOps()[0];
if (DbgOperand.getKind() != SDDbgOperand::SDNODE || Dbg->isInvalidated())
continue;

// TODO: assert(!Dbg->isInvalidated() && "Transfer of invalid dbg value");

// Just transfer the dbg value attached to From.
if (Dbg->getResNo() != From.getResNo())
if (DbgOperand.getResNo() != From.getResNo())
continue;

DIVariable *Var = Dbg->getVariable();
Expand Down Expand Up @@ -8583,7 +8589,7 @@ void SelectionDAG::salvageDebugInfo(SDNode &N) {
}

for (SDDbgValue *Dbg : ClonedDVs)
AddDbgValue(Dbg, Dbg->getSDNode(), false);
AddDbgValue(Dbg, Dbg->getLocationOps()[0].getSDNode(), false);
}

/// Creates a SDDbgLabel node.
Expand Down
12 changes: 8 additions & 4 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Expand Up @@ -1157,6 +1157,8 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
for (auto &DDI : DDIV) {
const DbgValueInst *DI = DDI.getDI();
assert(DI && "Ill-formed DanglingDebugInfo");
assert(!DDI.getDI()->hasArgList() &&
"Variadic dbg.values should not yet be left dangling.");
DebugLoc dl = DDI.getdl();
unsigned ValSDNodeOrder = Val.getNode()->getIROrder();
unsigned DbgSDNodeOrder = DDI.getSDNodeOrder();
Expand Down Expand Up @@ -1191,7 +1193,7 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
<< "in EmitFuncArgumentDbgValue\n");
} else {
LLVM_DEBUG(dbgs() << "Dropping debug info for " << *DI << "\n");
auto Undef = UndefValue::get(DDI.getDI()->getValue()->getType());
auto Undef = UndefValue::get(DDI.getDI()->getValue(0)->getType());
auto SDV =
DAG.getConstantDbgValue(Variable, Expr, Undef, dl, DbgSDNodeOrder);
DAG.AddDbgValue(SDV, nullptr, false);
Expand All @@ -1201,7 +1203,9 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V,
}

void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
Value *V = DDI.getDI()->getValue();
assert(!DDI.getDI()->hasArgList() &&
"Variadic dbg.values should not yet be left dangling.");
Value *V = DDI.getDI()->getValue(0);
DILocalVariable *Var = DDI.getDI()->getVariable();
DIExpression *Expr = DDI.getDI()->getExpression();
DebugLoc DL = DDI.getdl();
Expand Down Expand Up @@ -1245,7 +1249,7 @@ void SelectionDAGBuilder::salvageUnresolvedDbgValue(DanglingDebugInfo &DDI) {
// This was the final opportunity to salvage this debug information, and it
// couldn't be done. Place an undef DBG_VALUE at this location to terminate
// any earlier variable location.
auto Undef = UndefValue::get(DDI.getDI()->getValue()->getType());
auto Undef = UndefValue::get(DDI.getDI()->getValue(0)->getType());
auto SDV = DAG.getConstantDbgValue(Var, Expr, Undef, DL, SDNodeOrder);
DAG.AddDbgValue(SDV, nullptr, false);

Expand Down Expand Up @@ -5977,7 +5981,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
DILocalVariable *Variable = DI.getVariable();
DIExpression *Expression = DI.getExpression();
dropDanglingDebugInfo(Variable, Expression);
const Value *V = DI.getValue();
const Value *V = DI.getValue(0);
if (!V)
return;

Expand Down

0 comments on commit 9525af7

Please sign in to comment.