mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 02:33:06 +01: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:
parent
4a1dabde23
commit
e0cb677eb6
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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:
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
|
@ -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>;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
test/CodeGen/MIR/X86/dbg-value-list.mir
Normal file
64
test/CodeGen/MIR/X86/dbg-value-list.mir
Normal 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
|
||||||
|
|
||||||
|
...
|
||||||
|
|
Loading…
Reference in New Issue
Block a user