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);
// 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
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);
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.
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; }
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
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
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
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,
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();
}
for (SDDbgValue *Dbg : ClonedDVs)
- AddDbgValue(Dbg, Dbg->getSDNode(), false);
+ AddDbgValue(Dbg, Dbg->getLocationOps()[0].getSDNode(), false);
}
/// Creates a SDDbgLabel node.
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();
<< "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);
}
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();
// 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);
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;
LLVM_DUMP_METHOD void SDDbgValue::print(raw_ostream &OS) const {
OS << " DbgVal(Order=" << getOrder() << ')';
- if (isInvalidated()) OS << "(Invalidated)";
- if (isEmitted()) OS << "(Emitted)";
- switch (getKind()) {
- case SDNODE:
- if (getSDNode())
- OS << "(SDNODE=" << PrintNodeId(*getSDNode()) << ':' << getResNo() << ')';
- else
- OS << "(SDNODE)";
- break;
- case CONST:
- OS << "(CONST)";
- break;
- case FRAMEIX:
- OS << "(FRAMEIX=" << getFrameIx() << ')';
- break;
- case VREG:
- OS << "(VREG=" << getVReg() << ')';
- break;
+ if (isInvalidated())
+ OS << "(Invalidated)";
+ if (isEmitted())
+ OS << "(Emitted)";
+ OS << "(";
+ bool Comma = false;
+ for (const SDDbgOperand &Op : getLocationOps()) {
+ if (Comma)
+ OS << ", ";
+ switch (Op.getKind()) {
+ case SDDbgOperand::SDNODE:
+ if (Op.getSDNode())
+ OS << "SDNODE=" << PrintNodeId(*Op.getSDNode()) << ':' << Op.getResNo();
+ else
+ OS << "SDNODE";
+ break;
+ case SDDbgOperand::CONST:
+ OS << "CONST";
+ break;
+ case SDDbgOperand::FRAMEIX:
+ OS << "FRAMEIX=" << Op.getFrameIx();
+ break;
+ case SDDbgOperand::VREG:
+ OS << "VREG=" << Op.getVReg();
+ break;
+ }
+ Comma = true;
}
+ OS << ")";
if (isIndirect()) OS << "(Indirect)";
+ if (isVariadic())
+ OS << "(Variadic)";
OS << ":\"" << Var->getName() << '"';
#ifndef NDEBUG
if (Expr->getNumElements())