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

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

This reverts commit d07f106f4a48b6e941266525b6f7177834d7b74e.
This commit is contained in:
Stephen Tozer 2021-03-04 11:59:21 +00:00
parent 7cf2776667
commit 977ffc2c60
24 changed files with 145 additions and 474 deletions

View File

@ -5311,14 +5311,6 @@ The current supported opcode vocabulary is limited:
``AsmPrinter`` pass when a call site parameter value
(``DW_AT_call_site_parameter_value``) is represented as entry value
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
signed offset of the specified register. The opcode is only generated by the
``AsmPrinter`` pass to describe call site parameter value which requires an

View File

@ -576,15 +576,13 @@ the equivalent location is used.
After MIR locations are assigned to each variable, machine pseudo-instructions
corresponding to each ``llvm.dbg.value`` and ``llvm.dbg.addr`` intrinsic are
inserted. There are two forms of this type of instruction.
The first form, ``DBG_VALUE``, appears thus:
inserted. These ``DBG_VALUE`` instructions appear thus:
.. code-block:: text
DBG_VALUE %1, $noreg, !123, !DIExpression()
And has the following operands:
And have the following operands:
* The first operand can record the variable location as a register,
a frame index, an immediate, or the base address register if the original
debug intrinsic referred to memory. ``$noreg`` indicates the variable
@ -596,22 +594,6 @@ And has the following operands:
* Operand 3 is the Variable 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, as described in
:ref:`DIExpression<_DIExpression>`.
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
with optimization, LLVM aims to preserve the order in which variable

View File

@ -144,7 +144,6 @@ enum LocationAtom {
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_implicit_pointer = 0x1004, ///< Only used in LLVM metadata.
DW_OP_LLVM_arg = 0x1005, ///< Only used in LLVM metadata.
};
enum TypeKind : uint8_t {

View File

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

View File

@ -451,16 +451,9 @@ MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL,
/// for a MachineOperand.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
const MachineOperand &MO, const MDNode *Variable,
MachineOperand &MO, const MDNode *Variable,
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
/// for either a value in a register or a register-indirect
/// address and inserts it at position I.
@ -478,23 +471,14 @@ MachineInstrBuilder BuildMI(MachineBasicBlock &BB,
MachineOperand &MO, const MDNode *Variable,
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.
MachineInstr *buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const MachineInstr &Orig, int FrameIndex,
Register SpillReg);
const MachineInstr &Orig, int FrameIndex);
/// Update a DBG_VALUE whose value has been spilled to FrameIndex. Useful when
/// modifying an instruction in place while iterating over a basic block.
void updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex, Register Reg);
void updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex);
inline unsigned getDefRegState(bool B) {
return B ? RegState::Define : 0;

View File

@ -2775,14 +2775,6 @@ public:
static DIExpression *appendToStack(const DIExpression *Expr,
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
/// 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

View File

@ -77,10 +77,6 @@ HANDLE_TARGET_OPCODE(SUBREG_TO_REG)
/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic
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
/// that defines the value, rather than a virtual register.
HANDLE_TARGET_OPCODE(DBG_INSTR_REF)

View File

@ -1107,12 +1107,6 @@ def DBG_VALUE : StandardPseudoInstruction {
let AsmString = "DBG_VALUE";
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 {
let OutOperandList = (outs);
let InOperandList = (ins variable_ops);

View File

@ -153,8 +153,6 @@ StringRef llvm::dwarf::OperationEncodingString(unsigned Encoding) {
return "DW_OP_LLVM_entry_value";
case DW_OP_LLVM_implicit_pointer:
return "DW_OP_LLVM_implicit_pointer";
case DW_OP_LLVM_arg:
return "DW_OP_LLVM_arg";
}
}
@ -168,7 +166,6 @@ unsigned llvm::dwarf::getOperationEncoding(StringRef OperationEncodingString) {
.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_implicit_pointer", DW_OP_LLVM_implicit_pointer)
.Case("DW_OP_LLVM_arg", DW_OP_LLVM_arg)
.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.
static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
// This code handles only the 4-operand target-independent form.
if (MI->isNonListDebugValue() && MI->getNumOperands() != 4)
if (MI->getNumOperands() != 4)
return false;
SmallString<128> Str;
@ -1228,7 +1228,6 @@ void AsmPrinter::emitFunctionBody() {
emitInlineAsm(&MI);
break;
case TargetOpcode::DBG_VALUE:
case TargetOpcode::DBG_VALUE_LIST:
if (isVerbose()) {
if (!emitDebugValueComment(&MI, *this))
emitInstruction(&MI);

View File

@ -1048,7 +1048,7 @@ void InlineSpiller::spillAroundUses(Register Reg) {
// Modify DBG_VALUE now that the value is in a spill slot.
MachineBasicBlock *MBB = MI->getParent();
LLVM_DEBUG(dbgs() << "Modifying debug info due to spill:\t" << *MI);
buildDbgValueForSpill(*MBB, MI, *MI, StackSlot, Reg);
buildDbgValueForSpill(*MBB, MI, *MI, StackSlot);
MBB->erase(MI);
continue;
}

View File

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

View File

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

View File

@ -841,35 +841,28 @@ const DILabel *MachineInstr::getDebugLabel() const {
}
const MachineOperand &MachineInstr::getDebugVariableOp() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned VariableOp = isDebugValueList() ? 0 : 2;
return getOperand(VariableOp);
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE");
return getOperand(2);
}
MachineOperand &MachineInstr::getDebugVariableOp() {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned VariableOp = isDebugValueList() ? 0 : 2;
return getOperand(VariableOp);
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE");
return getOperand(2);
}
const DILocalVariable *MachineInstr::getDebugVariable() const {
return cast<DILocalVariable>(getDebugVariableOp().getMetadata());
}
const MachineOperand &MachineInstr::getDebugExpressionOp() const {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned ExpressionOp = isDebugValueList() ? 1 : 3;
return getOperand(ExpressionOp);
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE");
return cast<DILocalVariable>(getOperand(2).getMetadata());
}
MachineOperand &MachineInstr::getDebugExpressionOp() {
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*");
unsigned ExpressionOp = isDebugValueList() ? 1 : 3;
return getOperand(ExpressionOp);
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE");
return getOperand(3);
}
const DIExpression *MachineInstr::getDebugExpression() const {
return cast<DIExpression>(getDebugExpressionOp().getMetadata());
assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE");
return cast<DIExpression>(getOperand(3).getMetadata());
}
bool MachineInstr::isDebugEntryValue() const {
@ -1719,7 +1712,7 @@ void MachineInstr::print(raw_ostream &OS, ModuleSlotTracker &MST,
OS << " ";
if (isDebugValue() && MO.isMetadata()) {
// Pretty print DBG_VALUE* instructions.
// Pretty print DBG_VALUE instructions.
auto *DIV = dyn_cast<DILocalVariable>(MO.getMetadata());
if (DIV && !DIV->getName().empty())
OS << "!\"" << DIV->getName() << '\"';
@ -2123,8 +2116,8 @@ MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
const MCInstrDesc &MCID, bool IsIndirect,
const MachineOperand &MO,
const MDNode *Variable, const MDNode *Expr) {
MachineOperand &MO, 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) &&
@ -2138,28 +2131,7 @@ MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL,
else
MIB.addReg(0U, RegState::Debug);
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,
MachineBasicBlock::iterator I,
@ -2183,22 +2155,10 @@ MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
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.
/// This prepends DW_OP_deref when spilling an indirect DBG_VALUE.
static const DIExpression *computeExprForSpill(const MachineInstr &MI,
Register SpillReg) {
assert(MI.hasDebugOperandForReg(SpillReg) && "Spill Reg is not used in MI.");
static const DIExpression *computeExprForSpill(const MachineInstr &MI) {
assert(MI.getOperand(0).isReg() && "can't spill non-register");
assert(MI.getDebugVariable()->isValidLocationForIntrinsic(MI.getDebugLoc()) &&
"Expected inlined-at fields to agree");
@ -2207,14 +2167,6 @@ static const DIExpression *computeExprForSpill(const MachineInstr &MI,
assert(MI.getDebugOffset().getImm() == 0 &&
"DBG_VALUE with nonzero offset");
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;
}
@ -2222,32 +2174,19 @@ static const DIExpression *computeExprForSpill(const MachineInstr &MI,
MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const MachineInstr &Orig,
int FrameIndex, Register SpillReg) {
const DIExpression *Expr = computeExprForSpill(Orig, SpillReg);
MachineInstrBuilder NewMI =
BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc());
// Non-Variadic Operands: Location, Offset, Variable, Expression
// 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;
int FrameIndex) {
const DIExpression *Expr = computeExprForSpill(Orig);
return BuildMI(BB, I, Orig.getDebugLoc(), Orig.getDesc())
.addFrameIndex(FrameIndex)
.addImm(0U)
.addMetadata(Orig.getDebugVariable())
.addMetadata(Expr);
}
void llvm::updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex,
Register Reg) {
const DIExpression *Expr = computeExprForSpill(Orig, Reg);
if (Orig.isNonListDebugValue())
Orig.getDebugOffset().ChangeToImmediate(0U);
for (MachineOperand &Op : Orig.getDebugOperandsForReg(Reg))
Op.ChangeToFrameIndex(FrameIndex);
void llvm::updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex) {
const DIExpression *Expr = computeExprForSpill(Orig);
Orig.getDebugOperand(0).ChangeToFrameIndex(FrameIndex);
Orig.getDebugOffset().ChangeToImmediate(0U);
Orig.getDebugExpressionOp().setMetadata(Expr);
}
@ -2262,7 +2201,7 @@ void MachineInstr::collectDebugValues(
DI != DE; ++DI) {
if (!DI->isDebugValue())
return;
if (DI->hasDebugOperandForReg(MI.getOperand(0).getReg()))
if (DI->getDebugOperandForReg(MI.getOperand(0).getReg()))
DbgValues.push_back(&*DI);
}
}
@ -2280,15 +2219,14 @@ void MachineInstr::changeDebugValuesDefReg(Register Reg) {
auto *DI = MO.getParent();
if (!DI->isDebugValue())
continue;
if (DI->hasDebugOperandForReg(DefReg)) {
if (DI->getDebugOperandForReg(DefReg)) {
DbgValues.push_back(DI);
}
}
// Propagate Reg to debug value instructions.
for (auto *DBI : DbgValues)
for (MachineOperand &Op : DBI->getDebugOperandsForReg(DefReg))
Op.setReg(Reg);
DBI->getDebugOperandForReg(DefReg)->setReg(Reg);
}
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
/// deleted during LiveDebugVariables analysis.
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.
for (MachineInstr &UseMI : llvm::make_early_inc_range(use_instructions(Reg))) {
if (UseMI.isDebugValue() && UseMI.hasDebugOperandForReg(Reg))
UseMI.setDebugValueUndef();
if (UseMI.isDebugValue())
UseMI.getDebugOperandForReg(Reg)->setReg(0U);
}
}

View File

@ -1233,33 +1233,23 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
// complex location that is interpreted as being a memory address.
// This changes a pointer-valued variable to dereference that pointer,
// which is incorrect. Fix by adding DW_OP_stack_value.
unsigned PrependFlags = DIExpression::ApplyOffset;
if (!MI.isIndirectDebugValue() && !DIExpr->isComplex())
PrependFlags |= DIExpression::StackValue;
if (MI.isNonListDebugValue()) {
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
// expression need to insert a deref before prepending a Memory
// location expression. Also after doing this we change the DBG_VALUE
// to be direct.
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);
// If we have DBG_VALUE that is indirect and has a Implicit location
// expression need to insert a deref before prepending a Memory
// location expression. Also after doing this we change the DBG_VALUE
// to be direct.
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);
MI.getDebugExpressionOp().setMetadata(DIExpr);
continue;
}

View File

@ -408,8 +408,7 @@ void RegAllocFast::spill(MachineBasicBlock::iterator Before, Register VirtReg,
// to just reference the stack slot.
SmallVectorImpl<MachineInstr *> &LRIDbgValues = LiveDbgValueMap[VirtReg];
for (MachineInstr *DBG : LRIDbgValues) {
MachineInstr *NewDV =
buildDbgValueForSpill(*MBB, Before, *DBG, FI, AssignedReg);
MachineInstr *NewDV = buildDbgValueForSpill(*MBB, Before, *DBG, FI);
assert(NewDV->getParent() == MBB && "dangling parent pointer");
(void)NewDV;
LLVM_DEBUG(dbgs() << "Inserting debug info due to spill:\n" << *NewDV);
@ -425,14 +424,9 @@ void RegAllocFast::spill(MachineBasicBlock::iterator Before, Register VirtReg,
}
// Rewrite unassigned dbg_values to use the stack slot.
// TODO We can potentially do this for list debug values as well if we know
// how the dbg_values are getting unassigned.
if (DBG->isNonListDebugValue()) {
MachineOperand &MO = DBG->getDebugOperand(0);
if (MO.isReg() && MO.getReg() == 0) {
updateDbgValueForSpill(*DBG, FI, 0);
}
}
MachineOperand &MO = DBG->getOperand(0);
if (MO.isReg() && MO.getReg() == 0)
updateDbgValueForSpill(*DBG, FI);
}
// 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
@ -629,7 +623,8 @@ void RegAllocFast::assignDanglingDebugValues(MachineInstr &Definition,
SmallVectorImpl<MachineInstr*> &Dangling = UDBGValIter->second;
for (MachineInstr *DbgValue : Dangling) {
assert(DbgValue->isDebugValue());
if (!DbgValue->hasDebugOperandForReg(VirtReg))
MachineOperand &MO = DbgValue->getOperand(0);
if (!MO.isReg())
continue;
// Test whether the physreg survives from the definition to the DBG_VALUE.
@ -644,11 +639,9 @@ void RegAllocFast::assignDanglingDebugValues(MachineInstr &Definition,
break;
}
}
for (MachineOperand &MO : DbgValue->getDebugOperandsForReg(VirtReg)) {
MO.setReg(SetToReg);
if (SetToReg != 0)
MO.setIsRenamable();
}
MO.setReg(SetToReg);
if (SetToReg != 0)
MO.setIsRenamable();
}
Dangling.clear();
}
@ -1367,44 +1360,37 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) {
}
void RegAllocFast::handleDebugValue(MachineInstr &MI) {
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;
MachineOperand &MO = MI.getDebugOperand(0);
// Already spilled to a stackslot?
int SS = StackSlotForVirtReg[Reg];
if (SS != -1) {
// Modify DBG_VALUE now that the value is in a spill slot.
updateDbgValueForSpill(MI, SS, Reg);
LLVM_DEBUG(dbgs() << "Rewrite DBG_VALUE for spilled memory: " << MI);
continue;
}
// Ignore DBG_VALUEs that aren't based on virtual registers. These are
// mostly constants and frame indices.
if (!MO.isReg())
return;
Register Reg = MO.getReg();
if (!Register::isVirtualRegister(Reg))
return;
// 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) {
// Update every use of Reg within MI.
for (auto &RegMO : MI.getDebugOperandsForReg(Reg))
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);
// Already spilled to a stackslot?
int SS = StackSlotForVirtReg[Reg];
if (SS != -1) {
// Modify DBG_VALUE now that the value is in a spill slot.
updateDbgValueForSpill(MI, SS);
LLVM_DEBUG(dbgs() << "Rewrite DBG_VALUE for spilled memory: " << MI);
return;
}
// 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) {
@ -1486,12 +1472,13 @@ void RegAllocFast::allocateBasicBlock(MachineBasicBlock &MBB) {
for (auto &UDBGPair : DanglingDbgValues) {
for (MachineInstr *DbgValue : UDBGPair.second) {
assert(DbgValue->isDebugValue() && "expected DBG_VALUE");
MachineOperand &MO = DbgValue->getOperand(0);
// Nothing to do if the vreg was spilled in the meantime.
if (!DbgValue->hasDebugOperandForReg(UDBGPair.first))
if (!MO.isReg())
continue;
LLVM_DEBUG(dbgs() << "Register did not survive for " << *DbgValue
<< '\n');
DbgValue->setDebugValueUndef();
MO.setReg(0);
}
}
DanglingDbgValues.clear();

View File

@ -1059,7 +1059,6 @@ unsigned DIExpression::ExprOperand::getSize() const {
case dwarf::DW_OP_plus_uconst:
case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_LLVM_entry_value:
case dwarf::DW_OP_LLVM_arg:
case dwarf::DW_OP_regx:
return 2;
default:
@ -1116,7 +1115,6 @@ bool DIExpression::isValid() const {
}
case dwarf::DW_OP_LLVM_implicit_pointer:
case dwarf::DW_OP_LLVM_convert:
case dwarf::DW_OP_LLVM_arg:
case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_constu:
case dwarf::DW_OP_plus_uconst:
@ -1272,30 +1270,6 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags,
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,
SmallVectorImpl<uint64_t> &Ops,
bool StackValue,

View File

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

View File

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

View File

@ -9,13 +9,12 @@
#include "SystemZRegisterInfo.h"
#include "SystemZInstrInfo.h"
#include "SystemZSubtarget.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/IR/DebugInfoMetadata.h"
using namespace llvm;
@ -274,16 +273,7 @@ SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI,
// Special handling of dbg_value instructions.
if (MI->isDebugValue()) {
MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false);
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));
}
MI->getDebugOffset().ChangeToImmediate(Offset);
return;
}

View File

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

View File

@ -295,8 +295,8 @@ private:
/// Replace debug value MI with a new debug value instruction using register
/// VReg with an appropriate offset and DIExpression to incorporate the
/// address displacement AddrDispShift. Return new debug value instruction.
MachineInstr *replaceDebugValue(MachineInstr &MI, unsigned OldReg,
unsigned NewReg, int64_t AddrDispShift);
MachineInstr *replaceDebugValue(MachineInstr &MI, unsigned VReg,
int64_t AddrDispShift);
/// Removes LEAs which calculate similar addresses.
bool removeRedundantLEAs(MemOpMap &LEAs);
@ -576,50 +576,21 @@ bool X86OptimizeLEAPass::removeRedundantAddrCalc(MemOpMap &LEAs) {
}
MachineInstr *X86OptimizeLEAPass::replaceDebugValue(MachineInstr &MI,
unsigned OldReg,
unsigned NewReg,
unsigned VReg,
int64_t AddrDispShift) {
const DIExpression *Expr = MI.getDebugExpression();
if (AddrDispShift != 0) {
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);
}
}
}
if (AddrDispShift != 0)
Expr = DIExpression::prepend(Expr, DIExpression::StackValue, AddrDispShift);
// Replace DBG_VALUE instruction with modified version.
MachineBasicBlock *MBB = MI.getParent();
DebugLoc DL = MI.getDebugLoc();
bool IsIndirect = MI.isIndirectDebugValue();
const MDNode *Var = MI.getDebugVariable();
unsigned Opcode = MI.isNonListDebugValue() ? TargetOpcode::DBG_VALUE
: TargetOpcode::DBG_VALUE_LIST;
if (IsIndirect)
assert(MI.getDebugOffset().getImm() == 0 &&
"DBG_VALUE with nonzero offset");
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);
assert(MI.getOperand(1).getImm() == 0 && "DBG_VALUE with nonzero offset");
return BuildMI(*MBB, MBB->erase(&MI), DL, TII->get(TargetOpcode::DBG_VALUE),
IsIndirect, VReg, Var, Expr);
}
// Try to find similar LEAs in the list and replace one with another.
@ -664,7 +635,7 @@ bool X86OptimizeLEAPass::removeRedundantLEAs(MemOpMap &LEAs) {
// Replace DBG_VALUE instruction with modified version using the
// register from the replacing LEA and the address displacement
// between the LEA instructions.
replaceDebugValue(MI, LastVReg, FirstVReg, AddrDispShift);
replaceDebugValue(MI, FirstVReg, AddrDispShift);
continue;
}

View File

@ -1,64 +0,0 @@
# RUN: llc -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
...