mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[DebugInstrRef] Create DBG_INSTR_REFs in SelectionDAG
When given the -experimental-debug-variable-locations option (via -Xclang or to llc), have SelectionDAG generate DBG_INSTR_REF instructions instead of DBG_VALUE. For now, this only happens in a limited circumstance: when the value referred to is not a PHI and is defined in the current block. Other situations introduce interesting problems, addresed in later patches. Practically, this patch hooks into InstrEmitter and if it can find a defining instruction for a value, gives it an instruction number, and points the DBG_INSTR_REF at that <instr, operand> pair. Differential Revision: https://reviews.llvm.org/D85747
This commit is contained in:
parent
cef0930eed
commit
75a07ccbc2
@ -695,6 +695,11 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
|
||||
return &*MIB;
|
||||
}
|
||||
|
||||
// Attempt to produce a DBG_INSTR_REF if we've been asked to.
|
||||
if (EmitDebugInstrRefs)
|
||||
if (auto *InstrRef = EmitDbgInstrRef(SD, VRBaseMap))
|
||||
return InstrRef;
|
||||
|
||||
if (SD->getKind() == SDDbgValue::FRAMEIX) {
|
||||
// Stack address; this needs to be lowered in target-dependent fashion.
|
||||
// EmitTargetCodeForFrameDebugValue is responsible for allocation.
|
||||
@ -761,6 +766,63 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
|
||||
return &*MIB;
|
||||
}
|
||||
|
||||
MachineInstr *
|
||||
InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD,
|
||||
DenseMap<SDValue, Register> &VRBaseMap) {
|
||||
// Instruction referencing is still in a prototype state: for now we're only
|
||||
// going to support SDNodes within a block. Copies are not supported, they
|
||||
// don't actually define a value.
|
||||
if (SD->getKind() != SDDbgValue::SDNODE)
|
||||
return nullptr;
|
||||
|
||||
SDNode *Node = SD->getSDNode();
|
||||
SDValue Op = SDValue(Node, SD->getResNo());
|
||||
DenseMap<SDValue, Register>::iterator I = VRBaseMap.find(Op);
|
||||
if (I==VRBaseMap.end())
|
||||
return nullptr; // undef value: let EmitDbgValue produce a DBG_VALUE $noreg.
|
||||
|
||||
MDNode *Var = SD->getVariable();
|
||||
MDNode *Expr = SD->getExpression();
|
||||
DebugLoc DL = SD->getDebugLoc();
|
||||
|
||||
// Try to pick out a defining instruction at this point.
|
||||
unsigned VReg = getVR(Op, VRBaseMap);
|
||||
MachineInstr *ResultInstr = nullptr;
|
||||
|
||||
// No definition corresponds to scenarios where a vreg is live-in to a block,
|
||||
// and doesn't have a defining instruction (yet). This can be patched up
|
||||
// later; at this early stage of implementation, fall back to using DBG_VALUE.
|
||||
if (!MRI->hasOneDef(VReg))
|
||||
return nullptr;
|
||||
|
||||
MachineInstr &DefMI = *MRI->def_instr_begin(VReg);
|
||||
// Some target specific opcodes can become copies. As stated above, we're
|
||||
// ignoring those for now.
|
||||
if (DefMI.isCopy() || DefMI.getOpcode() == TargetOpcode::SUBREG_TO_REG)
|
||||
return nullptr;
|
||||
|
||||
const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF);
|
||||
auto MIB = BuildMI(*MF, DL, RefII);
|
||||
|
||||
// Find the operand which defines the specified VReg.
|
||||
unsigned OperandIdx = 0;
|
||||
for (const auto &MO : DefMI.operands()) {
|
||||
if (MO.isReg() && MO.isDef() && MO.getReg() == VReg)
|
||||
break;
|
||||
++OperandIdx;
|
||||
}
|
||||
assert(OperandIdx < DefMI.getNumOperands());
|
||||
|
||||
// Make the DBG_INSTR_REF refer to that instruction, and that operand.
|
||||
unsigned InstrNum = DefMI.getDebugInstrNum();
|
||||
MIB.addImm(InstrNum);
|
||||
MIB.addImm(OperandIdx);
|
||||
MIB.addMetadata(Var);
|
||||
MIB.addMetadata(Expr);
|
||||
ResultInstr = &*MIB;
|
||||
return ResultInstr;
|
||||
}
|
||||
|
||||
MachineInstr *
|
||||
InstrEmitter::EmitDbgLabel(SDDbgLabel *SD) {
|
||||
MDNode *Label = SD->getLabel();
|
||||
@ -1177,10 +1239,12 @@ EmitSpecialNode(SDNode *Node, bool IsClone, bool IsCloned,
|
||||
|
||||
/// InstrEmitter - Construct an InstrEmitter and set it to start inserting
|
||||
/// at the given position in the given block.
|
||||
InstrEmitter::InstrEmitter(MachineBasicBlock *mbb,
|
||||
InstrEmitter::InstrEmitter(const TargetMachine &TM, MachineBasicBlock *mbb,
|
||||
MachineBasicBlock::iterator insertpos)
|
||||
: MF(mbb->getParent()), MRI(&MF->getRegInfo()),
|
||||
TII(MF->getSubtarget().getInstrInfo()),
|
||||
TRI(MF->getSubtarget().getRegisterInfo()),
|
||||
TLI(MF->getSubtarget().getTargetLowering()), MBB(mbb),
|
||||
InsertPos(insertpos) {}
|
||||
InsertPos(insertpos) {
|
||||
EmitDebugInstrRefs = TM.Options.ValueTrackingVariableLocations;
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ class LLVM_LIBRARY_VISIBILITY InstrEmitter {
|
||||
MachineBasicBlock *MBB;
|
||||
MachineBasicBlock::iterator InsertPos;
|
||||
|
||||
/// Should we try to produce DBG_INSTR_REF instructions?
|
||||
bool EmitDebugInstrRefs;
|
||||
|
||||
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an
|
||||
/// implicit physical register output.
|
||||
void EmitCopyFromReg(SDNode *Node, unsigned ResNo,
|
||||
@ -109,6 +112,11 @@ public:
|
||||
MachineInstr *EmitDbgValue(SDDbgValue *SD,
|
||||
DenseMap<SDValue, Register> &VRBaseMap);
|
||||
|
||||
/// Attempt to emit a dbg_value as a DBG_INSTR_REF. May fail and return
|
||||
/// nullptr, in which case we fall back to plain EmitDbgValue.
|
||||
MachineInstr *EmitDbgInstrRef(SDDbgValue *SD,
|
||||
DenseMap<SDValue, Register> &VRBaseMap);
|
||||
|
||||
/// Generate machine instruction for a dbg_label node.
|
||||
MachineInstr *EmitDbgLabel(SDDbgLabel *SD);
|
||||
|
||||
@ -130,7 +138,8 @@ public:
|
||||
|
||||
/// InstrEmitter - Construct an InstrEmitter and set it to start inserting
|
||||
/// at the given position in the given block.
|
||||
InstrEmitter(MachineBasicBlock *mbb, MachineBasicBlock::iterator insertpos);
|
||||
InstrEmitter(const TargetMachine &TM, MachineBasicBlock *mbb,
|
||||
MachineBasicBlock::iterator insertpos);
|
||||
|
||||
private:
|
||||
void EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned,
|
||||
|
@ -760,7 +760,7 @@ void ScheduleDAGLinearize::Schedule() {
|
||||
|
||||
MachineBasicBlock*
|
||||
ScheduleDAGLinearize::EmitSchedule(MachineBasicBlock::iterator &InsertPos) {
|
||||
InstrEmitter Emitter(BB, InsertPos);
|
||||
InstrEmitter Emitter(DAG->getTarget(), BB, InsertPos);
|
||||
DenseMap<SDValue, Register> VRBaseMap;
|
||||
|
||||
LLVM_DEBUG({ dbgs() << "\n*** Final schedule ***\n"; });
|
||||
|
@ -829,7 +829,7 @@ EmitPhysRegCopy(SUnit *SU, DenseMap<SUnit*, Register> &VRBaseMap,
|
||||
/// not necessarily refer to returned BB. The emitter may split blocks.
|
||||
MachineBasicBlock *ScheduleDAGSDNodes::
|
||||
EmitSchedule(MachineBasicBlock::iterator &InsertPos) {
|
||||
InstrEmitter Emitter(BB, InsertPos);
|
||||
InstrEmitter Emitter(DAG->getTarget(), BB, InsertPos);
|
||||
DenseMap<SDValue, Register> VRBaseMap;
|
||||
DenseMap<SUnit*, Register> CopyVRBaseMap;
|
||||
SmallVector<std::pair<unsigned, MachineInstr*>, 32> Orders;
|
||||
|
54
test/DebugInfo/X86/instr-ref-selectiondag.ll
Normal file
54
test/DebugInfo/X86/instr-ref-selectiondag.ll
Normal file
@ -0,0 +1,54 @@
|
||||
; RUN: llc %s -mtriple=x86_64-unknown-unknown -o - -stop-before=finalize-isel \
|
||||
; RUN: | FileCheck %s --check-prefix=NORMAL \
|
||||
; RUN: --implicit-check-not=debug-instr-number \
|
||||
; RUN: --implicit-check-not=DBG_INSTR_REF
|
||||
; RUN: llc %s -mtriple=x86_64-unknown-unknown -o - -stop-before=finalize-isel \
|
||||
; RUN: -experimental-debug-variable-locations -verify-machineinstrs \
|
||||
; RUN: | FileCheck %s --check-prefix=INSTRREF \
|
||||
; RUN: --implicit-check-not=DBG_VALUE
|
||||
|
||||
; Test that SelectionDAG produces DBG_VALUEs normally, but DBG_INSTR_REFs when
|
||||
; asked.
|
||||
|
||||
; NORMAL: %[[REG0:[0-9]+]]:gr32 = ADD32rr
|
||||
; NORMAL-NEXT: DBG_VALUE %[[REG0]]
|
||||
; NORMAL-NEXT: %[[REG1:[0-9]+]]:gr32 = ADD32rr
|
||||
; NORMAL-NEXT: DBG_VALUE %[[REG1]]
|
||||
|
||||
; Note that I'm baking in an assumption of one-based ordering here. We could
|
||||
; capture and check for the instruction numbers, we'd rely on machine verifier
|
||||
; ensuring there were no duplicates.
|
||||
|
||||
; INSTRREF: ADD32rr
|
||||
; INSTRREF-SAME: debug-instr-number 1
|
||||
; INSTRREF-NEXT: DBG_INSTR_REF 1, 0
|
||||
; INSTRREF-NEXT: ADD32rr
|
||||
; INSTRREF-SAME: debug-instr-number 2
|
||||
; INSTRREF-NEXT: DBG_INSTR_REF 2, 0
|
||||
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
define i32 @foo(i32 %bar, i32 %baz, i32 %qux) !dbg !7 {
|
||||
entry:
|
||||
%0 = add i32 %bar, %baz, !dbg !14
|
||||
call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()), !dbg !14
|
||||
%1 = add i32 %0, %qux
|
||||
call void @llvm.dbg.value(metadata i32 %1, metadata !13, metadata !DIExpression()), !dbg !14
|
||||
ret i32 %1, !dbg !14
|
||||
}
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!3, !4}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)
|
||||
!1 = !DIFile(filename: "exprconflict.c", directory: "/home/jmorse")
|
||||
!2 = !{}
|
||||
!3 = !{i32 2, !"Dwarf Version", i32 4}
|
||||
!4 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
|
||||
!8 = !DISubroutineType(types: !9)
|
||||
!9 = !{!10, !10}
|
||||
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
||||
!11 = !{!13}
|
||||
!13 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 6, type: !10)
|
||||
!14 = !DILocation(line: 1, scope: !7)
|
Loading…
Reference in New Issue
Block a user