1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 18:42:46 +02:00

Reapply "[DebugInfo] Add new instruction and DIExpression operator for variadic debug values"

Rewrites test to use correct architecture triple; fixes incorrect
reference in SourceLevelDebugging doc; simplifies `spillReg` behaviour
so as to not be dependent on changes elsewhere in the patch stack.

This reverts commit d2000b45d033c06dc7973f59909a0ad12887ff51.
This commit is contained in:
Stephen Tozer 2021-03-04 12:02:28 +00:00
parent 4a1dabde23
commit e0cb677eb6
23 changed files with 467 additions and 139 deletions

View File

@ -5324,6 +5324,14 @@ The current supported opcode vocabulary is limited:
``AsmPrinter`` pass when a call site parameter value ``AsmPrinter`` pass when a call site parameter value
(``DW_AT_call_site_parameter_value``) is represented as entry value (``DW_AT_call_site_parameter_value``) is represented as entry value
of the parameter. of the parameter.
- ``DW_OP_LLVM_arg, N`` is used in debug intrinsics that refer to more than one
value, such as one that calculates the sum of two registers. This is always
used in combination with an ordered list of values, such that
``DW_OP_LLVM_arg, N`` refers to the ``N``th element in that list. For
example, ``!DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_minus,
DW_OP_stack_value)`` used with the list ``(%reg1, %reg2)`` would evaluate to
``%reg1 - reg2``. This list of values should be provided by the containing
intrinsic/instruction.
- ``DW_OP_breg`` (or ``DW_OP_bregx``) represents a content on the provided - ``DW_OP_breg`` (or ``DW_OP_bregx``) represents a content on the provided
signed offset of the specified register. The opcode is only generated by the signed offset of the specified register. The opcode is only generated by the
``AsmPrinter`` pass to describe call site parameter value which requires an ``AsmPrinter`` pass to describe call site parameter value which requires an

View File

@ -576,13 +576,15 @@ the equivalent location is used.
After MIR locations are assigned to each variable, machine pseudo-instructions After MIR locations are assigned to each variable, machine pseudo-instructions
corresponding to each ``llvm.dbg.value`` and ``llvm.dbg.addr`` intrinsic are corresponding to each ``llvm.dbg.value`` and ``llvm.dbg.addr`` intrinsic are
inserted. These ``DBG_VALUE`` instructions appear thus: inserted. There are two forms of this type of instruction.
The first form, ``DBG_VALUE``, appears thus:
.. code-block:: text .. code-block:: text
DBG_VALUE %1, $noreg, !123, !DIExpression() DBG_VALUE %1, $noreg, !123, !DIExpression()
And have the following operands: And has the following operands:
* The first operand can record the variable location as a register, * The first operand can record the variable location as a register,
a frame index, an immediate, or the base address register if the original a frame index, an immediate, or the base address register if the original
debug intrinsic referred to memory. ``$noreg`` indicates the variable debug intrinsic referred to memory. ``$noreg`` indicates the variable
@ -594,6 +596,22 @@ And have the following operands:
* Operand 3 is the Variable field of the original debug intrinsic. * Operand 3 is the Variable field of the original debug intrinsic.
* Operand 4 is the Expression field of the original debug intrinsic. * Operand 4 is the Expression field of the original debug intrinsic.
The second form, ``DBG_VALUE_LIST``, appears thus:
.. code-block:: text
DBG_VALUE_LIST !123, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus), %1, %2
And has the following operands:
* The first operand is the Variable field of the original debug intrinsic.
* The second operand is the Expression field of the original debug intrinsic.
* Any number of operands, from the 3rd onwards, record a sequence of variable
location operands, which may take any of the same values as the first
operand of the ``DBG_VALUE`` instruction above. These variable location
operands are inserted into the final DWARF Expression in positions indicated
by the DW_OP_LLVM_arg operator in the `DIExpression
<LangRef.html#diexpression>`.
The position at which the DBG_VALUEs are inserted should correspond to the The position at which the DBG_VALUEs are inserted should correspond to the
positions of their matching ``llvm.dbg.value`` intrinsics in the IR block. As positions of their matching ``llvm.dbg.value`` intrinsics in the IR block. As
with optimization, LLVM aims to preserve the order in which variable with optimization, LLVM aims to preserve the order in which variable

View File

@ -144,6 +144,7 @@ enum LocationAtom {
DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata.
DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata.
DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata. DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata.
DW_OP_LLVM_arg = 0x1005, ///< Only used in LLVM metadata.
}; };
enum TypeKind : uint8_t { enum TypeKind : uint8_t {

View File

@ -420,11 +420,11 @@ public:
/// instruction is indirect; will be an invalid register if this value is /// instruction is indirect; will be an invalid register if this value is
/// not indirect, and an immediate with value 0 otherwise. /// not indirect, and an immediate with value 0 otherwise.
const MachineOperand &getDebugOffset() const { const MachineOperand &getDebugOffset() const {
assert(isDebugValue() && "not a DBG_VALUE"); assert(isNonListDebugValue() && "not a DBG_VALUE");
return getOperand(1); return getOperand(1);
} }
MachineOperand &getDebugOffset() { MachineOperand &getDebugOffset() {
assert(isDebugValue() && "not a DBG_VALUE"); assert(isNonListDebugValue() && "not a DBG_VALUE");
return getOperand(1); return getOperand(1);
} }
@ -439,6 +439,7 @@ public:
/// Return the operand for the complex address expression referenced by /// Return the operand for the complex address expression referenced by
/// this DBG_VALUE instruction. /// this DBG_VALUE instruction.
const MachineOperand &getDebugExpressionOp() const;
MachineOperand &getDebugExpressionOp(); MachineOperand &getDebugExpressionOp();
/// Return the complex address expression referenced by /// Return the complex address expression referenced by
@ -501,26 +502,43 @@ public:
return *(debug_operands().begin() + Index); return *(debug_operands().begin() + Index);
} }
/// Returns a pointer to the operand corresponding to a debug use of Reg, or /// Returns whether this debug value has at least one debug operand with the
/// nullptr if Reg is not used in any debug operand. /// register \p Reg.
const MachineOperand *getDebugOperandForReg(Register Reg) const { bool hasDebugOperandForReg(Register Reg) const {
const MachineOperand *RegOp = return any_of(debug_operands(), [Reg](const MachineOperand &Op) {
find_if(debug_operands(), [Reg](const MachineOperand &Op) { return Op.isReg() && Op.getReg() == Reg;
return Op.isReg() && Op.getReg() == Reg; });
});
return RegOp == adl_end(debug_operands()) ? nullptr : RegOp;
} }
MachineOperand *getDebugOperandForReg(Register Reg) {
MachineOperand *RegOp = /// Returns a range of all of the operands that correspond to a debug use of
find_if(debug_operands(), [Reg](const MachineOperand &Op) { /// \p Reg.
return Op.isReg() && Op.getReg() == Reg; template <typename Operand, typename Instruction>
}); static iterator_range<
return RegOp == adl_end(debug_operands()) ? nullptr : RegOp; filter_iterator<Operand *, std::function<bool(Operand &Op)>>>
getDebugOperandsForReg(Instruction *MI, Register Reg) {
std::function<bool(Operand & Op)> OpUsesReg(
[Reg](Operand &Op) { return Op.isReg() && Op.getReg() == Reg; });
return make_filter_range(MI->debug_operands(), OpUsesReg);
}
iterator_range<filter_iterator<const MachineOperand *,
std::function<bool(const MachineOperand &Op)>>>
getDebugOperandsForReg(Register Reg) const {
return MachineInstr::getDebugOperandsForReg<const MachineOperand,
const MachineInstr>(this, Reg);
}
iterator_range<filter_iterator<MachineOperand *,
std::function<bool(MachineOperand &Op)>>>
getDebugOperandsForReg(Register Reg) {
return MachineInstr::getDebugOperandsForReg<MachineOperand, MachineInstr>(
this, Reg);
}
bool isDebugOperand(const MachineOperand *Op) const {
return Op >= adl_begin(debug_operands()) && Op <= adl_end(debug_operands());
} }
unsigned getDebugOperandIndex(const MachineOperand *Op) const { unsigned getDebugOperandIndex(const MachineOperand *Op) const {
assert(Op >= adl_begin(debug_operands()) && assert(isDebugOperand(Op) && "Expected a debug operand.");
Op <= adl_end(debug_operands()) && "Expected a debug operand.");
return std::distance(adl_begin(debug_operands()), Op); return std::distance(adl_begin(debug_operands()), Op);
} }
@ -600,12 +618,16 @@ public:
/// location for this DBG_VALUE instruction. /// location for this DBG_VALUE instruction.
iterator_range<mop_iterator> debug_operands() { iterator_range<mop_iterator> debug_operands() {
assert(isDebugValue() && "Must be a debug value instruction."); assert(isDebugValue() && "Must be a debug value instruction.");
return make_range(operands_begin(), operands_begin() + 1); return isDebugValueList()
? make_range(operands_begin() + 2, operands_end())
: make_range(operands_begin(), operands_begin() + 1);
} }
/// \copydoc debug_operands() /// \copydoc debug_operands()
iterator_range<const_mop_iterator> debug_operands() const { iterator_range<const_mop_iterator> debug_operands() const {
assert(isDebugValue() && "Must be a debug value instruction."); assert(isDebugValue() && "Must be a debug value instruction.");
return make_range(operands_begin(), operands_begin() + 1); return isDebugValueList()
? make_range(operands_begin() + 2, operands_end())
: make_range(operands_begin(), operands_begin() + 1);
} }
/// Returns a range over all explicit operands that are register definitions. /// Returns a range over all explicit operands that are register definitions.
/// Implicit definition are not included! /// Implicit definition are not included!
@ -1164,7 +1186,15 @@ public:
// True if the instruction represents a position in the function. // True if the instruction represents a position in the function.
bool isPosition() const { return isLabel() || isCFIInstruction(); } bool isPosition() const { return isLabel() || isCFIInstruction(); }
bool isDebugValue() const { return getOpcode() == TargetOpcode::DBG_VALUE; } bool isNonListDebugValue() const {
return getOpcode() == TargetOpcode::DBG_VALUE;
}
bool isDebugValueList() const {
return getOpcode() == TargetOpcode::DBG_VALUE_LIST;
}
bool isDebugValue() const {
return isNonListDebugValue() || isDebugValueList();
}
bool isDebugLabel() const { return getOpcode() == TargetOpcode::DBG_LABEL; } bool isDebugLabel() const { return getOpcode() == TargetOpcode::DBG_LABEL; }
bool isDebugRef() const { return getOpcode() == TargetOpcode::DBG_INSTR_REF; } bool isDebugRef() const { return getOpcode() == TargetOpcode::DBG_INSTR_REF; }
bool isDebugInstr() const { bool isDebugInstr() const {
@ -1174,12 +1204,14 @@ public:
return isDebugInstr() || isPseudoProbe(); return isDebugInstr() || isPseudoProbe();
} }
bool isDebugOffsetImm() const { return getDebugOffset().isImm(); } bool isDebugOffsetImm() const {
return isNonListDebugValue() && getDebugOffset().isImm();
}
/// A DBG_VALUE is indirect iff the location operand is a register and /// A DBG_VALUE is indirect iff the location operand is a register and
/// the offset operand is an immediate. /// the offset operand is an immediate.
bool isIndirectDebugValue() const { bool isIndirectDebugValue() const {
return isDebugValue() && getDebugOperand(0).isReg() && isDebugOffsetImm(); return isDebugOffsetImm() && getDebugOperand(0).isReg();
} }
/// A DBG_VALUE is an entry value iff its debug expression contains the /// A DBG_VALUE is an entry value iff its debug expression contains the
@ -1189,8 +1221,13 @@ public:
/// Return true if the instruction is a debug value which describes a part of /// Return true if the instruction is a debug value which describes a part of
/// a variable as unavailable. /// a variable as unavailable.
bool isUndefDebugValue() const { bool isUndefDebugValue() const {
return isDebugValue() && getDebugOperand(0).isReg() && if (!isDebugValue())
!getDebugOperand(0).getReg().isValid(); return false;
// If any $noreg locations are given, this DV is undef.
for (const MachineOperand &Op : debug_operands())
if (Op.isReg() && !Op.getReg().isValid())
return true;
return false;
} }
bool isPHI() const { bool isPHI() const {
@ -1265,6 +1302,7 @@ public:
case TargetOpcode::EH_LABEL: case TargetOpcode::EH_LABEL:
case TargetOpcode::GC_LABEL: case TargetOpcode::GC_LABEL:
case TargetOpcode::DBG_VALUE: case TargetOpcode::DBG_VALUE:
case TargetOpcode::DBG_VALUE_LIST:
case TargetOpcode::DBG_INSTR_REF: case TargetOpcode::DBG_INSTR_REF:
case TargetOpcode::DBG_LABEL: case TargetOpcode::DBG_LABEL:
case TargetOpcode::LIFETIME_START: case TargetOpcode::LIFETIME_START:

View File

@ -451,9 +451,16 @@ MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL,
/// for a MachineOperand. /// for a MachineOperand.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect, const MCInstrDesc &MCID, bool IsIndirect,
MachineOperand &MO, const MDNode *Variable, const MachineOperand &MO, const MDNode *Variable,
const MDNode *Expr); const MDNode *Expr);
/// This version of the builder builds a DBG_VALUE or DBG_VALUE_LIST intrinsic
/// for a MachineOperand.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
ArrayRef<MachineOperand> MOs,
const MDNode *Variable, const MDNode *Expr);
/// This version of the builder builds a DBG_VALUE intrinsic /// This version of the builder builds a DBG_VALUE intrinsic
/// for either a value in a register or a register-indirect /// for either a value in a register or a register-indirect
/// address and inserts it at position I. /// address and inserts it at position I.
@ -471,6 +478,14 @@ MachineInstrBuilder BuildMI(MachineBasicBlock &BB,
MachineOperand &MO, const MDNode *Variable, MachineOperand &MO, const MDNode *Variable,
const MDNode *Expr); const MDNode *Expr);
/// This version of the builder builds a DBG_VALUE or DBG_VALUE_LIST intrinsic
/// for a machine operand and inserts it at position I.
MachineInstrBuilder BuildMI(MachineBasicBlock &BB,
MachineBasicBlock::iterator I, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
ArrayRef<MachineOperand> MOs,
const MDNode *Variable, const MDNode *Expr);
/// Clone a DBG_VALUE whose value has been spilled to FrameIndex. /// Clone a DBG_VALUE whose value has been spilled to FrameIndex.
MachineInstr *buildDbgValueForSpill(MachineBasicBlock &BB, MachineInstr *buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I, MachineBasicBlock::iterator I,

View File

@ -2771,6 +2771,14 @@ public:
static DIExpression *appendToStack(const DIExpression *Expr, static DIExpression *appendToStack(const DIExpression *Expr,
ArrayRef<uint64_t> Ops); ArrayRef<uint64_t> Ops);
/// Create a copy of \p Expr by appending the given list of \p Ops to each
/// instance of the operand `DW_OP_LLVM_arg, \p ArgNo`. This is used to
/// modify a specific location used by \p Expr, such as when salvaging that
/// location.
static DIExpression *appendOpsToArg(const DIExpression *Expr,
ArrayRef<uint64_t> Ops, unsigned ArgNo,
bool StackValue = false);
/// Create a DIExpression to describe one part of an aggregate variable that /// Create a DIExpression to describe one part of an aggregate variable that
/// is fragmented across multiple Values. The DW_OP_LLVM_fragment operation /// is fragmented across multiple Values. The DW_OP_LLVM_fragment operation
/// will be appended to the elements of \c Expr. If \c Expr already contains /// will be appended to the elements of \c Expr. If \c Expr already contains

View File

@ -77,6 +77,10 @@ HANDLE_TARGET_OPCODE(SUBREG_TO_REG)
/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic /// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic
HANDLE_TARGET_OPCODE(DBG_VALUE) HANDLE_TARGET_OPCODE(DBG_VALUE)
/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic with a variadic
/// list of locations
HANDLE_TARGET_OPCODE(DBG_VALUE_LIST)
/// DBG_INSTR_REF - A mapping of llvm.dbg.value referring to the instruction /// DBG_INSTR_REF - A mapping of llvm.dbg.value referring to the instruction
/// that defines the value, rather than a virtual register. /// that defines the value, rather than a virtual register.
HANDLE_TARGET_OPCODE(DBG_INSTR_REF) HANDLE_TARGET_OPCODE(DBG_INSTR_REF)

View File

@ -1107,6 +1107,12 @@ def DBG_VALUE : StandardPseudoInstruction {
let AsmString = "DBG_VALUE"; let AsmString = "DBG_VALUE";
let hasSideEffects = false; let hasSideEffects = false;
} }
def DBG_VALUE_LIST : StandardPseudoInstruction {
let OutOperandList = (outs);
let InOperandList = (ins variable_ops);
let AsmString = "DBG_VALUE_LIST";
let hasSideEffects = 0;
}
def DBG_INSTR_REF : StandardPseudoInstruction { def DBG_INSTR_REF : StandardPseudoInstruction {
let OutOperandList = (outs); let OutOperandList = (outs);
let InOperandList = (ins variable_ops); let InOperandList = (ins variable_ops);

View File

@ -153,6 +153,8 @@ StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) {
return "DW_OP_LLVM_entry_value"; return "DW_OP_LLVM_entry_value";
case DW_OP_LLVM_implicit_pointer: case DW_OP_LLVM_implicit_pointer:
return "DW_OP_LLVM_implicit_pointer"; return "DW_OP_LLVM_implicit_pointer";
case DW_OP_LLVM_arg:
return "DW_OP_LLVM_arg";
} }
} }
@ -166,6 +168,7 @@ unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) {
.Case("DW_OP_LLVM_tag_offset", DW_OP_LLVM_tag_offset) .Case("DW_OP_LLVM_tag_offset", DW_OP_LLVM_tag_offset)
.Case("DW_OP_LLVM_entry_value", DW_OP_LLVM_entry_value) .Case("DW_OP_LLVM_entry_value", DW_OP_LLVM_entry_value)
.Case("DW_OP_LLVM_implicit_pointer", DW_OP_LLVM_implicit_pointer) .Case("DW_OP_LLVM_implicit_pointer", DW_OP_LLVM_implicit_pointer)
.Case("DW_OP_LLVM_arg", DW_OP_LLVM_arg)
.Default(0); .Default(0);
} }

View File

@ -905,7 +905,7 @@ static void emitKill(const MachineInstr *MI, AsmPrinter &AP) {
/// means the target will need to handle MI in EmitInstruction. /// means the target will need to handle MI in EmitInstruction.
static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
// This code handles only the 4-operand target-independent form. // This code handles only the 4-operand target-independent form.
if (MI->getNumOperands() != 4) if (MI->isNonListDebugValue() && MI->getNumOperands() != 4)
return false; return false;
SmallString<128> Str; SmallString<128> Str;
@ -1228,6 +1228,7 @@ void AsmPrinter::emitFunctionBody() {
emitInlineAsm(&MI); emitInlineAsm(&MI);
break; break;
case TargetOpcode::DBG_VALUE: case TargetOpcode::DBG_VALUE:
case TargetOpcode::DBG_VALUE_LIST:
if (isVerbose()) { if (isVerbose()) {
if (!emitDebugValueComment(&MI, *this)) if (!emitDebugValueComment(&MI, *this))
emitInstruction(&MI); emitInstruction(&MI);

View File

@ -235,7 +235,7 @@ bool LiveRangeShrink::runOnMachineFunction(MachineFunction &MF) {
MachineBasicBlock::iterator EndIter = std::next(MI.getIterator()); MachineBasicBlock::iterator EndIter = std::next(MI.getIterator());
if (MI.getOperand(0).isReg()) if (MI.getOperand(0).isReg())
for (; EndIter != MBB.end() && EndIter->isDebugValue() && for (; EndIter != MBB.end() && EndIter->isDebugValue() &&
EndIter->getDebugOperandForReg(MI.getOperand(0).getReg()); EndIter->hasDebugOperandForReg(MI.getOperand(0).getReg());
++EndIter, ++Next) ++EndIter, ++Next)
IOM[&*EndIter] = NewOrder; IOM[&*EndIter] = NewOrder;
MBB.splice(I, &MBB, MI.getIterator(), EndIter); MBB.splice(I, &MBB, MI.getIterator(), EndIter);

View File

@ -987,7 +987,9 @@ bool MIParser::parse(MachineInstr *&MI) {
Optional<unsigned> TiedDefIdx; Optional<unsigned> TiedDefIdx;
if (parseMachineOperandAndTargetFlags(OpCode, Operands.size(), MO, TiedDefIdx)) if (parseMachineOperandAndTargetFlags(OpCode, Operands.size(), MO, TiedDefIdx))
return true; return true;
if (OpCode == TargetOpcode::DBG_VALUE && MO.isReg()) if ((OpCode == TargetOpcode::DBG_VALUE ||
OpCode == TargetOpcode::DBG_VALUE_LIST) &&
MO.isReg())
MO.setIsDebug(); MO.setIsDebug();
Operands.push_back( Operands.push_back(
ParsedMachineOperand(MO, Loc, Token.location(), TiedDefIdx)); ParsedMachineOperand(MO, Loc, Token.location(), TiedDefIdx));

View File

@ -841,28 +841,35 @@ const DILabel *MachineInstr::getDebugLabel() const {
} }
const MachineOperand &MachineInstr::getDebugVariableOp() const { const MachineOperand &MachineInstr::getDebugVariableOp() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
return getOperand(2); unsigned VariableOp = isDebugValueList() ? 0 : 2;
return getOperand(VariableOp);
} }
MachineOperand &MachineInstr::getDebugVariableOp() { MachineOperand &MachineInstr::getDebugVariableOp() {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
return getOperand(2); unsigned VariableOp = isDebugValueList() ? 0 : 2;
return getOperand(VariableOp);
} }
const DILocalVariable *MachineInstr::getDebugVariable() const { const DILocalVariable *MachineInstr::getDebugVariable() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); return cast<DILocalVariable>(getDebugVariableOp().getMetadata());
return cast<DILocalVariable>(getOperand(2).getMetadata()); }
const MachineOperand &MachineInstr::getDebugExpressionOp() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned ExpressionOp = isDebugValueList() ? 1 : 3;
return getOperand(ExpressionOp);
} }
MachineOperand &MachineInstr::getDebugExpressionOp() { MachineOperand &MachineInstr::getDebugExpressionOp() {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
return getOperand(3); unsigned ExpressionOp = isDebugValueList() ? 1 : 3;
return getOperand(ExpressionOp);
} }
const DIExpression *MachineInstr::getDebugExpression() const { const DIExpression *MachineInstr::getDebugExpression() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); return cast<DIExpression>(getDebugExpressionOp().getMetadata());
return cast<DIExpression>(getOperand(3).getMetadata());
} }
bool MachineInstr::isDebugEntryValue() const { bool MachineInstr::isDebugEntryValue() const {
@ -1712,7 +1719,7 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
OS << " "; OS << " ";
if (isDebugValue() && MO.isMetadata()) { if (isDebugValue() && MO.isMetadata()) {
// Pretty print DBG_VALUE instructions. // Pretty print DBG_VALUE* instructions.
auto *DIV = dyn_cast<DILocalVariable>(MO.getMetadata()); auto *DIV = dyn_cast<DILocalVariable>(MO.getMetadata());
if (DIV && !DIV->getName().empty()) if (DIV && !DIV->getName().empty())
OS << "!\"" << DIV->getName() << '\"'; OS << "!\"" << DIV->getName() << '\"';
@ -2116,8 +2123,8 @@ MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL, MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect, const MCInstrDesc &MCID, bool IsIndirect,
MachineOperand &MO, const MDNode *Variable, const MachineOperand &MO,
const MDNode *Expr) { const MDNode *Variable, const MDNode *Expr) {
assert(isa<DILocalVariable>(Variable) && "not a variable"); assert(isa<DILocalVariable>(Variable) && "not a variable");
assert(cast<DIExpression>(Expr)->isValid() && "not an expression"); assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) && assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
@ -2131,7 +2138,28 @@ MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
else else
MIB.addReg(0U, RegState::Debug); MIB.addReg(0U, RegState::Debug);
return MIB.addMetadata(Variable).addMetadata(Expr); return MIB.addMetadata(Variable).addMetadata(Expr);
} }
MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
ArrayRef<MachineOperand> MOs,
const MDNode *Variable, const MDNode *Expr) {
assert(isa<DILocalVariable>(Variable) && "not a variable");
assert(cast<DIExpression>(Expr)->isValid() && "not an expression");
assert(cast<DILocalVariable>(Variable)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
if (MCID.Opcode == TargetOpcode::DBG_VALUE)
return BuildMI(MF, DL, MCID, IsIndirect, MOs[0], Variable, Expr);
auto MIB = BuildMI(MF, DL, MCID);
MIB.addMetadata(Variable).addMetadata(Expr);
for (const MachineOperand &MO : MOs)
if (MO.isReg())
MIB.addReg(MO.getReg(), RegState::Debug);
else
MIB.add(MO);
return MIB;
}
MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB, MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
MachineBasicBlock::iterator I, MachineBasicBlock::iterator I,
@ -2155,10 +2183,22 @@ MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
return MachineInstrBuilder(MF, *MI); return MachineInstrBuilder(MF, *MI);
} }
MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const DebugLoc &DL, const MCInstrDesc &MCID,
bool IsIndirect, ArrayRef<MachineOperand> MOs,
const MDNode *Variable, const MDNode *Expr) {
MachineFunction &MF = *BB.getParent();
MachineInstr *MI = BuildMI(MF, DL, MCID, IsIndirect, MOs, Variable, Expr);
BB.insert(I, MI);
return MachineInstrBuilder(MF, *MI);
}
/// Compute the new DIExpression to use with a DBG_VALUE for a spill slot. /// Compute the new DIExpression to use with a DBG_VALUE for a spill slot.
/// This prepends DW_OP_deref when spilling an indirect DBG_VALUE. /// This prepends DW_OP_deref when spilling an indirect DBG_VALUE.
static const DIExpression *computeExprForSpill(const MachineInstr &MI) { static const DIExpression *computeExprForSpill(const MachineInstr &MI,
assert(MI.getOperand(0).isReg() && "can't spill non-register"); Register SpillReg) {
assert(MI.hasDebugOperandForReg(SpillReg) && "Spill Reg is not used in MI.");
assert(MI.getDebugVariable()->isValidLocationForIntrinsic(MI.getDebugLoc()) && assert(MI.getDebugVariable()->isValidLocationForIntrinsic(MI.getDebugLoc()) &&
"Expected inlined-at fields to agree"); "Expected inlined-at fields to agree");
@ -2167,6 +2207,14 @@ static const DIExpression *computeExprForSpill(const MachineInstr &MI) {
assert(MI.getDebugOffset().getImm() == 0 && assert(MI.getDebugOffset().getImm() == 0 &&
"DBG_VALUE with nonzero offset"); "DBG_VALUE with nonzero offset");
Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
} else if (MI.isDebugValueList()) {
// We will replace the spilled register with a frame index, so
// immediately deref all references to the spilled register.
std::array<uint64_t, 1> Ops{{dwarf::DW_OP_deref}};
for (const MachineOperand &Op : MI.getDebugOperandsForReg(SpillReg)) {
unsigned OpIdx = MI.getDebugOperandIndex(&Op);
Expr = DIExpression::appendOpsToArg(Expr, Ops, OpIdx);
}
} }
return Expr; return Expr;
} }
@ -2175,18 +2223,32 @@ MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I, MachineBasicBlock::iterator I,
const MachineInstr &Orig, const MachineInstr &Orig,
int FrameIndex) { int FrameIndex) {
const DIExpression *Expr = computeExprForSpill(Orig); Register SpillReg = Orig.getDebugOperand(0).getReg();
return BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc()) const DIExpression *Expr = computeExprForSpill(Orig, SpillReg);
.addFrameIndex(FrameIndex) MachineInstrBuilder NewMI =
.addImm(0U) BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc());
.addMetadata(Orig.getDebugVariable()) // Non-Variadic Operands: Location, Offset, Variable, Expression
.addMetadata(Expr); // Variadic Operands: Variable, Expression, Locations...
if (Orig.isNonListDebugValue())
NewMI.addFrameIndex(FrameIndex).addImm(0U);
NewMI.addMetadata(Orig.getDebugVariable()).addMetadata(Expr);
if (Orig.isDebugValueList()) {
for (const MachineOperand &Op : Orig.debug_operands())
if (Op.isReg() && Op.getReg() == SpillReg)
NewMI.addFrameIndex(FrameIndex);
else
NewMI.add(MachineOperand(Op));
}
return NewMI;
} }
void llvm::updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex) { void llvm::updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex) {
const DIExpression *Expr = computeExprForSpill(Orig); Register SpillReg = Orig.getDebugOperand(0).getReg();
Orig.getDebugOperand(0).ChangeToFrameIndex(FrameIndex); const DIExpression *Expr = computeExprForSpill(Orig, SpillReg);
Orig.getDebugOffset().ChangeToImmediate(0U); if (Orig.isNonListDebugValue())
Orig.getDebugOffset().ChangeToImmediate(0U);
for (MachineOperand &Op : Orig.getDebugOperandsForReg(SpillReg))
Op.ChangeToFrameIndex(FrameIndex);
Orig.getDebugExpressionOp().setMetadata(Expr); Orig.getDebugExpressionOp().setMetadata(Expr);
} }
@ -2201,7 +2263,7 @@ void MachineInstr::collectDebugValues(
DI != DE; ++DI) { DI != DE; ++DI) {
if (!DI->isDebugValue()) if (!DI->isDebugValue())
return; return;
if (DI->getDebugOperandForReg(MI.getOperand(0).getReg())) if (DI->hasDebugOperandForReg(MI.getOperand(0).getReg()))
DbgValues.push_back(&*DI); DbgValues.push_back(&*DI);
} }
} }
@ -2219,14 +2281,15 @@ void MachineInstr::changeDebugValuesDefReg(Register Reg) {
auto *DI = MO.getParent(); auto *DI = MO.getParent();
if (!DI->isDebugValue()) if (!DI->isDebugValue())
continue; continue;
if (DI->getDebugOperandForReg(DefReg)) { if (DI->hasDebugOperandForReg(DefReg)) {
DbgValues.push_back(DI); DbgValues.push_back(DI);
} }
} }
// Propagate Reg to debug value instructions. // Propagate Reg to debug value instructions.
for (auto *DBI : DbgValues) for (auto *DBI : DbgValues)
DBI->getDebugOperandForReg(DefReg)->setReg(Reg); for (MachineOperand &Op : DBI->getDebugOperandsForReg(DefReg))
Op.setReg(Reg);
} }
using MMOList = SmallVector<const MachineMemOperand *, 2>; using MMOList = SmallVector<const MachineMemOperand *, 2>;

View File

@ -530,11 +530,11 @@ bool MachineRegisterInfo::isConstantPhysReg(MCRegister PhysReg) const {
/// specified register as undefined which causes the DBG_VALUE to be /// specified register as undefined which causes the DBG_VALUE to be
/// deleted during LiveDebugVariables analysis. /// deleted during LiveDebugVariables analysis.
void MachineRegisterInfo::markUsesInDebugValueAsUndef(Register Reg) const { void MachineRegisterInfo::markUsesInDebugValueAsUndef(Register Reg) const {
// Mark any DBG_VALUE that uses Reg as undef (but don't delete it.) // Mark any DBG_VALUE* that uses Reg as undef (but don't delete it.)
// We use make_early_inc_range because setReg invalidates the iterator. // We use make_early_inc_range because setReg invalidates the iterator.
for (MachineInstr &UseMI : llvm::make_early_inc_range(use_instructions(Reg))) { for (MachineInstr &UseMI : llvm::make_early_inc_range(use_instructions(Reg))) {
if (UseMI.isDebugValue()) if (UseMI.isDebugValue() && UseMI.hasDebugOperandForReg(Reg))
UseMI.getDebugOperandForReg(Reg)->setReg(0U); UseMI.setDebugValueUndef();
} }
} }

View File

@ -1233,23 +1233,33 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
// complex location that is interpreted as being a memory address. // complex location that is interpreted as being a memory address.
// This changes a pointer-valued variable to dereference that pointer, // This changes a pointer-valued variable to dereference that pointer,
// which is incorrect. Fix by adding DW_OP_stack_value. // which is incorrect. Fix by adding DW_OP_stack_value.
unsigned PrependFlags = DIExpression::ApplyOffset;
if (!MI.isIndirectDebugValue() && !DIExpr->isComplex())
PrependFlags |= DIExpression::StackValue;
// If we have DBG_VALUE that is indirect and has a Implicit location if (MI.isNonListDebugValue()) {
// expression need to insert a deref before prepending a Memory unsigned PrependFlags = DIExpression::ApplyOffset;
// location expression. Also after doing this we change the DBG_VALUE if (!MI.isIndirectDebugValue() && !DIExpr->isComplex())
// to be direct. PrependFlags |= DIExpression::StackValue;
if (MI.isIndirectDebugValue() && DIExpr->isImplicit()) {
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, Size}; // If we have DBG_VALUE that is indirect and has a Implicit location
bool WithStackValue = true; // expression need to insert a deref before prepending a Memory
DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue); // location expression. Also after doing this we change the DBG_VALUE
// Make the DBG_VALUE direct. // to be direct.
MI.getDebugOffset().ChangeToRegister(0, false); if (MI.isIndirectDebugValue() && DIExpr->isImplicit()) {
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, Size};
bool WithStackValue = true;
DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue);
// Make the DBG_VALUE direct.
MI.getDebugOffset().ChangeToRegister(0, false);
}
DIExpr = TRI.prependOffsetExpression(DIExpr, PrependFlags, Offset);
} else {
// The debug operand at DebugOpIndex was a frame index at offset
// `Offset`; now the operand has been replaced with the frame
// register, we must add Offset with `register x, plus Offset`.
unsigned DebugOpIndex = MI.getDebugOperandIndex(&MI.getOperand(i));
SmallVector<uint64_t, 3> Ops;
TRI.getOffsetOpcodes(Offset, Ops);
DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, DebugOpIndex);
} }
DIExpr = TRI.prependOffsetExpression(DIExpr, PrependFlags, Offset);
MI.getDebugExpressionOp().setMetadata(DIExpr); MI.getDebugExpressionOp().setMetadata(DIExpr);
continue; continue;
} }

View File

@ -424,9 +424,14 @@ void RegAllocFast::spill(MachineBasicBlock::iterator Before, Register VirtReg,
} }
// Rewrite unassigned dbg_values to use the stack slot. // Rewrite unassigned dbg_values to use the stack slot.
MachineOperand &MO = DBG->getOperand(0); // TODO We can potentially do this for list debug values as well if we know
if (MO.isReg() && MO.getReg() == 0) // how the dbg_values are getting unassigned.
updateDbgValueForSpill(*DBG, FI); if (DBG->isNonListDebugValue()) {
MachineOperand &MO = DBG->getDebugOperand(0);
if (MO.isReg() && MO.getReg() == 0) {
updateDbgValueForSpill(*DBG, FI);
}
}
} }
// Now this register is spilled there is should not be any DBG_VALUE // Now this register is spilled there is should not be any DBG_VALUE
// pointing to this register because they are all pointing to spilled value // pointing to this register because they are all pointing to spilled value
@ -623,8 +628,7 @@ void RegAllocFast::assignDanglingDebugValues(MachineInstr &Definition,
SmallVectorImpl<MachineInstr*> &Dangling = UDBGValIter->second; SmallVectorImpl<MachineInstr*> &Dangling = UDBGValIter->second;
for (MachineInstr *DbgValue : Dangling) { for (MachineInstr *DbgValue : Dangling) {
assert(DbgValue->isDebugValue()); assert(DbgValue->isDebugValue());
MachineOperand &MO = DbgValue->getOperand(0); if (!DbgValue->hasDebugOperandForReg(VirtReg))
if (!MO.isReg())
continue; continue;
// Test whether the physreg survives from the definition to the DBG_VALUE. // Test whether the physreg survives from the definition to the DBG_VALUE.
@ -639,9 +643,11 @@ void RegAllocFast::assignDanglingDebugValues(MachineInstr &Definition,
break; break;
} }
} }
MO.setReg(SetToReg); for (MachineOperand &MO : DbgValue->getDebugOperandsForReg(VirtReg)) {
if (SetToReg != 0) MO.setReg(SetToReg);
MO.setIsRenamable(); if (SetToReg != 0)
MO.setIsRenamable();
}
} }
Dangling.clear(); Dangling.clear();
} }
@ -1360,37 +1366,44 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
} }
void RegAllocFast::handleDebugValue(MachineInstr &MI) { void RegAllocFast::handleDebugValue(MachineInstr &MI) {
MachineOperand &MO = MI.getDebugOperand(0); SmallSet<Register, 4> SeenRegisters;
for (MachineOperand &MO : MI.debug_operands()) {
// Ignore DBG_VALUEs that aren't based on virtual registers. These are
// mostly constants and frame indices.
if (!MO.isReg())
continue;
Register Reg = MO.getReg();
if (!Register::isVirtualRegister(Reg))
continue;
// Only process each register once per MI, each use of that register will
// be updated if necessary.
if (!SeenRegisters.insert(Reg).second)
continue;
// Ignore DBG_VALUEs that aren't based on virtual registers. These are // Already spilled to a stackslot?
// mostly constants and frame indices. int SS = StackSlotForVirtReg[Reg];
if (!MO.isReg()) if (SS != -1) {
return; // Modify DBG_VALUE now that the value is in a spill slot.
Register Reg = MO.getReg(); updateDbgValueForSpill(MI, SS);
if (!Register::isVirtualRegister(Reg)) LLVM_DEBUG(dbgs() << "Rewrite DBG_VALUE for spilled memory: " << MI);
return; continue;
}
// Already spilled to a stackslot? // See if this virtual register has already been allocated to a physical
int SS = StackSlotForVirtReg[Reg]; // register or spilled to a stack slot.
if (SS != -1) { LiveRegMap::iterator LRI = findLiveVirtReg(Reg);
// Modify DBG_VALUE now that the value is in a spill slot. if (LRI != LiveVirtRegs.end() && LRI->PhysReg) {
updateDbgValueForSpill(MI, SS); // Update every use of Reg within MI.
LLVM_DEBUG(dbgs() << "Rewrite DBG_VALUE for spilled memory: " << MI); for (auto &RegMO : MI.getDebugOperandsForReg(Reg))
return; setPhysReg(MI, RegMO, LRI->PhysReg);
} else {
DanglingDbgValues[Reg].push_back(&MI);
}
// If Reg hasn't been spilled, put this DBG_VALUE in LiveDbgValueMap so
// that future spills of Reg will have DBG_VALUEs.
LiveDbgValueMap[Reg].push_back(&MI);
} }
// See if this virtual register has already been allocated to a physical
// register or spilled to a stack slot.
LiveRegMap::iterator LRI = findLiveVirtReg(Reg);
if (LRI != LiveVirtRegs.end() && LRI->PhysReg) {
setPhysReg(MI, MO, LRI->PhysReg);
} else {
DanglingDbgValues[Reg].push_back(&MI);
}
// If Reg hasn't been spilled, put this DBG_VALUE in LiveDbgValueMap so
// that future spills of Reg will have DBG_VALUEs.
LiveDbgValueMap[Reg].push_back(&MI);
} }
void RegAllocFast::handleBundle(MachineInstr &MI) { void RegAllocFast::handleBundle(MachineInstr &MI) {
@ -1472,13 +1485,12 @@ void RegAllocFast::allocateBasicBlock(MachineBasicBlock &MBB) {
for (auto &UDBGPair : DanglingDbgValues) { for (auto &UDBGPair : DanglingDbgValues) {
for (MachineInstr *DbgValue : UDBGPair.second) { for (MachineInstr *DbgValue : UDBGPair.second) {
assert(DbgValue->isDebugValue() && "expected DBG_VALUE"); assert(DbgValue->isDebugValue() && "expected DBG_VALUE");
MachineOperand &MO = DbgValue->getOperand(0);
// Nothing to do if the vreg was spilled in the meantime. // Nothing to do if the vreg was spilled in the meantime.
if (!MO.isReg()) if (!DbgValue->hasDebugOperandForReg(UDBGPair.first))
continue; continue;
LLVM_DEBUG(dbgs() << "Register did not survive for " << *DbgValue LLVM_DEBUG(dbgs() << "Register did not survive for " << *DbgValue
<< '\n'); << '\n');
MO.setReg(0); DbgValue->setDebugValueUndef();
} }
} }
DanglingDbgValues.clear(); DanglingDbgValues.clear();

View File

@ -1059,6 +1059,7 @@ unsigned DIExpression::ExprOperand::getSize() const {
case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus_uconst:
case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_LLVM_entry_value: case dwarf::DW_OP_LLVM_entry_value:
case dwarf::DW_OP_LLVM_arg:
case dwarf::DW_OP_regx: case dwarf::DW_OP_regx:
return 2; return 2;
default: default:
@ -1115,6 +1116,7 @@ bool DIExpression::isValid() const {
} }
case dwarf::DW_OP_LLVM_implicit_pointer: case dwarf::DW_OP_LLVM_implicit_pointer:
case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_convert:
case dwarf::DW_OP_LLVM_arg:
case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_constu: case dwarf::DW_OP_constu:
case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus_uconst:
@ -1270,6 +1272,30 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags,
return prependOpcodes(Expr, Ops, StackValue, EntryValue); return prependOpcodes(Expr, Ops, StackValue, EntryValue);
} }
DIExpression *DIExpression::appendOpsToArg(const DIExpression *Expr,
ArrayRef<uint64_t> Ops,
unsigned ArgNo, bool StackValue) {
assert(Expr && "Can't add ops to this expression");
// Handle non-variadic intrinsics by prepending the opcodes.
if (!any_of(Expr->expr_ops(),
[](auto Op) { return Op.getOp() == dwarf::DW_OP_LLVM_arg; })) {
assert(ArgNo == 0 &&
"Location Index must be 0 for a non-variadic expression.");
SmallVector<uint64_t, 8> NewOps(Ops.begin(), Ops.end());
return DIExpression::prependOpcodes(Expr, NewOps, StackValue);
}
SmallVector<uint64_t, 8> NewOps;
for (auto Op : Expr->expr_ops()) {
Op.appendToVector(NewOps);
if (Op.getOp() == dwarf::DW_OP_LLVM_arg && Op.getArg(0) == ArgNo)
NewOps.insert(NewOps.end(), Ops.begin(), Ops.end());
}
return DIExpression::get(Expr->getContext(), NewOps);
}
DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr, DIExpression *DIExpression::prependOpcodes(const DIExpression *Expr,
SmallVectorImpl<uint64_t> &Ops, SmallVectorImpl<uint64_t> &Ops,
bool StackValue, bool StackValue,

View File

@ -1210,7 +1210,8 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
} }
break; break;
case AArch64::DBG_VALUE: { case AArch64::DBG_VALUE:
case AArch64::DBG_VALUE_LIST: {
if (isVerbose() && OutStreamer->hasRawTextSupport()) { if (isVerbose() && OutStreamer->hasRawTextSupport()) {
SmallString<128> TmpStr; SmallString<128> TmpStr;
raw_svector_ostream OS(TmpStr); raw_svector_ostream OS(TmpStr);
@ -1231,7 +1232,7 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
OutStreamer->emitCFIBKeyFrame(); OutStreamer->emitCFIBKeyFrame();
return; return;
} }
} }
// Tail calls use pseudo instructions so they have the proper code-gen // Tail calls use pseudo instructions so they have the proper code-gen
// attributes (isCall, isReturn, etc.). We lower them to the real // attributes (isCall, isReturn, etc.). We lower them to the real

View File

@ -65,16 +65,25 @@ bool NVPTXPrologEpilogPass::runOnMachineFunction(MachineFunction &MF) {
// way with simply the frame index and offset rather than any // way with simply the frame index and offset rather than any
// target-specific addressing mode. // target-specific addressing mode.
if (MI.isDebugValue()) { if (MI.isDebugValue()) {
assert(i == 0 && "Frame indices can only appear as the first " MachineOperand &Op = MI.getOperand(i);
"operand of a DBG_VALUE machine instruction"); assert(
MI.isDebugOperand(&Op) &&
"Frame indices can only appear as a debug operand in a DBG_VALUE*"
" machine instruction");
Register Reg; Register Reg;
int64_t Offset = auto Offset =
TFI.getFrameIndexReference(MF, MI.getOperand(0).getIndex(), Reg) TFI.getFrameIndexReference(MF, Op.getIndex(), Reg);
.getFixed(); Op.ChangeToRegister(Reg, /*isDef=*/false);
MI.getOperand(0).ChangeToRegister(Reg, /*isDef=*/false); Op.setIsDebug();
MI.getOperand(0).setIsDebug(); const DIExpression *DIExpr = MI.getDebugExpression();
auto *DIExpr = DIExpression::prepend( if (MI.isNonListDebugValue()) {
MI.getDebugExpression(), DIExpression::ApplyOffset, Offset); DIExpr = TRI.prependOffsetExpression(MI.getDebugExpression(), DIExpression::ApplyOffset, Offset);
} else {
SmallVector<uint64_t, 3> Ops;
TRI.getOffsetOpcodes(Offset, Ops);
unsigned OpIdx = MI.getDebugOperandIndex(&Op);
DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, OpIdx);
}
MI.getDebugExpressionOp().setMetadata(DIExpr); MI.getDebugExpressionOp().setMetadata(DIExpr);
continue; continue;
} }

View File

@ -9,12 +9,13 @@
#include "SystemZRegisterInfo.h" #include "SystemZRegisterInfo.h"
#include "SystemZInstrInfo.h" #include "SystemZInstrInfo.h"
#include "SystemZSubtarget.h" #include "SystemZSubtarget.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/VirtRegMap.h" #include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/IR/DebugInfoMetadata.h"
using namespace llvm; using namespace llvm;
@ -273,7 +274,16 @@ SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
// Special handling of dbg_value instructions. // Special handling of dbg_value instructions.
if (MI->isDebugValue()) { if (MI->isDebugValue()) {
MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false); MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false);
MI->getDebugOffset().ChangeToImmediate(Offset); if (MI->isNonListDebugValue()) {
MI->getDebugOffset().ChangeToImmediate(Offset);
} else {
unsigned OpIdx = MI->getDebugOperandIndex(&MI->getOperand(FIOperandNum));
SmallVector<uint64_t, 3> Ops;
DIExpression::appendOffset(
Ops, TFI->getFrameIndexReference(MF, FrameIndex, BasePtr).getFixed());
MI->getDebugExpressionOp().setMetadata(
DIExpression::appendOpsToArg(MI->getDebugExpression(), Ops, OpIdx));
}
return; return;
} }

View File

@ -30,7 +30,7 @@ WebAssemblyDebugValueManager::WebAssemblyDebugValueManager(
for (MachineBasicBlock::iterator DE = Instr->getParent()->end(); DI != DE; for (MachineBasicBlock::iterator DE = Instr->getParent()->end(); DI != DE;
++DI) { ++DI) {
if (DI->isDebugValue() && if (DI->isDebugValue() &&
DI->getDebugOperandForReg(Instr->getOperand(0).getReg())) DI->hasDebugOperandForReg(Instr->getOperand(0).getReg()))
DbgValues.push_back(&*DI); DbgValues.push_back(&*DI);
} }
} }

View File

@ -295,8 +295,8 @@ private:
/// Replace debug value MI with a new debug value instruction using register /// Replace debug value MI with a new debug value instruction using register
/// VReg with an appropriate offset and DIExpression to incorporate the /// VReg with an appropriate offset and DIExpression to incorporate the
/// address displacement AddrDispShift. Return new debug value instruction. /// address displacement AddrDispShift. Return new debug value instruction.
MachineInstr *replaceDebugValue(MachineInstr &MI, unsigned VReg, MachineInstr *replaceDebugValue(MachineInstr &MI, unsigned OldReg,
int64_t AddrDispShift); unsigned NewReg, int64_t AddrDispShift);
/// Removes LEAs which calculate similar addresses. /// Removes LEAs which calculate similar addresses.
bool removeRedundantLEAs(MemOpMap &LEAs); bool removeRedundantLEAs(MemOpMap &LEAs);
@ -576,21 +576,50 @@ bool X86OptimizeLEAPass::removeRedundantAddrCalc(MemOpMap &LEAs) {
} }
MachineInstr *X86OptimizeLEAPass::replaceDebugValue(MachineInstr &MI, MachineInstr *X86OptimizeLEAPass::replaceDebugValue(MachineInstr &MI,
unsigned VReg, unsigned OldReg,
unsigned NewReg,
int64_t AddrDispShift) { int64_t AddrDispShift) {
const DIExpression *Expr = MI.getDebugExpression(); const DIExpression *Expr = MI.getDebugExpression();
if (AddrDispShift != 0) if (AddrDispShift != 0) {
Expr = DIExpression::prepend(Expr, DIExpression::StackValue, AddrDispShift); if (MI.isNonListDebugValue()) {
Expr =
DIExpression::prepend(Expr, DIExpression::StackValue, AddrDispShift);
} else {
// Update the Expression, appending an offset of `AddrDispShift` to the
// Op corresponding to `OldReg`.
SmallVector<uint64_t, 3> Ops;
DIExpression::appendOffset(Ops, AddrDispShift);
for (MachineOperand &Op : MI.getDebugOperandsForReg(OldReg)) {
unsigned OpIdx = MI.getDebugOperandIndex(&Op);
Expr = DIExpression::appendOpsToArg(Expr, Ops, OpIdx);
}
}
}
// Replace DBG_VALUE instruction with modified version. // Replace DBG_VALUE instruction with modified version.
MachineBasicBlock *MBB = MI.getParent(); MachineBasicBlock *MBB = MI.getParent();
DebugLoc DL = MI.getDebugLoc(); DebugLoc DL = MI.getDebugLoc();
bool IsIndirect = MI.isIndirectDebugValue(); bool IsIndirect = MI.isIndirectDebugValue();
const MDNode *Var = MI.getDebugVariable(); const MDNode *Var = MI.getDebugVariable();
unsigned Opcode = MI.isNonListDebugValue() ? TargetOpcode::DBG_VALUE
: TargetOpcode::DBG_VALUE_LIST;
if (IsIndirect) if (IsIndirect)
assert(MI.getOperand(1).getImm() == 0 && "DBG_VALUE with nonzero offset"); assert(MI.getDebugOffset().getImm() == 0 &&
return BuildMI(*MBB, MBB->erase(&MI), DL, TII->get(TargetOpcode::DBG_VALUE), "DBG_VALUE with nonzero offset");
IsIndirect, VReg, Var, Expr); SmallVector<MachineOperand, 4> NewOps;
// If we encounter an operand using the old register, replace it with an
// operand that uses the new register; otherwise keep the old operand.
auto replaceOldReg = [OldReg, NewReg](const MachineOperand &Op) {
if (Op.isReg() && Op.getReg() == OldReg)
return MachineOperand::CreateReg(NewReg, false, false, false, false,
false, false, false, false, 0,
/*IsRenamable*/ true);
return Op;
};
for (const MachineOperand &Op : MI.debug_operands())
NewOps.push_back(replaceOldReg(Op));
return BuildMI(*MBB, MBB->erase(&MI), DL, TII->get(Opcode), IsIndirect,
NewOps, Var, Expr);
} }
// Try to find similar LEAs in the list and replace one with another. // Try to find similar LEAs in the list and replace one with another.
@ -635,7 +664,7 @@ bool X86OptimizeLEAPass::removeRedundantLEAs(MemOpMap &LEAs) {
// Replace DBG_VALUE instruction with modified version using the // Replace DBG_VALUE instruction with modified version using the
// register from the replacing LEA and the address displacement // register from the replacing LEA and the address displacement
// between the LEA instructions. // between the LEA instructions.
replaceDebugValue(MI, FirstVReg, AddrDispShift); replaceDebugValue(MI, LastVReg, FirstVReg, AddrDispShift);
continue; continue;
} }

View File

@ -0,0 +1,64 @@
# RUN: llc -march=x86-64 -run-pass machineverifier -o - %s | FileCheck %s
# Simple round-trip test for DBG_VALUE_LIST.
# CHECK: [[VAR_C:![0-9]+]] = !DILocalVariable(name: "c"
# CHECK: DBG_VALUE_LIST [[VAR_C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), $edi, $esi, debug-location
--- |
; ModuleID = 'test.cpp'
source_filename = "test.cpp"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: norecurse nounwind readnone uwtable
define dso_local i32 @_Z3fooii(i32 %a, i32 %b) local_unnamed_addr !dbg !7 {
entry:
call void @llvm.dbg.value(metadata i32 %a, metadata !12, metadata !DIExpression()), !dbg !15
call void @llvm.dbg.value(metadata i32 %b, metadata !13, metadata !DIExpression()), !dbg !15
call void @llvm.dbg.value(metadata i32 undef, metadata !14, metadata !DIExpression()), !dbg !15
%mul = mul nsw i32 %b, %a, !dbg !16
ret i32 %mul, !dbg !17
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.value(metadata, metadata, metadata)
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.cpp", directory: "/")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{!"clang version 11.0.0"}
!7 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooii", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !10, !10}
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{!12, !13, !14}
!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 2, type: !10)
!13 = !DILocalVariable(name: "b", arg: 2, scope: !7, file: !1, line: 2, type: !10)
!14 = !DILocalVariable(name: "c", scope: !7, file: !1, line: 3, type: !10)
!15 = !DILocation(line: 0, scope: !7)
!16 = !DILocation(line: 4, column: 12, scope: !7)
!17 = !DILocation(line: 4, column: 3, scope: !7)
...
---
name: _Z3fooii
body: |
bb.0.entry:
liveins: $edi, $esi
DBG_VALUE $edi, $noreg, !12, !DIExpression(), debug-location !15
DBG_VALUE $esi, $noreg, !13, !DIExpression(), debug-location !15
$eax = MOV32rr $edi
DBG_VALUE_LIST !14, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), $edi, $esi, debug-location !15
DBG_VALUE $esi, $noreg, !13, !DIExpression(), debug-location !15
DBG_VALUE $eax, $noreg, !12, !DIExpression(), debug-location !15
renamable $eax = nsw IMUL32rr killed renamable $eax, killed renamable $esi, implicit-def dead $eflags, debug-location !16
RETQ $eax, debug-location !17
...