diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -504,6 +504,25 @@ void substituteDebugValuesForInst(const MachineInstr &Old, MachineInstr &New, unsigned MaxOperand = UINT_MAX); + /// Find the underlying defining instruction / operand for a COPY instruction + /// while in SSA form. Copies do not actually define values -- they move them + /// between registers. Labelling a COPY-like instruction with an instruction + /// number is to be avoided as it makes value numbers non-unique later in + /// compilation. This method follows the definition chain for any sequence of + /// COPY-like instructions to find whatever non-COPY-like instruction defines + /// the copied value; or for parameters, creates a DBG_PHI on entry. + /// May insert instructions into the entry block! + /// \p MI The copy-like instruction to salvage. + /// \returns An instruction/operand pair identifying the defining value. + DebugInstrOperandPair salvageCopySSA(MachineInstr &MI); + + /// Finalise any partially emitted debug instructions. These are DBG_INSTR_REF + /// instructions where we only knew the vreg of the value they use, not the + /// instruction that defines that vreg. Once isel finishes, we should have + /// enough information for every DBG_INSTR_REF to point at an instruction + /// (or DBG_PHI). + void finalizeDebugInstrRefs(); + MachineFunction(Function &F, const LLVMTargetMachine &Target, const TargetSubtargetInfo &STI, unsigned FunctionNum, MachineModuleInfo &MMI); diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -1007,6 +1007,205 @@ } } +auto MachineFunction::salvageCopySSA(MachineInstr &MI) + -> DebugInstrOperandPair { + MachineRegisterInfo &MRI = getRegInfo(); + const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); + const TargetInstrInfo &TII = *getSubtarget().getInstrInfo(); + + // Chase the value read by a copy-like instruction back to the instruction + // that ultimately _defines_ that value. This may pass: + // * Through multiple intermediate copies, including subregister moves / + // copies, + // * Copies from physical registers that must then be traced back to the + // defining instruction, + // * Or, physical registers may be live-in to (only) the entry block, which + // requires a DBG_PHI to be created. + // We can pursue this problem in that order: trace back through copies, + // optionally through a physical register, to a defining instruction. We + // should never move from physreg to vreg. As we're still in SSA form, no need + // to worry about partial definitions of registers. + + // Helper lambda to interpret a copy-like instruction. Takes instruction, + // returns the register read and any subregister identifying which part is + // read. + auto GetRegAndSubreg = + [&](const MachineInstr &Cpy) -> std::pair { + Register NewReg, OldReg; + unsigned SubReg; + if (Cpy.isCopy()) { + OldReg = Cpy.getOperand(0).getReg(); + NewReg = Cpy.getOperand(1).getReg(); + SubReg = Cpy.getOperand(1).getSubReg(); + } else if (Cpy.isSubregToReg()) { + OldReg = Cpy.getOperand(0).getReg(); + NewReg = Cpy.getOperand(2).getReg(); + SubReg = Cpy.getOperand(3).getImm(); + } else { + auto CopyDetails = *TII.isCopyInstr(Cpy); + const MachineOperand &Src = *CopyDetails.Source; + const MachineOperand &Dest = *CopyDetails.Destination; + OldReg = Dest.getReg(); + NewReg = Src.getReg(); + SubReg = Src.getSubReg(); + } + + return {NewReg, SubReg}; + }; + + // First seek either the defining instruction, or a copy from a physreg. + // During search, the current state is the current copy instruction, and which + // register we've read. Accumulate qualifying subregisters into SubregsSeen; + // deal with those later. + auto State = GetRegAndSubreg(MI); + auto CurInst = MI.getIterator(); + SmallVector SubregsSeen; + while (true) { + // If we've found a copy from a physreg, first portion of search is over. + if (!State.first.isVirtual()) + break; + + // Record any subregister qualifier. + if (State.second) + SubregsSeen.push_back(State.second); + + assert(MRI.hasOneDef(State.first)); + MachineInstr &Inst = *MRI.def_begin(State.first)->getParent(); + CurInst = Inst.getIterator(); + + // Any non-copy instruction is the defining instruction we're seeking. + if (!Inst.isCopyLike() && !TII.isCopyInstr(Inst)) + break; + State = GetRegAndSubreg(Inst); + }; + + // Helper lambda to apply additional subregister substitutions to a known + // instruction/operand pair. Adds new (fake) substitutions so that we can + // record the subregister. FIXME: this isn't very space efficient if multiple + // values are tracked back through the same copies; cache something later. + auto ApplySubregisters = + [&](DebugInstrOperandPair P) -> DebugInstrOperandPair { + for (unsigned Subreg : reverse(SubregsSeen)) { + // Fetch a new instruction number, not attached to an actual instruction. + unsigned NewInstrNumber = getNewDebugInstrNum(); + // Add a substitution from the "new" number to the known one, with a + // qualifying subreg. + makeDebugValueSubstitution({NewInstrNumber, 0}, P, Subreg); + // Return the new number; to find the underlying value, consumers need to + // deal with the qualifying subreg. + P = {NewInstrNumber, 0}; + } + return P; + }; + + // If we managed to find the defining instruction after COPYs, return an + // instruction / operand pair after adding subregister qualifiers. + if (State.first.isVirtual()) { + // Virtual register def -- we can just look up where this happens. + MachineInstr *Inst = MRI.def_begin(State.first)->getParent(); + for (auto &MO : Inst->operands()) { + if (!MO.isReg() || !MO.isDef() || MO.getReg() != State.first) + continue; + return ApplySubregisters( + {Inst->getDebugInstrNum(), Inst->getOperandNo(&MO)}); + } + + llvm_unreachable("Vreg def with no corresponding operand?"); + } + + // Our search ended in a copy from a physreg: walk back up the function + // looking for whatever defines the physreg. + assert(CurInst->isCopyLike() || TII.isCopyInstr(*CurInst)); + State = GetRegAndSubreg(*CurInst); + Register RegToSeek = State.first; + + auto RMII = CurInst->getReverseIterator(); + auto PrevInstrs = make_range(RMII, CurInst->getParent()->instr_rend()); + for (auto &ToExamine : PrevInstrs) { + for (auto &MO : ToExamine.operands()) { + // Test for operand that defines something aliasing RegToSeek. + if (!MO.isReg() || !MO.isDef() || + !TRI.regsOverlap(RegToSeek, MO.getReg())) + continue; + + return ApplySubregisters( + {ToExamine.getDebugInstrNum(), ToExamine.getOperandNo(&MO)}); + } + } + + // We reached the start of the block before finding a defining instruction. + // It must be an argument: assert that this is the entry block, and produce + // a DBG_PHI. + assert(!State.first.isVirtual()); + MachineBasicBlock &TargetBB = *CurInst->getParent(); + assert(&*TargetBB.getParent()->begin() == &TargetBB); + + // Create DBG_PHI for specified physreg. + auto Builder = BuildMI(TargetBB, TargetBB.getFirstNonPHI(), DebugLoc(), + TII.get(TargetOpcode::DBG_PHI)); + Builder.addReg(State.first, RegState::Debug); + unsigned NewNum = getNewDebugInstrNum(); + Builder.addImm(NewNum); + return ApplySubregisters({NewNum, 0u}); +} + +void MachineFunction::finalizeDebugInstrRefs() { + auto *TII = getSubtarget().getInstrInfo(); + + auto MakeDbgValue = [&](MachineInstr &MI) { + const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_VALUE); + MI.setDesc(RefII); + MI.getOperand(1).ChangeToRegister(0, false); + MI.getOperand(0).setIsDebug(); + }; + + if (!getTarget().Options.ValueTrackingVariableLocations) + return; + + for (auto &MBB : *this) { + for (auto &MI : MBB) { + if (!MI.isDebugRef() || !MI.getOperand(0).isReg()) + continue; + + Register Reg = MI.getOperand(0).getReg(); + + // Some vregs can be deleted as redundant in the meantime. Mark those + // as DBG_VALUE $noreg. + if (Reg == 0) { + MakeDbgValue(MI); + continue; + } + + assert(Reg.isVirtual()); + MachineInstr &DefMI = *RegInfo->def_instr_begin(Reg); + assert(RegInfo->hasOneDef(Reg)); + + // If we've found a copy-like instruction, follow it back to the + // instruction that defines the source value, see salvageCopySSA docs + // for why this is important. + if (DefMI.isCopyLike() || TII->isCopyInstr(DefMI)) { + auto Result = salvageCopySSA(DefMI); + MI.getOperand(0).ChangeToImmediate(Result.first); + MI.getOperand(1).setImm(Result.second); + } else { + // Otherwise, identify the operand number that the VReg refers to. + unsigned OperandIdx = 0; + for (const auto &MO : DefMI.operands()) { + if (MO.isReg() && MO.isDef() && MO.getReg() == Reg) + break; + ++OperandIdx; + } + assert(OperandIdx < DefMI.getNumOperands()); + + // Morph this instr ref to point at the given instruction and operand. + unsigned ID = DefMI.getDebugInstrNum(); + MI.getOperand(0).ChangeToImmediate(ID); + MI.getOperand(1).setImm(OperandIdx); + } + } + } +} + /// \} //===----------------------------------------------------------------------===// 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 @@ -119,11 +119,19 @@ 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. + /// Emit a dbg_value as a DBG_INSTR_REF. May produce DBG_VALUE $noreg instead + /// if there is no variable location; alternately a half-formed DBG_INSTR_REF + /// that refers to a virtual register and is corrected later in isel. MachineInstr *EmitDbgInstrRef(SDDbgValue *SD, DenseMap &VRBaseMap); + /// Emit a DBG_VALUE $noreg, indicating a variable has no location. + MachineInstr *EmitDbgNoLocation(SDDbgValue *SD); + + /// Emit a DBG_VALUE from the operands to SDDbgValue. + MachineInstr *EmitDbgValueFromSingleOp(SDDbgValue *SD, + DenseMap &VRBaseMap); + /// Generate machine instruction for a dbg_label node. MachineInstr *EmitDbgLabel(SDDbgLabel *SD); 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 @@ -686,6 +686,9 @@ ArrayRef LocationOps = SD->getLocationOps(); assert(!LocationOps.empty() && "dbg_value with no location operands?"); + if (SD->isInvalidated()) + return EmitDbgNoLocation(SD); + // Emit variadic dbg_value nodes as DBG_VALUE_LIST. if (SD->isVariadic()) { // DBG_VALUE_LIST := "DBG_VALUE_LIST" var, expression, loc (, loc)* @@ -694,26 +697,7 @@ auto MIB = BuildMI(*MF, DL, DbgValDesc); MIB.addMetadata(Var); MIB.addMetadata(Expr); - if (SD->isInvalidated()) { - // At least one node is no longer computed so we are unable to emit the - // location. Simply mark all of the operands as undef. - for (size_t i = 0; i < LocationOps.size(); ++i) - MIB.addReg(0U, RegState::Debug); - } else { - AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap); - } - return &*MIB; - } - - if (SD->isInvalidated()) { - // An invalidated SDNode must generate an undef DBG_VALUE: although the - // original value is no longer computed, earlier DBG_VALUEs live ranges - // must not leak into later code. - auto MIB = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE)); - MIB.addReg(0U); - MIB.addReg(0U, RegState::Debug); - MIB.addMetadata(Var); - MIB.addMetadata(Expr); + AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap); return &*MIB; } @@ -725,23 +709,7 @@ if (auto *InstrRef = EmitDbgInstrRef(SD, VRBaseMap)) return InstrRef; - // Emit non-variadic dbg_value nodes as DBG_VALUE. - // DBG_VALUE := "DBG_VALUE" loc, isIndirect, var, expr - const MCInstrDesc &DbgValDesc = TII->get(TargetOpcode::DBG_VALUE); - // Build the DBG_VALUE instruction base. - auto MIB = BuildMI(*MF, DL, DbgValDesc); - // Add the single location componenet 'loc'. - assert(LocationOps.size() == 1 && - "Non variadic dbg_value should have only one location op"); - AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap); - // Add 'isIndirect'. - if (SD->isIndirect()) - MIB.addImm(0U); - else - MIB.addReg(0U, RegState::Debug); - MIB.addMetadata(Var); - MIB.addMetadata(Expr); - return &*MIB; + return EmitDbgValueFromSingleOp(SD, VRBaseMap); } void InstrEmitter::AddDbgValueLocationOps( @@ -794,62 +762,134 @@ MachineInstr * InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD, DenseMap &VRBaseMap) { - // No support for instruction references for variadic values yet. - if (SD->isVariadic()) - return nullptr; + assert(!SD->isVariadic()); SDDbgOperand DbgOperand = SD->getLocationOps()[0]; - // 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 (DbgOperand.getKind() != SDDbgOperand::SDNODE) - return nullptr; - - SDNode *Node = DbgOperand.getSDNode(); - SDValue Op = SDValue(Node, DbgOperand.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(); + const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF); - // Try to pick out a defining instruction at this point. - unsigned VReg = getVR(Op, VRBaseMap); - MachineInstr *ResultInstr = nullptr; + // Handle variable locations that don't actually depend on the instructions + // in the program: constants and stack locations. + if (DbgOperand.getKind() == SDDbgOperand::FRAMEIX || + DbgOperand.getKind() == SDDbgOperand::CONST) + return EmitDbgValueFromSingleOp(SD, VRBaseMap); - // 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; + // It may not be immediately possible to identify the MachineInstr that + // defines a VReg, it can depend for example on the order blocks are + // emitted in. When this happens, or when further analysis is needed later, + // produce an instruction like this: + // + // DBG_INSTR_REF %0:gr64, 0, !123, !456 + // + // i.e., point the instruction at the vreg, and patch it up later in + // MachineFunction::finalizeDebugInstrRefs. + auto EmitHalfDoneInstrRef = [&](unsigned VReg) -> MachineInstr * { + auto MIB = BuildMI(*MF, DL, RefII); + MIB.addReg(VReg); + MIB.addImm(0); + MIB.addMetadata(Var); + MIB.addMetadata(Expr); + return MIB; + }; - 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; + // Try to find both the defined register and the instruction defining it. + MachineInstr *DefMI = nullptr; + unsigned VReg; + + if (DbgOperand.getKind() == SDDbgOperand::VREG) { + VReg = DbgOperand.getVReg(); + + // No definition means that block hasn't been emitted yet. Leave a vreg + // reference to be fixed later. + if (!MRI->hasOneDef(VReg)) + return EmitHalfDoneInstrRef(VReg); + + DefMI = &*MRI->def_instr_begin(VReg); + } else { + assert(DbgOperand.getKind() == SDDbgOperand::SDNODE); + // Look up the corresponding VReg for the given SDNode, if any. + SDNode *Node = DbgOperand.getSDNode(); + SDValue Op = SDValue(Node, DbgOperand.getResNo()); + DenseMap::iterator I = VRBaseMap.find(Op); + // No VReg -> produce a DBG_VALUE $noreg instead. + if (I==VRBaseMap.end()) + return EmitDbgNoLocation(SD); + + // Try to pick out a defining instruction at this point. + VReg = getVR(Op, VRBaseMap); + + // Again, if there's no instruction defining the VReg right now, fix it up + // later. + if (!MRI->hasOneDef(VReg)) + return EmitHalfDoneInstrRef(VReg); + + DefMI = &*MRI->def_instr_begin(VReg); + } + + // Avoid copy like instructions: they don't define values, only move them. + // Leave a virtual-register reference until it can be fixed up later, to find + // the underlying value definition. + if (DefMI->isCopyLike() || TII->isCopyInstr(*DefMI)) + return EmitHalfDoneInstrRef(VReg); - const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF); auto MIB = BuildMI(*MF, DL, RefII); - // Find the operand which defines the specified VReg. + // Find the operand number which defines the specified VReg. unsigned OperandIdx = 0; - for (const auto &MO : DefMI.operands()) { + for (const auto &MO : DefMI->operands()) { if (MO.isReg() && MO.isDef() && MO.getReg() == VReg) break; ++OperandIdx; } - assert(OperandIdx < DefMI.getNumOperands()); + assert(OperandIdx < DefMI->getNumOperands()); // Make the DBG_INSTR_REF refer to that instruction, and that operand. - unsigned InstrNum = DefMI.getDebugInstrNum(); + unsigned InstrNum = DefMI->getDebugInstrNum(); MIB.addImm(InstrNum); MIB.addImm(OperandIdx); MIB.addMetadata(Var); MIB.addMetadata(Expr); - ResultInstr = &*MIB; - return ResultInstr; + return &*MIB; +} + +MachineInstr *InstrEmitter::EmitDbgNoLocation(SDDbgValue *SD) { + // An invalidated SDNode must generate an undef DBG_VALUE: although the + // original value is no longer computed, earlier DBG_VALUEs live ranges + // must not leak into later code. + MDNode *Var = SD->getVariable(); + MDNode *Expr = SD->getExpression(); + DebugLoc DL = SD->getDebugLoc(); + auto MIB = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE)); + MIB.addReg(0U); + MIB.addReg(0U, RegState::Debug); + MIB.addMetadata(Var); + MIB.addMetadata(Expr); + return &*MIB; +} + +MachineInstr * +InstrEmitter::EmitDbgValueFromSingleOp(SDDbgValue *SD, + DenseMap &VRBaseMap) { + MDNode *Var = SD->getVariable(); + MDNode *Expr = SD->getExpression(); + DebugLoc DL = SD->getDebugLoc(); + const MCInstrDesc &II = TII->get(TargetOpcode::DBG_VALUE); + + assert(SD->getLocationOps().size() == 1 && + "Non variadic dbg_value should have only one location op"); + + // Emit non-variadic dbg_value nodes as DBG_VALUE. + // DBG_VALUE := "DBG_VALUE" loc, isIndirect, var, expr + auto MIB = BuildMI(*MF, DL, II); + AddDbgValueLocationOps(MIB, II, SD->getLocationOps(), VRBaseMap); + + if (SD->isIndirect()) + MIB.addImm(0U); + else + MIB.addReg(0U, RegState::Debug); + + return MIB.addMetadata(Var).addMetadata(Expr); } MachineInstr * diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -575,6 +575,7 @@ LiveInMap.insert(LI); // Insert DBG_VALUE instructions for function arguments to the entry block. + bool InstrRef = TM.Options.ValueTrackingVariableLocations; for (unsigned i = 0, e = FuncInfo->ArgDbgValues.size(); i != e; ++i) { MachineInstr *MI = FuncInfo->ArgDbgValues[e - i - 1]; assert(MI->getOpcode() != TargetOpcode::DBG_VALUE_LIST && @@ -595,6 +596,10 @@ << Register::virtReg2Index(Reg) << "\n"); } + // Don't try and extend through copies in instruction referencing mode. + if (InstrRef) + continue; + // If Reg is live-in then update debug info to track its copy in a vreg. DenseMap::iterator LDI = LiveInMap.find(Reg); if (LDI != LiveInMap.end()) { @@ -646,6 +651,10 @@ } } + // For debug-info, in instruction referencing mode, we need to perform some + // post-isel maintenence. + MF->finalizeDebugInstrRefs(); + // Determine if there are any calls in this machine function. MachineFrameInfo &MFI = MF->getFrameInfo(); for (const auto &MBB : *MF) { diff --git a/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll b/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll --- a/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll +++ b/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll @@ -13,7 +13,7 @@ ; CHECK: DBG_VALUE $ecx, $noreg, ![[A]], !DIExpression(), debug-location ; CHECK: DBG_VALUE $edx, $noreg, ![[B]], !DIExpression(), debug-location -; CHECK: DBG_VALUE_LIST ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), $noreg, $noreg, debug-location +; CHECK: DBG_VALUE $noreg, $noreg, ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), debug-location target triple = "x86_64-pc-windows-msvc19.16.27034" define dso_local i32 @"?foo@@YAHHH@Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 { diff --git a/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll b/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll --- a/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll +++ b/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll @@ -4,7 +4,7 @@ ;; variadic dbg_value using %y becomes undef. ; CHECK: ![[C:[0-9]+]] = !DILocalVariable(name: "c", -; CHECK: DBG_VALUE_LIST ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), $noreg, $noreg, debug-location +; CHECK: DBG_VALUE $noreg, $noreg, ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), debug-location target triple = "x86_64-pc-windows-msvc19.16.27034" define dso_local i32 @"?foo@@YAHHH@Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 { diff --git a/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll b/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll --- a/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll +++ b/llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll @@ -10,6 +10,8 @@ ; Test that SelectionDAG produces DBG_VALUEs normally, but DBG_INSTR_REFs when ; asked. +; NORMAL-LABEL: name: foo + ; NORMAL: %[[REG0:[0-9]+]]:gr32 = ADD32rr ; NORMAL-NEXT: DBG_VALUE %[[REG0]] ; NORMAL-NEXT: %[[REG1:[0-9]+]]:gr32 = ADD32rr @@ -19,6 +21,8 @@ ; capture and check for the instruction numbers, we'd rely on machine verifier ; ensuring there were no duplicates. +; INSTRREF-LABEL: name: foo + ; INSTRREF: ADD32rr ; INSTRREF-SAME: debug-instr-number 1 ; INSTRREF-NEXT: DBG_INSTR_REF 1, 0 @@ -26,6 +30,10 @@ ; INSTRREF-SAME: debug-instr-number 2 ; INSTRREF-NEXT: DBG_INSTR_REF 2, 0 +@glob32 = global i32 0 +@glob16 = global i16 0 +@glob8 = global i8 0 + declare void @llvm.dbg.value(metadata, metadata, metadata) define i32 @foo(i32 %bar, i32 %baz, i32 %qux) !dbg !7 { @@ -37,6 +45,105 @@ ret i32 %1, !dbg !14 } +; In the code below, isel produces a large number of copies between subregisters +; to represent the gradually decreasing width of the argument. This gets +; optimized away into three stores, but it's an objective of the instruction +; referencing design that COPYs are not numbered: they move values, not define +; them. Test that nothing is numbered, and instead that appropriate +; substitutions with subregister details are recorded. + +; NORMAL-LABEL: name: bar + +; NORMAL: DBG_VALUE $rdi +; NORMAL-NEXT: %0:gr64_with_sub_8bit = COPY $rdi +; NORMAL-NEXT: DBG_VALUE %0, +; NORMAL-NEXT: %1:gr32 = COPY %0.sub_32bit, +; NORMAL-NEXT: DBG_VALUE %1 +; NORMAL: %3:gr16 = COPY %0.sub_16bit, +; NORMAL-NEXT: DBG_VALUE %3 +; NORMAL: %5:gr8 = COPY %0.sub_8bit, +; NORMAL-NEXT: DBG_VALUE %5 + +; INSTRREF-LABEL: name: bar + +;; +; INSTRREF: debugValueSubstitutions: +; INSTRREF-NEXT: - { srcinst: 2, srcop: 0, dstinst: 1, dstop: 0, subreg: 6 } +; INSTRREF-NEXT: - { srcinst: 4, srcop: 0, dstinst: 3, dstop: 0, subreg: 4 } +; INSTRREF-NEXT: - { srcinst: 6, srcop: 0, dstinst: 5, dstop: 0, subreg: 1 } + +;; As a slight inefficiency today, multiple DBG_PHIs are created. + +; INSTRREF: DBG_PHI $rdi, 5 +; INSTRREF-NEXT: DBG_PHI $rdi, 3 +; INSTRREF-NEXT: DBG_PHI $rdi, 1 +;; Allow arguments to be specified by physreg DBG_VALUEs. +; INSTRREF-NEXT: DBG_VALUE $rdi + +;; Don't test the location of these instr-refs, only that the three non-argument +;; dbg.values become DBG_INSTR_REFs. We previously checked that these numbers +;; get substituted, with appropriate subregister qualifiers. +; INSTRREF: DBG_INSTR_REF 2, 0 +; INSTRREF: DBG_INSTR_REF 4, 0 +; INSTRREF: DBG_INSTR_REF 6, 0 + +define i32 @bar(i64 %bar) !dbg !20 { +entry: + call void @llvm.dbg.value(metadata i64 %bar, metadata !21, metadata !DIExpression()), !dbg !22 + %0 = trunc i64 %bar to i32, !dbg !22 + call void @llvm.dbg.value(metadata i32 %0, metadata !21, metadata !DIExpression()), !dbg !22 + store i32 %0, i32 *@glob32, !dbg !22 + %1 = trunc i32 %0 to i16, !dbg !22 + call void @llvm.dbg.value(metadata i16 %1, metadata !21, metadata !DIExpression()), !dbg !22 + store i16 %1, i16 *@glob16, !dbg !22 + %2 = trunc i16 %1 to i8, !dbg !22 + call void @llvm.dbg.value(metadata i8 %2, metadata !21, metadata !DIExpression()), !dbg !22 + store i8 %2, i8 *@glob8, !dbg !22 + ret i32 0, !dbg !22 +} + +; Ensure that we can track copies back to physreg defs, and throw in a subreg +; substitution for fun. The call to @xyzzy defines $rax, which gets copied to +; a VReg, and then truncated by a subreg copy. We should be able to track +; through the copies and walk back to the physreg def, labelling the CALL +; instruction. We should also be able to do this even when the block layout is +; crazily ordered. + +; NORMAL-LABEL: name: baz + +; NORMAL: CALL64pcrel32 target-flags(x86-plt) @xyzzy +; NORMAL: %2:gr64 = COPY $rax, +; NORMAL: %0:gr64 = COPY %2, +; NORMAL-LABEL: bb.1.slippers: +; NORMAL: DBG_VALUE %1 +; NORMAL-LABEL: bb.2.shoes: +; NORMAL: %1:gr16 = COPY %0.sub_16bit + +; INSTRREF-LABEL: name: baz + +; INSTRREF: debugValueSubstitutions: +; INSTRREF-NEXT: - { srcinst: 2, srcop: 0, dstinst: 1, dstop: 6, subreg: 4 } + +; INSTRREF: CALL64pcrel32 target-flags(x86-plt) @xyzzy, {{.*}} debug-instr-number 1 +; INSTRREF: DBG_INSTR_REF 2, 0 + +declare i64 @xyzzy() + +define i32 @baz() !dbg !30 { +entry: + %foo = call i64 @xyzzy(), !dbg !32 + br label %shoes + +slippers: + call void @llvm.dbg.value(metadata i16 %moo, metadata !31, metadata !DIExpression()), !dbg !32 + store i16 %moo, i16 *@glob16, !dbg !32 + ret i32 0, !dbg !32 + +shoes: + %moo = trunc i64 %foo to i16 + br label %slippers +} + !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!3, !4} @@ -52,3 +159,9 @@ !11 = !{!13} !13 = !DILocalVariable(name: "baz", scope: !7, file: !1, line: 6, type: !10) !14 = !DILocation(line: 1, scope: !7) +!20 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!21 = !DILocalVariable(name: "xyzzy", scope: !20, file: !1, line: 6, type: !10) +!22 = !DILocation(line: 1, scope: !20) +!30 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!31 = !DILocalVariable(name: "xyzzy", scope: !30, file: !1, line: 6, type: !10) +!32 = !DILocation(line: 1, scope: !30) diff --git a/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll b/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll --- a/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll +++ b/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll @@ -5,9 +5,7 @@ ; CHECK-LABEL: body: -; CHECK: DBG_VALUE_LIST ![[VAR:[0-9]+]] -; CHECK-SAME: $noreg, $noreg - +; CHECK: DBG_VALUE $noreg, $noreg, ![[VAR:[0-9]+]] 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"