From: gbtozers Date: Fri, 11 Sep 2020 14:58:01 +0000 (+0100) Subject: [DebugInfo] Add new instruction and DIExpression operator for variadic debug values X-Git-Tag: llvmorg-14-init~13403 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d07f106f4a48b6e941266525b6f7177834d7b74e;p=platform%2Fupstream%2Fllvm.git [DebugInfo] Add new instruction and DIExpression operator for variadic debug values This patch adds a new instruction that can represent variadic debug values, DBG_VALUE_VAR. This patch alone covers the addition of the instruction and a set of basic code changes in MachineInstr and a few adjacent areas, but does not correctly handle variadic debug values outside of these areas, nor does it generate them at any point. The new instruction is similar to the existing DBG_VALUE instruction, with the following differences: the operands are in a different order, any number of values may be used in the instruction following the Variable and Expression operands (these are referred to in code as “debug operands”) and are indexed from 0 so that getDebugOperand(X) == getOperand(X+2), and the Expression in a DBG_VALUE_VAR must use the DW_OP_LLVM_arg operator to pass arguments into the expression. The new DW_OP_LLVM_arg operator is only valid in expressions appearing in a DBG_VALUE_VAR; it takes a single argument and pushes the debug operand at the index given by the argument onto the Expression stack. For example the sub-expression `DW_OP_LLVM_arg, 0` has the meaning “Push the debug operand at index 0 onto the expression stack.” Differential Revision: https://reviews.llvm.org/D82363 --- diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index fef7a2a..06194da 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5311,6 +5311,14 @@ 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 diff --git a/llvm/docs/SourceLevelDebugging.rst b/llvm/docs/SourceLevelDebugging.rst index e5984cd..357f720 100644 --- a/llvm/docs/SourceLevelDebugging.rst +++ b/llvm/docs/SourceLevelDebugging.rst @@ -576,13 +576,15 @@ 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. 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 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, a frame index, an immediate, or the base address register if the original 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 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 diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h index 765d5d6..a725aff 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.h +++ b/llvm/include/llvm/BinaryFormat/Dwarf.h @@ -144,6 +144,7 @@ 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 { diff --git a/llvm/include/llvm/CodeGen/MachineInstr.h b/llvm/include/llvm/CodeGen/MachineInstr.h index c4ddd05..6071f73 100644 --- a/llvm/include/llvm/CodeGen/MachineInstr.h +++ b/llvm/include/llvm/CodeGen/MachineInstr.h @@ -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(isDebugValue() && "not a DBG_VALUE"); + assert(isNonListDebugValue() && "not a DBG_VALUE"); return getOperand(1); } MachineOperand &getDebugOffset() { - assert(isDebugValue() && "not a DBG_VALUE"); + assert(isNonListDebugValue() && "not a DBG_VALUE"); return getOperand(1); } @@ -439,6 +439,7 @@ 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 @@ -501,26 +502,43 @@ public: return *(debug_operands().begin() + Index); } - /// Returns a pointer to the operand corresponding to a debug use of Reg, or - /// nullptr if Reg is not used in any debug operand. - const MachineOperand *getDebugOperandForReg(Register Reg) const { - const MachineOperand *RegOp = - find_if(debug_operands(), [Reg](const MachineOperand &Op) { - return Op.isReg() && Op.getReg() == Reg; - }); - return RegOp == adl_end(debug_operands()) ? nullptr : RegOp; + /// 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; + }); } - 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; + + /// Returns a range of all of the operands that correspond to a debug use of + /// \p Reg. + template + static iterator_range< + filter_iterator>> + getDebugOperandsForReg(Instruction *MI, Register Reg) { + std::function OpUsesReg( + [Reg](Operand &Op) { return Op.isReg() && Op.getReg() == Reg; }); + return make_filter_range(MI->debug_operands(), OpUsesReg); + } + iterator_range>> + getDebugOperandsForReg(Register Reg) const { + return MachineInstr::getDebugOperandsForReg(this, Reg); + } + iterator_range>> + getDebugOperandsForReg(Register Reg) { + return MachineInstr::getDebugOperandsForReg( + 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 { - assert(Op >= adl_begin(debug_operands()) && - Op <= adl_end(debug_operands()) && "Expected a debug operand."); + assert(isDebugOperand(Op) && "Expected a debug operand."); return std::distance(adl_begin(debug_operands()), Op); } @@ -600,12 +618,16 @@ public: /// location for this DBG_VALUE instruction. iterator_range debug_operands() { 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() iterator_range debug_operands() const { 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. /// Implicit definition are not included! @@ -1164,7 +1186,15 @@ public: // True if the instruction represents a position in the function. 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 isDebugRef() const { return getOpcode() == TargetOpcode::DBG_INSTR_REF; } bool isDebugInstr() const { @@ -1174,12 +1204,14 @@ public: 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 /// the offset operand is an immediate. 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 @@ -1189,8 +1221,13 @@ public: /// Return true if the instruction is a debug value which describes a part of /// a variable as unavailable. bool isUndefDebugValue() const { - return isDebugValue() && getDebugOperand(0).isReg() && - !getDebugOperand(0).getReg().isValid(); + 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; } bool isPHI() const { @@ -1265,6 +1302,7 @@ 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: diff --git a/llvm/include/llvm/CodeGen/MachineInstrBuilder.h b/llvm/include/llvm/CodeGen/MachineInstrBuilder.h index 115c501..18786b7 100644 --- a/llvm/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/llvm/include/llvm/CodeGen/MachineInstrBuilder.h @@ -451,9 +451,16 @@ MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, /// for a MachineOperand. MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID, bool IsIndirect, - MachineOperand &MO, const MDNode *Variable, + const 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 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. @@ -471,14 +478,23 @@ 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 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); + const MachineInstr &Orig, int FrameIndex, + Register SpillReg); /// 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); +void updateDbgValueForSpill(MachineInstr &Orig, int FrameIndex, Register Reg); inline unsigned getDefRegState(bool B) { return B ? RegState::Define : 0; diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index a82418f..9cfcdba 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -2775,6 +2775,14 @@ public: static DIExpression *appendToStack(const DIExpression *Expr, ArrayRef 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 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 diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index 04d41a4..63964b4 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -77,6 +77,10 @@ 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) diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index 332de74..1f0f897 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -1107,6 +1107,12 @@ 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); diff --git a/llvm/lib/BinaryFormat/Dwarf.cpp b/llvm/lib/BinaryFormat/Dwarf.cpp index e474736..c884257 100644 --- a/llvm/lib/BinaryFormat/Dwarf.cpp +++ b/llvm/lib/BinaryFormat/Dwarf.cpp @@ -153,6 +153,8 @@ 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"; } } @@ -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_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); } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 9eaf486..37d8798 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -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->getNumOperands() != 4) + if (MI->isNonListDebugValue() && MI->getNumOperands() != 4) return false; SmallString<128> Str; @@ -1228,6 +1228,7 @@ void AsmPrinter::emitFunctionBody() { emitInlineAsm(&MI); break; case TargetOpcode::DBG_VALUE: + case TargetOpcode::DBG_VALUE_LIST: if (isVerbose()) { if (!emitDebugValueComment(&MI, *this)) emitInstruction(&MI); diff --git a/llvm/lib/CodeGen/InlineSpiller.cpp b/llvm/lib/CodeGen/InlineSpiller.cpp index 7c28023..4635daf 100644 --- a/llvm/lib/CodeGen/InlineSpiller.cpp +++ b/llvm/lib/CodeGen/InlineSpiller.cpp @@ -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); + buildDbgValueForSpill(*MBB, MI, *MI, StackSlot, Reg); MBB->erase(MI); continue; } diff --git a/llvm/lib/CodeGen/LiveRangeShrink.cpp b/llvm/lib/CodeGen/LiveRangeShrink.cpp index 7fa14fd..6c03a87 100644 --- a/llvm/lib/CodeGen/LiveRangeShrink.cpp +++ b/llvm/lib/CodeGen/LiveRangeShrink.cpp @@ -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->getDebugOperandForReg(MI.getOperand(0).getReg()); + EndIter->hasDebugOperandForReg(MI.getOperand(0).getReg()); ++EndIter, ++Next) IOM[&*EndIter] = NewOrder; MBB.splice(I, &MBB, MI.getIterator(), EndIter); diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp index fe979b9..a3f84f3 100644 --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -987,7 +987,9 @@ bool MIParser::parse(MachineInstr *&MI) { Optional TiedDefIdx; if (parseMachineOperandAndTargetFlags(OpCode, Operands.size(), MO, TiedDefIdx)) return true; - if (OpCode == TargetOpcode::DBG_VALUE && MO.isReg()) + if ((OpCode == TargetOpcode::DBG_VALUE || + OpCode == TargetOpcode::DBG_VALUE_LIST) && + MO.isReg()) MO.setIsDebug(); Operands.push_back( ParsedMachineOperand(MO, Loc, Token.location(), TiedDefIdx)); diff --git a/llvm/lib/CodeGen/MachineInstr.cpp b/llvm/lib/CodeGen/MachineInstr.cpp index 94afaff..c1b04d7 100644 --- a/llvm/lib/CodeGen/MachineInstr.cpp +++ b/llvm/lib/CodeGen/MachineInstr.cpp @@ -841,28 +841,35 @@ const DILabel *MachineInstr::getDebugLabel() const { } const MachineOperand &MachineInstr::getDebugVariableOp() const { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); - return getOperand(2); + assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); + unsigned VariableOp = isDebugValueList() ? 0 : 2; + return getOperand(VariableOp); } MachineOperand &MachineInstr::getDebugVariableOp() { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); - return getOperand(2); + assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); + unsigned VariableOp = isDebugValueList() ? 0 : 2; + return getOperand(VariableOp); } const DILocalVariable *MachineInstr::getDebugVariable() const { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); - return cast(getOperand(2).getMetadata()); + return cast(getDebugVariableOp().getMetadata()); +} + +const MachineOperand &MachineInstr::getDebugExpressionOp() const { + assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); + unsigned ExpressionOp = isDebugValueList() ? 1 : 3; + return getOperand(ExpressionOp); } MachineOperand &MachineInstr::getDebugExpressionOp() { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); - return getOperand(3); + assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE*"); + unsigned ExpressionOp = isDebugValueList() ? 1 : 3; + return getOperand(ExpressionOp); } const DIExpression *MachineInstr::getDebugExpression() const { - assert((isDebugValue() || isDebugRef()) && "not a DBG_VALUE"); - return cast(getOperand(3).getMetadata()); + return cast(getDebugExpressionOp().getMetadata()); } bool MachineInstr::isDebugEntryValue() const { @@ -1712,7 +1719,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(MO.getMetadata()); if (DIV && !DIV->getName().empty()) OS << "!\"" << DIV->getName() << '\"'; @@ -2116,8 +2123,8 @@ MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL, MachineInstrBuilder llvm::BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID, bool IsIndirect, - MachineOperand &MO, const MDNode *Variable, - const MDNode *Expr) { + const MachineOperand &MO, + const MDNode *Variable, const MDNode *Expr) { assert(isa(Variable) && "not a variable"); assert(cast(Expr)->isValid() && "not an expression"); assert(cast(Variable)->isValidLocationForIntrinsic(DL) && @@ -2131,7 +2138,28 @@ 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 MOs, + const MDNode *Variable, const MDNode *Expr) { + assert(isa(Variable) && "not a variable"); + assert(cast(Expr)->isValid() && "not an expression"); + assert(cast(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, @@ -2155,10 +2183,22 @@ 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 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) { - assert(MI.getOperand(0).isReg() && "can't spill non-register"); +static const DIExpression *computeExprForSpill(const MachineInstr &MI, + Register SpillReg) { + assert(MI.hasDebugOperandForReg(SpillReg) && "Spill Reg is not used in MI."); assert(MI.getDebugVariable()->isValidLocationForIntrinsic(MI.getDebugLoc()) && "Expected inlined-at fields to agree"); @@ -2167,6 +2207,14 @@ 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 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; } @@ -2174,19 +2222,32 @@ static const DIExpression *computeExprForSpill(const MachineInstr &MI) { MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB, MachineBasicBlock::iterator I, const MachineInstr &Orig, - 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) { - const DIExpression *Expr = computeExprForSpill(Orig); - Orig.getDebugOperand(0).ChangeToFrameIndex(FrameIndex); - Orig.getDebugOffset().ChangeToImmediate(0U); + 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; +} + +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); Orig.getDebugExpressionOp().setMetadata(Expr); } @@ -2201,7 +2262,7 @@ void MachineInstr::collectDebugValues( DI != DE; ++DI) { if (!DI->isDebugValue()) return; - if (DI->getDebugOperandForReg(MI.getOperand(0).getReg())) + if (DI->hasDebugOperandForReg(MI.getOperand(0).getReg())) DbgValues.push_back(&*DI); } } @@ -2219,14 +2280,15 @@ void MachineInstr::changeDebugValuesDefReg(Register Reg) { auto *DI = MO.getParent(); if (!DI->isDebugValue()) continue; - if (DI->getDebugOperandForReg(DefReg)) { + if (DI->hasDebugOperandForReg(DefReg)) { DbgValues.push_back(DI); } } // Propagate Reg to debug value instructions. for (auto *DBI : DbgValues) - DBI->getDebugOperandForReg(DefReg)->setReg(Reg); + for (MachineOperand &Op : DBI->getDebugOperandsForReg(DefReg)) + Op.setReg(Reg); } using MMOList = SmallVector; diff --git a/llvm/lib/CodeGen/MachineRegisterInfo.cpp b/llvm/lib/CodeGen/MachineRegisterInfo.cpp index d7444ec..58bb866 100644 --- a/llvm/lib/CodeGen/MachineRegisterInfo.cpp +++ b/llvm/lib/CodeGen/MachineRegisterInfo.cpp @@ -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.getDebugOperandForReg(Reg)->setReg(0U); + if (UseMI.isDebugValue() && UseMI.hasDebugOperandForReg(Reg)) + UseMI.setDebugValueUndef(); } } diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp index 84bb292..91c6911 100644 --- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp +++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp @@ -1233,23 +1233,33 @@ 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 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 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); + 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 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 Ops; + TRI.getOffsetOpcodes(Offset, Ops); + DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, DebugOpIndex); + } MI.getDebugExpressionOp().setMetadata(DIExpr); continue; } diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp index 256faa2..79d6762 100644 --- a/llvm/lib/CodeGen/RegAllocFast.cpp +++ b/llvm/lib/CodeGen/RegAllocFast.cpp @@ -408,7 +408,8 @@ void RegAllocFast::spill(MachineBasicBlock::iterator Before, Register VirtReg, // to just reference the stack slot. SmallVectorImpl &LRIDbgValues = LiveDbgValueMap[VirtReg]; for (MachineInstr *DBG : LRIDbgValues) { - MachineInstr *NewDV = buildDbgValueForSpill(*MBB, Before, *DBG, FI); + MachineInstr *NewDV = + buildDbgValueForSpill(*MBB, Before, *DBG, FI, AssignedReg); assert(NewDV->getParent() == MBB && "dangling parent pointer"); (void)NewDV; LLVM_DEBUG(dbgs() << "Inserting debug info due to spill:\n" << *NewDV); @@ -424,9 +425,14 @@ void RegAllocFast::spill(MachineBasicBlock::iterator Before, Register VirtReg, } // Rewrite unassigned dbg_values to use the stack slot. - MachineOperand &MO = DBG->getOperand(0); - if (MO.isReg() && MO.getReg() == 0) - updateDbgValueForSpill(*DBG, FI); + // 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); + } + } } // 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 @@ -623,8 +629,7 @@ void RegAllocFast::assignDanglingDebugValues(MachineInstr &Definition, SmallVectorImpl &Dangling = UDBGValIter->second; for (MachineInstr *DbgValue : Dangling) { assert(DbgValue->isDebugValue()); - MachineOperand &MO = DbgValue->getOperand(0); - if (!MO.isReg()) + if (!DbgValue->hasDebugOperandForReg(VirtReg)) continue; // Test whether the physreg survives from the definition to the DBG_VALUE. @@ -639,9 +644,11 @@ void RegAllocFast::assignDanglingDebugValues(MachineInstr &Definition, break; } } - MO.setReg(SetToReg); - if (SetToReg != 0) - MO.setIsRenamable(); + for (MachineOperand &MO : DbgValue->getDebugOperandsForReg(VirtReg)) { + MO.setReg(SetToReg); + if (SetToReg != 0) + MO.setIsRenamable(); + } } Dangling.clear(); } @@ -1360,37 +1367,44 @@ void RegAllocFast::allocateInstruction(MachineInstr &MI) { } void RegAllocFast::handleDebugValue(MachineInstr &MI) { - MachineOperand &MO = MI.getDebugOperand(0); + SmallSet 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 - // mostly constants and frame indices. - if (!MO.isReg()) - return; - Register Reg = MO.getReg(); - if (!Register::isVirtualRegister(Reg)) - return; + // 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; + } - // 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) { + // Update every use of Reg within MI. + for (auto &RegMO : MI.getDebugOperandsForReg(Reg)) + setPhysReg(MI, RegMO, LRI->PhysReg); + } else { + DanglingDbgValues[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); } - - // 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) { @@ -1472,13 +1486,12 @@ 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 (!MO.isReg()) + if (!DbgValue->hasDebugOperandForReg(UDBGPair.first)) continue; LLVM_DEBUG(dbgs() << "Register did not survive for " << *DbgValue << '\n'); - MO.setReg(0); + DbgValue->setDebugValueUndef(); } } DanglingDbgValues.clear(); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 973020c..ba2638e 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1059,6 +1059,7 @@ 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: @@ -1115,6 +1116,7 @@ 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: @@ -1270,6 +1272,30 @@ DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags, return prependOpcodes(Expr, Ops, StackValue, EntryValue); } +DIExpression *DIExpression::appendOpsToArg(const DIExpression *Expr, + ArrayRef 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 NewOps(Ops.begin(), Ops.end()); + return DIExpression::prependOpcodes(Expr, NewOps, StackValue); + } + + SmallVector 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 &Ops, bool StackValue, diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 672efdf..289df8e 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -1210,7 +1210,8 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { } break; - case AArch64::DBG_VALUE: { + case AArch64::DBG_VALUE: + case AArch64::DBG_VALUE_LIST: { if (isVerbose() && OutStreamer->hasRawTextSupport()) { SmallString<128> TmpStr; raw_svector_ostream OS(TmpStr); @@ -1231,7 +1232,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 diff --git a/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp b/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp index 756355f..0c1f741 100644 --- a/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXPrologEpilogPass.cpp @@ -65,16 +65,25 @@ bool NVPTXPrologEpilogPass::runOnMachineFunction(MachineFunction &MF) { // way with simply the frame index and offset rather than any // target-specific addressing mode. if (MI.isDebugValue()) { - assert(i == 0 && "Frame indices can only appear as the first " - "operand of a DBG_VALUE machine instruction"); + MachineOperand &Op = MI.getOperand(i); + assert( + MI.isDebugOperand(&Op) && + "Frame indices can only appear as a debug operand in a DBG_VALUE*" + " machine instruction"); Register Reg; - 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); + 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 Ops; + TRI.getOffsetOpcodes(Offset, Ops); + unsigned OpIdx = MI.getDebugOperandIndex(&Op); + DIExpr = DIExpression::appendOpsToArg(DIExpr, Ops, OpIdx); + } MI.getDebugExpressionOp().setMetadata(DIExpr); continue; } diff --git a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp index 055daf3..da91316 100644 --- a/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZRegisterInfo.cpp @@ -9,12 +9,13 @@ #include "SystemZRegisterInfo.h" #include "SystemZInstrInfo.h" #include "SystemZSubtarget.h" -#include "llvm/CodeGen/LiveIntervals.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/CodeGen/LiveIntervals.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; @@ -273,7 +274,16 @@ SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI, // Special handling of dbg_value instructions. if (MI->isDebugValue()) { 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 Ops; + DIExpression::appendOffset( + Ops, TFI->getFrameIndexReference(MF, FrameIndex, BasePtr).getFixed()); + MI->getDebugExpressionOp().setMetadata( + DIExpression::appendOpsToArg(MI->getDebugExpression(), Ops, OpIdx)); + } return; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp index c63656a..d511fde 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp @@ -30,7 +30,7 @@ WebAssemblyDebugValueManager::WebAssemblyDebugValueManager( for (MachineBasicBlock::iterator DE = Instr->getParent()->end(); DI != DE; ++DI) { if (DI->isDebugValue() && - DI->getDebugOperandForReg(Instr->getOperand(0).getReg())) + DI->hasDebugOperandForReg(Instr->getOperand(0).getReg())) DbgValues.push_back(&*DI); } } diff --git a/llvm/lib/Target/X86/X86OptimizeLEAs.cpp b/llvm/lib/Target/X86/X86OptimizeLEAs.cpp index c8899a8..220fd0b 100644 --- a/llvm/lib/Target/X86/X86OptimizeLEAs.cpp +++ b/llvm/lib/Target/X86/X86OptimizeLEAs.cpp @@ -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 VReg, - int64_t AddrDispShift); + MachineInstr *replaceDebugValue(MachineInstr &MI, unsigned OldReg, + unsigned NewReg, int64_t AddrDispShift); /// Removes LEAs which calculate similar addresses. bool removeRedundantLEAs(MemOpMap &LEAs); @@ -576,21 +576,50 @@ bool X86OptimizeLEAPass::removeRedundantAddrCalc(MemOpMap &LEAs) { } MachineInstr *X86OptimizeLEAPass::replaceDebugValue(MachineInstr &MI, - unsigned VReg, + unsigned OldReg, + unsigned NewReg, int64_t AddrDispShift) { const DIExpression *Expr = MI.getDebugExpression(); - if (AddrDispShift != 0) - Expr = DIExpression::prepend(Expr, DIExpression::StackValue, AddrDispShift); + 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 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. 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.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); + assert(MI.getDebugOffset().getImm() == 0 && + "DBG_VALUE with nonzero offset"); + SmallVector 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. @@ -635,7 +664,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, FirstVReg, AddrDispShift); + replaceDebugValue(MI, LastVReg, FirstVReg, AddrDispShift); continue; } diff --git a/llvm/test/CodeGen/MIR/Generic/dbg-value-list.mir b/llvm/test/CodeGen/MIR/Generic/dbg-value-list.mir new file mode 100644 index 0000000..e17843a --- /dev/null +++ b/llvm/test/CodeGen/MIR/Generic/dbg-value-list.mir @@ -0,0 +1,64 @@ +# 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 + +... +