diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h --- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h +++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h @@ -37,6 +37,9 @@ 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 @@ MachineInstr *EmitDbgValue(SDDbgValue *SD, DenseMap &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 &VRBaseMap); + /// Generate machine instruction for a dbg_label node. MachineInstr *EmitDbgLabel(SDDbgLabel *SD); @@ -130,7 +138,8 @@ /// 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, diff --git a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp --- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -695,6 +695,11 @@ 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 @@ return &*MIB; } +MachineInstr * +InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD, + DenseMap &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::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 @@ /// 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; +} diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp @@ -760,7 +760,7 @@ MachineBasicBlock* ScheduleDAGLinearize::EmitSchedule(MachineBasicBlock::iterator &InsertPos) { - InstrEmitter Emitter(BB, InsertPos); + InstrEmitter Emitter(DAG->getTarget(), BB, InsertPos); DenseMap VRBaseMap; LLVM_DEBUG({ dbgs() << "\n*** Final schedule ***\n"; }); diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -829,7 +829,7 @@ /// 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 VRBaseMap; DenseMap CopyVRBaseMap; SmallVector, 32> Orders; diff --git a/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll b/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll @@ -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)