Following on from this RFC[0] from a while back, this is the first patch towards
implementing variadic debug values.
This patch specifically adds a set of functions to MachineInstr for performing
operations specific to debug values, and replacing uses of the more general
functions where appropriate. The most prevalent of these is replacing
getOperand(0) with getDebugOperand(0) for debug-value-specific code, as the
operands corresponding to values will no longer be at index 0, but index 2 and
upwards: getDebugOperand(x) == getOperand(x+2). Similar replacements have been
added for the other operands, along with some helper functions to replace
oft-repeated code and operate on a variable number of value operands.
[0] http://lists.llvm.org/pipermail/llvm-dev/2020-February/139376.html<Paste>
Differential Revision: https://reviews.llvm.org/D81852
/// other machine instruction to use NewReg.
void UpdateDbgValue(MachineInstr &MI, unsigned OldReg, unsigned NewReg) {
assert(MI.isDebugValue() && "MI is not DBG_VALUE!");
- if (MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == OldReg)
- MI.getOperand(0).setReg(NewReg);
+ if (MI.getDebugOperand(0).isReg() &&
+ MI.getDebugOperand(0).getReg() == OldReg)
+ MI.getDebugOperand(0).setReg(NewReg);
}
/// Update all DBG_VALUE instructions that may be affected by the dependency
/// Returns the debug location id of this MachineInstr.
const DebugLoc &getDebugLoc() const { return debugLoc; }
+ /// Return the operand containing the offset to be used if this DBG_VALUE
+ /// instruction is indirect; will be an invalid register if this value is
+ /// not indirect, and an immediate with value 0 otherwise.
+ const MachineOperand &getDebugOffset() const {
+ assert(isDebugValue() && "not a DBG_VALUE");
+ return getOperand(1);
+ }
+ MachineOperand &getDebugOffset() {
+ assert(isDebugValue() && "not a DBG_VALUE");
+ return getOperand(1);
+ }
+
+ /// Return the operand for the debug variable referenced by
+ /// this DBG_VALUE instruction.
+ const MachineOperand &getDebugVariableOp() const;
+ MachineOperand &getDebugVariableOp();
+
/// Return the debug variable referenced by
/// this DBG_VALUE instruction.
const DILocalVariable *getDebugVariable() const;
+ /// Return the operand for the complex address expression referenced by
+ /// this DBG_VALUE instruction.
+ MachineOperand &getDebugExpressionOp();
+
/// Return the complex address expression referenced by
/// this DBG_VALUE instruction.
const DIExpression *getDebugExpression() const;
/// Retuns the total number of operands.
unsigned getNumOperands() const { return NumOperands; }
+ /// Returns the total number of operands which are debug locations.
+ unsigned getNumDebugOperands() const {
+ return std::distance(debug_operands().begin(), debug_operands().end());
+ }
+
const MachineOperand& getOperand(unsigned i) const {
assert(i < getNumOperands() && "getOperand() out of range!");
return Operands[i];
return Operands[i];
}
+ MachineOperand &getDebugOperand(unsigned Index) {
+ assert(Index < getNumDebugOperands() && "getDebugOperand() out of range!");
+ return *(debug_operands().begin() + Index);
+ }
+ const MachineOperand &getDebugOperand(unsigned Index) const {
+ assert(Index < getNumDebugOperands() && "getDebugOperand() out of range!");
+ return *(debug_operands().begin() + Index);
+ }
+
+ /// Returns a pointer to the operand corresponding to a debug use of Reg, or
+ /// nullptr if Reg is not used in any debug operand.
+ const MachineOperand *getDebugOperandForReg(Register Reg) const {
+ const MachineOperand *RegOp =
+ find_if(debug_operands(), [Reg](const MachineOperand &Op) {
+ return Op.isReg() && Op.getReg() == Reg;
+ });
+ return RegOp == adl_end(debug_operands()) ? nullptr : RegOp;
+ }
+ MachineOperand *getDebugOperandForReg(Register Reg) {
+ MachineOperand *RegOp =
+ find_if(debug_operands(), [Reg](const MachineOperand &Op) {
+ return Op.isReg() && Op.getReg() == Reg;
+ });
+ return RegOp == adl_end(debug_operands()) ? nullptr : RegOp;
+ }
+
+ unsigned getDebugOperandIndex(const MachineOperand *Op) const {
+ assert(Op >= adl_begin(debug_operands()) &&
+ Op <= adl_end(debug_operands()) && "Expected a debug operand.");
+ return std::distance(adl_begin(debug_operands()), Op);
+ }
+
/// Returns the total number of definitions.
unsigned getNumDefs() const {
return getNumExplicitDefs() + MCID->getNumImplicitDefs();
iterator_range<const_mop_iterator> implicit_operands() const {
return make_range(explicit_operands().end(), operands_end());
}
+ /// Returns a range over all operands that are used to determine the variable
+ /// location for this DBG_VALUE instruction.
+ iterator_range<mop_iterator> debug_operands() {
+ assert(isDebugValue() && "Must be a debug value instruction.");
+ return make_range(operands_begin(), operands_begin() + 1);
+ }
+ /// \copydoc debug_operands()
+ iterator_range<const_mop_iterator> debug_operands() const {
+ assert(isDebugValue() && "Must be a debug value instruction.");
+ return make_range(operands_begin(), operands_begin() + 1);
+ }
/// Returns a range over all explicit operands that are register definitions.
/// Implicit definition are not included!
iterator_range<mop_iterator> defs() {
bool isDebugLabel() const { return getOpcode() == TargetOpcode::DBG_LABEL; }
bool isDebugInstr() const { return isDebugValue() || isDebugLabel(); }
- /// A DBG_VALUE is indirect iff the first operand is a register and
- /// the second operand is an immediate.
+ bool isDebugOffsetImm() const { return getDebugOffset().isImm(); }
+
+ /// A DBG_VALUE is indirect iff the location operand is a register and
+ /// the offset operand is an immediate.
bool isIndirectDebugValue() const {
- return isDebugValue()
- && getOperand(0).isReg()
- && getOperand(1).isImm();
+ return isDebugValue() && getDebugOperand(0).isReg() && isDebugOffsetImm();
}
/// A DBG_VALUE is an entry value iff its debug expression contains the
/// Return true if the instruction is a debug value which describes a part of
/// a variable as unavailable.
bool isUndefDebugValue() const {
- return isDebugValue() && getOperand(0).isReg() && !getOperand(0).getReg().isValid();
+ return isDebugValue() && getDebugOperand(0).isReg() &&
+ !getDebugOperand(0).getReg().isValid();
}
bool isPHI() const {
return getOperand(getNumExplicitDefs()).getIntrinsicID();
}
+ /// Sets all register debug operands in this debug value instruction to be
+ /// undef.
+ void setDebugValueUndef() {
+ assert(isDebugValue() && "Must be a debug value instruction.");
+ for (MachineOperand &MO : debug_operands()) {
+ if (MO.isReg())
+ MO.setReg(0);
+ }
+ }
+
private:
/// If this instruction is embedded into a MachineFunction, return the
/// MachineRegisterInfo object for the current function, otherwise
OS << " <- ";
// The second operand is only an offset if it's an immediate.
- bool MemLoc = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
+ bool MemLoc = MI->isIndirectDebugValue();
int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0;
const DIExpression *Expr = MI->getDebugExpression();
if (Expr->getNumElements()) {
}
// Register or immediate value. Register 0 means undef.
- if (MI->getOperand(0).isFPImm()) {
- APFloat APF = APFloat(MI->getOperand(0).getFPImm()->getValueAPF());
- if (MI->getOperand(0).getFPImm()->getType()->isFloatTy()) {
+ if (MI->getDebugOperand(0).isFPImm()) {
+ APFloat APF = APFloat(MI->getDebugOperand(0).getFPImm()->getValueAPF());
+ if (MI->getDebugOperand(0).getFPImm()->getType()->isFloatTy()) {
OS << (double)APF.convertToFloat();
- } else if (MI->getOperand(0).getFPImm()->getType()->isDoubleTy()) {
+ } else if (MI->getDebugOperand(0).getFPImm()->getType()->isDoubleTy()) {
OS << APF.convertToDouble();
} else {
// There is no good way to print long double. Convert a copy to
&ignored);
OS << "(long double) " << APF.convertToDouble();
}
- } else if (MI->getOperand(0).isImm()) {
- OS << MI->getOperand(0).getImm();
- } else if (MI->getOperand(0).isCImm()) {
- MI->getOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/);
- } else if (MI->getOperand(0).isTargetIndex()) {
- auto Op = MI->getOperand(0);
+ } else if (MI->getDebugOperand(0).isImm()) {
+ OS << MI->getDebugOperand(0).getImm();
+ } else if (MI->getDebugOperand(0).isCImm()) {
+ MI->getDebugOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/);
+ } else if (MI->getDebugOperand(0).isTargetIndex()) {
+ auto Op = MI->getDebugOperand(0);
OS << "!target-index(" << Op.getIndex() << "," << Op.getOffset() << ")";
return true;
} else {
Register Reg;
- if (MI->getOperand(0).isReg()) {
- Reg = MI->getOperand(0).getReg();
+ if (MI->getDebugOperand(0).isReg()) {
+ Reg = MI->getDebugOperand(0).getReg();
} else {
- assert(MI->getOperand(0).isFI() && "Unknown operand type");
+ assert(MI->getDebugOperand(0).isFI() && "Unknown operand type");
const TargetFrameLowering *TFI = AP.MF->getSubtarget().getFrameLowering();
- Offset += TFI->getFrameIndexReference(*AP.MF,
- MI->getOperand(0).getIndex(), Reg);
+ Offset += TFI->getFrameIndexReference(
+ *AP.MF, MI->getDebugOperand(0).getIndex(), Reg);
MemLoc = true;
}
if (Reg == 0) {
return 0;
// If location of variable is described using a register (directly or
// indirectly), this register is always a first operand.
- return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : Register();
+ return MI.getDebugOperand(0).isReg() ? MI.getDebugOperand(0).getReg()
+ : Register();
}
bool DbgValueHistoryMap::startDbgValue(InlinedEntity Var,
DbgVariableLocation Location;
if (!Instruction.isDebugValue())
return None;
- if (!Instruction.getOperand(0).isReg())
+ if (!Instruction.getDebugOperand(0).isReg())
return None;
- Location.Register = Instruction.getOperand(0).getReg();
+ Location.Register = Instruction.getDebugOperand(0).getReg();
Location.FragmentInfo.reset();
// We only handle expressions generated by DIExpression::appendOffset,
// which doesn't require a full stack machine.
continue;
auto IsDescribedByReg = [](const MachineInstr *MI) {
- return MI->getOperand(0).isReg() && MI->getOperand(0).getReg();
+ return MI->getDebugOperand(0).isReg() && MI->getDebugOperand(0).getReg();
};
// The first mention of a function argument gets the CurrentFnBegin label,
static DbgValueLoc getDebugLocValue(const MachineInstr *MI) {
const DIExpression *Expr = MI->getDebugExpression();
assert(MI->getNumOperands() == 4);
- if (MI->getOperand(0).isReg()) {
- auto RegOp = MI->getOperand(0);
- auto Op1 = MI->getOperand(1);
+ if (MI->getDebugOperand(0).isReg()) {
+ auto RegOp = MI->getDebugOperand(0);
+ auto Op1 = MI->getDebugOffset();
// If the second operand is an immediate, this is a
// register-indirect address.
assert((!Op1.isImm() || (Op1.getImm() == 0)) && "unexpected offset");
MachineLocation MLoc(RegOp.getReg(), Op1.isImm());
return DbgValueLoc(Expr, MLoc);
}
- if (MI->getOperand(0).isTargetIndex()) {
- auto Op = MI->getOperand(0);
+ if (MI->getDebugOperand(0).isTargetIndex()) {
+ auto Op = MI->getDebugOperand(0);
return DbgValueLoc(Expr,
TargetIndexLocation(Op.getIndex(), Op.getOffset()));
}
- if (MI->getOperand(0).isImm())
- return DbgValueLoc(Expr, MI->getOperand(0).getImm());
- if (MI->getOperand(0).isFPImm())
- return DbgValueLoc(Expr, MI->getOperand(0).getFPImm());
- if (MI->getOperand(0).isCImm())
- return DbgValueLoc(Expr, MI->getOperand(0).getCImm());
+ if (MI->getDebugOperand(0).isImm())
+ return DbgValueLoc(Expr, MI->getDebugOperand(0).getImm());
+ if (MI->getDebugOperand(0).isFPImm())
+ return DbgValueLoc(Expr, MI->getDebugOperand(0).getFPImm());
+ if (MI->getDebugOperand(0).isCImm())
+ return DbgValueLoc(Expr, MI->getDebugOperand(0).getCImm());
llvm_unreachable("Unexpected 4-operand DBG_VALUE instruction!");
}
// throughout the function. This is a hack, presumably for DWARF v2 and not
// necessarily correct. It would be much better to use a dbg.declare instead
// if we know the constant is live throughout the scope.
- if (DbgValue->getOperand(0).isImm() && MBB->pred_empty())
+ if (DbgValue->getDebugOperand(0).isImm() && MBB->pred_empty())
return true;
// Now check for situations where an "open-ended" DBG_VALUE isn't enough to
assert(MI.getNumOperands() == 4 && "malformed DBG_VALUE");
// If location of variable is described using a register (directly
// or indirectly), this register is always a first operand.
- return MI.getOperand(0).isReg() ? MI.getOperand(0).getReg() : Register();
+ return MI.getDebugOperand(0).isReg() ? MI.getDebugOperand(0).getReg()
+ : Register();
}
/// If \p Op is a stack or frame register return true, otherwise return false.
if (int RegNo = isDbgValueDescribedByReg(MI)) {
Kind = RegisterKind;
Loc.RegNo = RegNo;
- } else if (MI.getOperand(0).isImm()) {
+ } else if (MI.getDebugOperand(0).isImm()) {
Kind = ImmediateKind;
- Loc.Immediate = MI.getOperand(0).getImm();
- } else if (MI.getOperand(0).isFPImm()) {
+ Loc.Immediate = MI.getDebugOperand(0).getImm();
+ } else if (MI.getDebugOperand(0).isFPImm()) {
Kind = ImmediateKind;
- Loc.FPImm = MI.getOperand(0).getFPImm();
- } else if (MI.getOperand(0).isCImm()) {
+ Loc.FPImm = MI.getDebugOperand(0).getFPImm();
+ } else if (MI.getDebugOperand(0).isCImm()) {
Kind = ImmediateKind;
- Loc.CImm = MI.getOperand(0).getCImm();
+ Loc.CImm = MI.getDebugOperand(0).getCImm();
}
// We create the debug entry values from the factory functions rather than
// expression. The register location of such DBG_VALUE is always the one
// from the entry DBG_VALUE, it does not matter if the entry value was
// copied in to another register due to some optimizations.
- return BuildMI(MF, DbgLoc, IID, Indirect, MI.getOperand(0).getReg(),
- Var, Expr);
+ return BuildMI(MF, DbgLoc, IID, Indirect,
+ MI.getDebugOperand(0).getReg(), Var, Expr);
case RegisterKind:
// Register locations are like the source DBG_VALUE, but with the
// register number from this VarLoc.
return BuildMI(MF, DbgLoc, IID, true, Base, Var, SpillExpr);
}
case ImmediateKind: {
- MachineOperand MO = MI.getOperand(0);
+ MachineOperand MO = MI.getDebugOperand(0);
return BuildMI(MF, DbgLoc, IID, Indirect, MO, Var, DIExpr);
}
case EntryValueBackupKind:
// the entry value any more. In addition, if the debug expression from the
// DBG_VALUE is not empty, we can assume the parameter's value has changed
// indicating that we should stop tracking its entry value as well.
- if (!MI.getOperand(0).isReg() ||
+ if (!MI.getDebugOperand(0).isReg() ||
MI.getDebugExpression()->getNumElements() != 0)
return true;
// it means the parameter's value has not changed and we should be able to use
// its entry value.
bool TrySalvageEntryValue = false;
- Register Reg = MI.getOperand(0).getReg();
+ Register Reg = MI.getDebugOperand(0).getReg();
auto I = std::next(MI.getReverseIterator());
const MachineOperand *SrcRegOp, *DestRegOp;
if (I != MI.getParent()->rend()) {
for (uint64_t ID : OpenRanges.getEntryValueBackupVarLocs()) {
const VarLoc &VL = VarLocIDs[LocIndex::fromRawInteger(ID)];
if (VL.getEntryValueCopyBackupReg() == Reg &&
- VL.MI.getOperand(0).getReg() == SrcRegOp->getReg())
+ VL.MI.getDebugOperand(0).getReg() == SrcRegOp->getReg())
return false;
}
}
}
}
- if (isDbgValueDescribedByReg(MI) || MI.getOperand(0).isImm() ||
- MI.getOperand(0).isFPImm() || MI.getOperand(0).isCImm()) {
+ if (isDbgValueDescribedByReg(MI) || MI.getDebugOperand(0).isImm() ||
+ MI.getDebugOperand(0).isFPImm() || MI.getDebugOperand(0).isCImm()) {
// Use normal VarLoc constructor for registers and immediates.
VarLoc VL(MI, LS);
// End all previous ranges of VL.Var.
llvm_unreachable("DBG_VALUE with mem operand encountered after regalloc?");
} else {
// This must be an undefined location. If it has an open range, erase it.
- assert(MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == 0 &&
+ assert(MI.getDebugOperand(0).isReg() &&
+ MI.getDebugOperand(0).getReg() == 0 &&
"Unexpected non-undef DBG_VALUE encountered");
VarLoc VL(MI, LS);
OpenRanges.erase(VL);
// Only consider parameters that are described using registers. Parameters
// that are passed on the stack are not yet supported, so ignore debug
// values that are described by the frame or stack pointer.
- if (!isRegOtherThanSPAndFP(MI.getOperand(0), MI, TRI))
+ if (!isRegOtherThanSPAndFP(MI.getDebugOperand(0), MI, TRI))
return false;
// If a parameter's value has been propagated from the caller, then the
// parameter's DBG_VALUE may be described using a register defined by some
// instruction in the entry block, in which case we shouldn't create an
// entry value.
- if (DefinedRegs.count(MI.getOperand(0).getReg()))
+ if (DefinedRegs.count(MI.getDebugOperand(0).getReg()))
return false;
// TODO: Add support for parameters that have a pre-existing debug expressions
bool LDVImpl::handleDebugValue(MachineInstr &MI, SlotIndex Idx) {
// DBG_VALUE loc, offset, variable
if (MI.getNumOperands() != 4 ||
- !(MI.getOperand(1).isReg() || MI.getOperand(1).isImm()) ||
- !MI.getOperand(2).isMetadata()) {
+ !(MI.getDebugOffset().isReg() || MI.getDebugOffset().isImm()) ||
+ !MI.getDebugVariableOp().isMetadata()) {
LLVM_DEBUG(dbgs() << "Can't handle " << MI);
return false;
}
// (and if the machine verifier is improved to catch this), then these checks
// could be removed or replaced by asserts.
bool Discard = false;
- if (MI.getOperand(0).isReg() &&
- Register::isVirtualRegister(MI.getOperand(0).getReg())) {
- const Register Reg = MI.getOperand(0).getReg();
+ if (MI.getDebugOperand(0).isReg() &&
+ Register::isVirtualRegister(MI.getDebugOperand(0).getReg())) {
+ const Register Reg = MI.getDebugOperand(0).getReg();
if (!LIS->hasInterval(Reg)) {
// The DBG_VALUE is described by a virtual register that does not have a
// live interval. Discard the DBG_VALUE.
}
// Get or create the UserValue for (variable,offset) here.
- bool IsIndirect = MI.getOperand(1).isImm();
+ bool IsIndirect = MI.isDebugOffsetImm();
if (IsIndirect)
- assert(MI.getOperand(1).getImm() == 0 && "DBG_VALUE with nonzero offset");
+ assert(MI.getDebugOffset().getImm() == 0 &&
+ "DBG_VALUE with nonzero offset");
const DILocalVariable *Var = MI.getDebugVariable();
const DIExpression *Expr = MI.getDebugExpression();
UserValue *UV = getUserValue(Var, Expr->getFragmentInfo(), MI.getDebugLoc());
if (!Discard)
- UV->addDef(Idx, MI.getOperand(0), IsIndirect, *Expr);
+ UV->addDef(Idx, MI.getDebugOperand(0), IsIndirect, *Expr);
else {
MachineOperand MO = MachineOperand::CreateReg(0U, false);
MO.setIsDebug();
MachineBasicBlock::iterator EndIter = std::next(MI.getIterator());
if (MI.getOperand(0).isReg())
for (; EndIter != MBB.end() && EndIter->isDebugValue() &&
- EndIter->getOperand(0).isReg() &&
- EndIter->getOperand(0).getReg() == MI.getOperand(0).getReg();
+ EndIter->getDebugOperandForReg(MI.getOperand(0).getReg());
++EndIter, ++Next)
IOM[&*EndIter] = NewOrder;
MBB.splice(I, &MBB, MI.getIterator(), EndIter);
return cast<DILabel>(getOperand(0).getMetadata());
}
+const MachineOperand &MachineInstr::getDebugVariableOp() const {
+ assert(isDebugValue() && "not a DBG_VALUE");
+ return getOperand(2);
+}
+
+MachineOperand &MachineInstr::getDebugVariableOp() {
+ assert(isDebugValue() && "not a DBG_VALUE");
+ return getOperand(2);
+}
+
const DILocalVariable *MachineInstr::getDebugVariable() const {
assert(isDebugValue() && "not a DBG_VALUE");
return cast<DILocalVariable>(getOperand(2).getMetadata());
}
+MachineOperand &MachineInstr::getDebugExpressionOp() {
+ assert(isDebugValue() && "not a DBG_VALUE");
+ return getOperand(3);
+}
+
const DIExpression *MachineInstr::getDebugExpression() const {
assert(isDebugValue() && "not a DBG_VALUE");
return cast<DIExpression>(getOperand(3).getMetadata());
}
// Print extra comments for DEBUG_VALUE.
- if (isDebugValue() && getOperand(e - 2).isMetadata()) {
+ if (isDebugValue() && getDebugVariableOp().isMetadata()) {
if (!HaveSemi) {
OS << ";";
HaveSemi = true;
}
- auto *DV = cast<DILocalVariable>(getOperand(e - 2).getMetadata());
+ auto *DV = getDebugVariable();
OS << " line no:" << DV->getLine();
if (isIndirectDebugValue())
OS << " indirect";
const DIExpression *Expr = MI.getDebugExpression();
if (MI.isIndirectDebugValue()) {
- assert(MI.getOperand(1).getImm() == 0 && "DBG_VALUE with nonzero offset");
+ assert(MI.getDebugOffset().getImm() == 0 &&
+ "DBG_VALUE with nonzero offset");
Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
}
return Expr;
void llvm::updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex) {
const DIExpression *Expr = computeExprForSpill(Orig);
- Orig.getOperand(0).ChangeToFrameIndex(FrameIndex);
- Orig.getOperand(1).ChangeToImmediate(0U);
- Orig.getOperand(3).setMetadata(Expr);
+ Orig.getDebugOperand(0).ChangeToFrameIndex(FrameIndex);
+ Orig.getDebugOffset().ChangeToImmediate(0U);
+ Orig.getDebugExpressionOp().setMetadata(Expr);
}
void MachineInstr::collectDebugValues(
DI != DE; ++DI) {
if (!DI->isDebugValue())
return;
- if (DI->getOperand(0).isReg() &&
- DI->getOperand(0).getReg() == MI.getOperand(0).getReg())
+ if (DI->getDebugOperandForReg(MI.getOperand(0).getReg()))
DbgValues.push_back(&*DI);
}
}
if (!getOperand(0).isReg())
return;
- unsigned DefReg = getOperand(0).getReg();
+ Register DefReg = getOperand(0).getReg();
auto *MRI = getRegInfo();
for (auto &MO : MRI->use_operands(DefReg)) {
auto *DI = MO.getParent();
if (!DI->isDebugValue())
continue;
- if (DI->getOperand(0).isReg() &&
- DI->getOperand(0).getReg() == DefReg){
+ if (DI->getDebugOperandForReg(DefReg)) {
DbgValues.push_back(DI);
}
}
// Propagate Reg to debug value instructions.
for (auto *DBI : DbgValues)
- DBI->getOperand(0).setReg(Reg);
+ DBI->getDebugOperandForReg(DefReg)->setReg(Reg);
}
using MMOList = SmallVector<const MachineMemOperand *, 2>;
nextI = std::next(I); // I is invalidated by the setReg
MachineInstr *UseMI = &*I;
if (UseMI->isDebugValue())
- UseMI->getOperand(0).setReg(0U);
+ UseMI->getDebugOperandForReg(Reg)->setReg(0U);
}
}
MI.getDebugLoc()->getInlinedAt());
bool SeenBefore = SeenDbgVars.count(Var) != 0;
- MachineOperand &MO = MI.getOperand(0);
+ MachineOperand &MO = MI.getDebugOperand(0);
if (MO.isReg() && MO.getReg().isVirtual())
SeenDbgUsers[MO.getReg()].push_back(SeenDbgUser(&MI, SeenBefore));
// Copy DBG_VALUE operand and set the original to undef. We then check to
// see whether this is something that can be copy-forwarded. If it isn't,
// continue around the loop.
- MachineOperand DbgMO = DbgMI.getOperand(0);
+ MachineOperand &DbgMO = DbgMI.getDebugOperand(0);
const MachineOperand *SrcMO = nullptr, *DstMO = nullptr;
auto CopyOperands = TII.isCopyInstr(SinkInst);
if (PostRA && DbgMO.getReg() != DstMO->getReg())
return false;
- DbgMI.getOperand(0).setReg(SrcMO->getReg());
- DbgMI.getOperand(0).setSubReg(SrcMO->getSubReg());
+ DbgMO.setReg(SrcMO->getReg());
+ DbgMO.setSubReg(SrcMO->getSubReg());
return true;
}
SuccToSinkTo.insert(InsertPos, NewDbgMI);
if (!attemptDebugCopyProp(MI, *DbgMI))
- DbgMI->getOperand(0).setReg(0);
+ DbgMI->setDebugValueUndef();
}
}
// This DBG_VALUE would re-order assignments. If we can't copy-propagate
// it, it can't be recovered. Set it undef.
if (!attemptDebugCopyProp(MI, *DbgMI))
- DbgMI->getOperand(0).setReg(0);
+ DbgMI->setDebugValueUndef();
} else {
DbgUsersToSink.push_back(DbgMI);
}
if (User.getParent() == MI.getParent())
continue;
- assert(User.getOperand(0).isReg() &&
+ assert(User.getDebugOperand(0).isReg() &&
"DBG_VALUE user of vreg, but non reg operand?");
DbgDefUsers.push_back(&User);
}
// Point the users of this copy that are no longer dominated, at the source
// of the copy.
for (auto *User : DbgDefUsers) {
- User->getOperand(0).setReg(MI.getOperand(1).getReg());
- User->getOperand(0).setSubReg(MI.getOperand(1).getSubReg());
+ User->getDebugOperand(0).setReg(MI.getOperand(1).getReg());
+ User->getDebugOperand(0).setSubReg(MI.getOperand(1).getSubReg());
}
}
// We must sink this DBG_VALUE if its operand is sunk. To avoid searching
// for DBG_VALUEs later, record them when they're encountered.
if (MI->isDebugValue()) {
- auto &MO = MI->getOperand(0);
+ auto &MO = MI->getDebugOperand(0);
if (MO.isReg() && Register::isPhysicalRegister(MO.getReg())) {
// Bail if we can already tell the sink would be rejected, rather
// than needlessly accumulating lots of DBG_VALUEs.
break;
if (!MI.isDebugValue() || !MI.getDebugVariable()->isParameter())
continue;
- if (MI.getOperand(0).isFI()) {
+ if (MI.getDebugOperand(0).isFI()) {
// We can only emit valid locations for frame indices after the frame
// setup, so do not stash away them.
FrameIndexValues.push_back(&MI);
bool WithStackValue = true;
DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue);
// Make the DBG_VALUE direct.
- MI.getOperand(1).ChangeToRegister(0, false);
+ MI.getDebugOffset().ChangeToRegister(0, false);
}
DIExpr = DIExpression::prepend(DIExpr, PrependFlags, Offset);
- MI.getOperand(3).setMetadata(DIExpr);
+ MI.getDebugExpressionOp().setMetadata(DIExpr);
continue;
}
}
void RegAllocFast::handleDebugValue(MachineInstr &MI) {
- MachineOperand &MO = MI.getOperand(0);
+ MachineOperand &MO = MI.getDebugOperand(0);
// Ignore DBG_VALUEs that aren't based on virtual registers. These are
// mostly constants and frame indices.
// vreg => DbgValueLoc map.
auto CloseNewDVRange = [this, &ToInsert](SlotIndex Slot) {
for (auto *X : ToInsert)
- DbgVRegToValues[X->getOperand(0).getReg()].push_back({Slot, X});
+ DbgVRegToValues[X->getDebugOperand(0).getReg()].push_back({Slot, X});
ToInsert.clear();
};
SlotIndex CurrentSlot = Slots.getMBBStartIdx(&MBB);
for (auto &MI : MBB) {
- if (MI.isDebugValue() && MI.getOperand(0).isReg() &&
- MI.getOperand(0).getReg().isVirtual()) {
+ if (MI.isDebugValue() && MI.getDebugOperand(0).isReg() &&
+ MI.getDebugOperand(0).getReg().isVirtual()) {
ToInsert.push_back(&MI);
} else if (!MI.isDebugInstr()) {
CurrentSlot = Slots.getInstructionIndex(MI);
// "Other" is live and there is a DBG_VALUE of Reg: test if we should
// set it undef.
if (DbgValueSetIt->first >= SegmentIt->start &&
- DbgValueSetIt->second->getOperand(0).getReg() != 0 &&
+ DbgValueSetIt->second->getDebugOperand(0).getReg() != 0 &&
ShouldUndef(DbgValueSetIt->first)) {
// Mark undef, erase record of this DBG_VALUE to avoid revisiting.
- DbgValueSetIt->second->getOperand(0).setReg(0);
+ DbgValueSetIt->second->setDebugValueUndef();
continue;
}
++DbgValueSetIt;
assert(NOps == 4);
OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
// cast away const; DIetc do not take const operands for some reason.
- OS << cast<DILocalVariable>(MI->getOperand(NOps - 2).getMetadata())
- ->getName();
+ OS << MI->getDebugVariable()->getName();
OS << " <- ";
// Frame address. Currently handles register +- offset only.
- assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
+ assert(MI->getDebugOperand(0).isReg() && MI->isDebugOffsetImm());
OS << '[';
printOperand(MI, 0, OS);
OS << '+';
MI.getOperand(0).setIsDebug();
auto *DIExpr = DIExpression::prepend(
MI.getDebugExpression(), DIExpression::ApplyOffset, Offset);
- MI.getOperand(3).setMetadata(DIExpr);
+ MI.getDebugExpressionOp().setMetadata(DIExpr);
continue;
}
// Special handling of dbg_value instructions.
if (MI->isDebugValue()) {
MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false);
- MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
+ MI->getDebugOffset().ChangeToImmediate(Offset);
return;
}
void WebAssemblyDebugValueManager::updateReg(unsigned Reg) {
for (auto *DBI : DbgValues)
- DBI->getOperand(0).setReg(Reg);
+ DBI->getDebugOperand(0).setReg(Reg);
}
void WebAssemblyDebugValueManager::clone(MachineInstr *Insert,
MachineFunction *MF = MBB->getParent();
for (MachineInstr *DBI : reverse(DbgValues)) {
MachineInstr *Clone = MF->CloneMachineInstr(DBI);
- Clone->getOperand(0).setReg(NewReg);
+ Clone->getDebugOperand(0).setReg(NewReg);
MBB->insert(Insert, Clone);
}
}
void WebAssemblyDebugValueManager::replaceWithLocal(unsigned LocalId) {
for (auto *DBI : DbgValues) {
- MachineOperand &Op = DBI->getOperand(0);
+ MachineOperand &Op = DBI->getDebugOperand(0);
Op.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL, LocalId);
}
}
MachineInstr *X86OptimizeLEAPass::replaceDebugValue(MachineInstr &MI,
unsigned VReg,
int64_t AddrDispShift) {
- DIExpression *Expr = const_cast<DIExpression *>(MI.getDebugExpression());
+ const DIExpression *Expr = MI.getDebugExpression();
if (AddrDispShift != 0)
Expr = DIExpression::prepend(Expr, DIExpression::StackValue, AddrDispShift);