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 @@ -44,7 +44,6 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" @@ -1192,52 +1191,58 @@ auto MakeUndefDbgValue = [&](MachineInstr &MI) { const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_VALUE_LIST); MI.setDesc(RefII); - MI.getDebugOperand(0).setReg(0); + MI.setDebugValueUndef(); }; DenseMap ArgDbgPHIs; for (auto &MBB : *this) { for (auto &MI : MBB) { - if (!MI.isDebugRef() || !MI.getDebugOperand(0).isReg()) + if (!MI.isDebugRef()) continue; - Register Reg = MI.getDebugOperand(0).getReg(); + bool IsValidRef = true; - // Some vregs can be deleted as redundant in the meantime. Mark those - // as DBG_VALUE $noreg. Additionally, some normal instructions are - // quickly deleted, leaving dangling references to vregs with no def. - if (Reg == 0 || !RegInfo->hasOneDef(Reg)) { - MakeUndefDbgValue(MI); - continue; - } - // Only convert Expr to variadic form when we're sure we're emitting a - // complete instruction reference. - MI.getDebugExpressionOp().setMetadata( - DIExpression::convertToVariadicExpression(MI.getDebugExpression())); - - assert(Reg.isVirtual()); - MachineInstr &DefMI = *RegInfo->def_instr_begin(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, ArgDbgPHIs); - MI.getDebugOperand(0).ChangeToDbgInstrRef(Result.first, 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; + for (MachineOperand &MO : MI.debug_operands()) { + if (!MO.isReg()) + continue; + + Register Reg = MO.getReg(); + + // Some vregs can be deleted as redundant in the meantime. Mark those + // as DBG_VALUE $noreg. Additionally, some normal instructions are + // quickly deleted, leaving dangling references to vregs with no def. + if (Reg == 0 || !RegInfo->hasOneDef(Reg)) { + IsValidRef = false; + break; } - assert(OperandIdx < DefMI.getNumOperands()); - // Morph this instr ref to point at the given instruction and operand. - unsigned ID = DefMI.getDebugInstrNum(); - MI.getDebugOperand(0).ChangeToDbgInstrRef(ID, OperandIdx); + assert(Reg.isVirtual()); + MachineInstr &DefMI = *RegInfo->def_instr_begin(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, ArgDbgPHIs); + MO.ChangeToDbgInstrRef(Result.first, Result.second); + } else { + // Otherwise, identify the operand number that the VReg refers to. + unsigned OperandIdx = 0; + for (const auto &DefMO : DefMI.operands()) { + if (DefMO.isReg() && DefMO.isDef() && DefMO.getReg() == Reg) + break; + ++OperandIdx; + } + assert(OperandIdx < DefMI.getNumOperands()); + + // Morph this instr ref to point at the given instruction and operand. + unsigned ID = DefMI.getDebugInstrNum(); + MO.ChangeToDbgInstrRef(ID, OperandIdx); + } } + + if (!IsValidRef) + MakeUndefDbgValue(MI); } } } diff --git a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp --- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1256,8 +1256,9 @@ // If using instruction referencing, produce this as a DBG_INSTR_REF, // to be later patched up by finalizeDebugInstrRefs. Tack a deref onto // the expression, we don't have an "indirect" flag in DBG_INSTR_REF. - auto *NewExpr = - DIExpression::prepend(DI->getExpression(), DIExpression::DerefBefore); + SmallVector Ops( + {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_deref}); + auto *NewExpr = DIExpression::prependOpcodes(DI->getExpression(), Ops); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, *Op, DI->getVariable(), NewExpr); @@ -1325,9 +1326,11 @@ /* isKill */ false, /* isDead */ false, /* isUndef */ false, /* isEarlyClobber */ false, /* SubReg */ 0, /* isDebug */ true)}); + SmallVector Ops({dwarf::DW_OP_LLVM_arg, 0}); + auto *NewExpr = DIExpression::prependOpcodes(DI->getExpression(), Ops); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD.getDL(), TII.get(TargetOpcode::DBG_INSTR_REF), /*IsIndirect*/ false, MOs, - DI->getVariable(), DI->getExpression()); + DI->getVariable(), NewExpr); } } else { // We don't know how to handle other cases, so we drop. 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 @@ -128,6 +128,10 @@ /// Emit a DBG_VALUE $noreg, indicating a variable has no location. MachineInstr *EmitDbgNoLocation(SDDbgValue *SD); + /// Emit a DBG_VALUE_LIST from the operands to SDDbgValue. + MachineInstr *EmitDbgValueList(SDDbgValue *SD, + DenseMap &VRBaseMap); + /// Emit a DBG_VALUE from the operands to SDDbgValue. MachineInstr *EmitDbgValueFromSingleOp(SDDbgValue *SD, DenseMap &VRBaseMap); 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 @@ -679,7 +679,6 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD, DenseMap &VRBaseMap) { MDNode *Var = SD->getVariable(); - MDNode *Expr = SD->getExpression(); DebugLoc DL = SD->getDebugLoc(); assert(cast(Var)->isValidLocationForIntrinsic(DL) && "Expected inlined-at fields to agree"); @@ -692,26 +691,15 @@ 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)* - const MCInstrDesc &DbgValDesc = TII->get(TargetOpcode::DBG_VALUE_LIST); - // Build the DBG_VALUE_LIST instruction base. - auto MIB = BuildMI(*MF, DL, DbgValDesc); - MIB.addMetadata(Var); - MIB.addMetadata(Expr); - AddDbgValueLocationOps(MIB, DbgValDesc, LocationOps, VRBaseMap); - return &*MIB; - } - // Attempt to produce a DBG_INSTR_REF if we've been asked to. - // We currently exclude the possibility of instruction references for - // variadic nodes; if at some point we enable them, this should be moved - // above the variadic block. if (EmitDebugInstrRefs) if (auto *InstrRef = EmitDbgInstrRef(SD, VRBaseMap)) return InstrRef; + // Emit variadic dbg_value nodes as DBG_VALUE_LIST. + if (SD->isVariadic()) + return EmitDbgValueList(SD, VRBaseMap); + return EmitDbgValueFromSingleOp(SD, VRBaseMap); } @@ -765,101 +753,147 @@ MachineInstr * InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD, DenseMap &VRBaseMap) { - assert(!SD->isVariadic()); - SDDbgOperand DbgOperand = SD->getLocationOps()[0]; MDNode *Var = SD->getVariable(); const DIExpression *Expr = (DIExpression*)SD->getExpression(); DebugLoc DL = SD->getDebugLoc(); const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_INSTR_REF); - // 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) + // Returns true if the given operand is not a legal debug operand for a + // DBG_INSTR_REF. + auto IsInvalidOp = [](SDDbgOperand DbgOp) { + return DbgOp.getKind() == SDDbgOperand::FRAMEIX; + }; + // Returns true if the given operand is not itself an instruction reference + // but is a legal debug operand for a DBG_INSTR_REF. + auto IsNonInstrRefOp = [](SDDbgOperand DbgOp) { + return DbgOp.getKind() == SDDbgOperand::CONST; + }; + + // If this variable location does not depend on any instructions or contains + // any stack locations, produce it as a standard debug value instead. + if (any_of(SD->getLocationOps(), IsInvalidOp) || + all_of(SD->getLocationOps(), IsNonInstrRefOp)) { + if (SD->isVariadic()) + return EmitDbgValueList(SD, VRBaseMap); return EmitDbgValueFromSingleOp(SD, VRBaseMap); + } // Immediately fold any indirectness from the LLVM-IR intrinsic into the // expression: - if (SD->isIndirect()) { - std::vector Elts = {dwarf::DW_OP_deref}; - Expr = DIExpression::append(Expr, Elts); - } + if (SD->isIndirect()) + Expr = DIExpression::append(Expr, dwarf::DW_OP_deref); + // If this is not already a variadic expression, it must be modified to become + // one. + if (!SD->isVariadic()) + Expr = DIExpression::convertToVariadicExpression(Expr); + + SmallVector MOs; // 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 + // DBG_INSTR_REF !123, !456, %0:gr64 // // i.e., point the instruction at the vreg, and patch it up later in // MachineFunction::finalizeDebugInstrRefs. - auto EmitHalfDoneInstrRef = [&](unsigned VReg) -> MachineInstr * { - SmallVector MOs({MachineOperand::CreateReg( + auto AddVRegOp = [&](unsigned VReg) { + MOs.push_back(MachineOperand::CreateReg( /* Reg */ VReg, /* isDef */ false, /* isImp */ false, /* isKill */ false, /* isDead */ false, /* isUndef */ false, /* isEarlyClobber */ false, - /* SubReg */ 0, /* isDebug */ true)}); - return BuildMI(*MF, DL, RefII, false, MOs, Var, Expr); + /* SubReg */ 0, /* isDebug */ true)); }; + unsigned OpCount = SD->getLocationOps().size(); + for (unsigned OpIdx = 0; OpIdx < OpCount; ++OpIdx) { + SDDbgOperand DbgOperand = SD->getLocationOps()[OpIdx]; - // Try to find both the defined register and the instruction defining it. - MachineInstr *DefMI = nullptr; - unsigned VReg; + // 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(); + 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); + // No definition means that block hasn't been emitted yet. Leave a vreg + // reference to be fixed later. + if (!MRI->hasOneDef(VReg)) { + AddVRegOp(VReg); + continue; + } - 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); - } + DefMI = &*MRI->def_instr_begin(VReg); + } else if (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()) + break; - // 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); + // Try to pick out a defining instruction at this point. + VReg = getVR(Op, VRBaseMap); - // Find the operand number which defines the specified VReg. - unsigned OperandIdx = 0; - for (const auto &MO : DefMI->operands()) { - if (MO.isReg() && MO.isDef() && MO.getReg() == VReg) - break; - ++OperandIdx; + // Again, if there's no instruction defining the VReg right now, fix it up + // later. + if (!MRI->hasOneDef(VReg)) { + AddVRegOp(VReg); + continue; + } + + DefMI = &*MRI->def_instr_begin(VReg); + } else { + assert(DbgOperand.getKind() == SDDbgOperand::CONST); + // TODO: Probably extract this out into a function shared with + // AddDbgValueLocationOps. + const Value *V = DbgOperand.getConst(); + if (const ConstantInt *CI = dyn_cast(V)) { + if (CI->getBitWidth() > 64) + MOs.push_back(MachineOperand::CreateCImm(CI)); + else + MOs.push_back(MachineOperand::CreateImm(CI->getSExtValue())); + } else if (const ConstantFP *CF = dyn_cast(V)) { + MOs.push_back(MachineOperand::CreateFPImm(CF)); + } else if (isa(V)) { + // Note: This assumes that all nullptr constants are zero-valued. + MOs.push_back(MachineOperand::CreateImm(0)); + } else { + // Could be an Undef. In any case insert an Undef so we can see what we + // dropped. + AddVRegOp(0U); + } + continue; + } + + // 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)) { + AddVRegOp(VReg); + continue; + } + + // Find the operand number 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(); + MOs.push_back(MachineOperand::CreateDbgInstrRef(InstrNum, OperandIdx)); } - assert(OperandIdx < DefMI->getNumOperands()); - // Only convert Expr to variadic form when we're sure we're emitting a - // complete instruction reference. - if (!SD->isVariadic()) - Expr = DIExpression::convertToVariadicExpression(Expr); - // Make the DBG_INSTR_REF refer to that instruction, and that operand. - unsigned InstrNum = DefMI->getDebugInstrNum(); - SmallVector MOs( - {MachineOperand::CreateDbgInstrRef(InstrNum, OperandIdx)}); + // If we haven't created a valid MachineOperand for every DbgOp, abort and + // produce an undef DBG_VALUE. + if (MOs.size() != OpCount) + return EmitDbgNoLocation(SD); + return BuildMI(*MF, DL, RefII, false, MOs, Var, Expr); } @@ -870,11 +904,36 @@ 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); + const MCInstrDesc& Desc = TII->get(SD->isVariadic() + ? TargetOpcode::DBG_VALUE_LIST + : TargetOpcode::DBG_VALUE); + auto MIB = BuildMI(*MF, DL, Desc); + if (!SD->isVariadic()) { + MIB.addReg(0U); + MIB.addReg(0U); + } + MIB.addMetadata(Var); + MIB.addMetadata(Expr); + if (SD->isVariadic()) { + for (unsigned OpIdx = 0; OpIdx < SD->getLocationOps().size(); ++OpIdx) + MIB.addReg(0U); + } + return &*MIB; +} + +MachineInstr * +InstrEmitter::EmitDbgValueList(SDDbgValue *SD, + DenseMap &VRBaseMap) { + MDNode *Var = SD->getVariable(); + DIExpression *Expr = SD->getExpression(); + DebugLoc DL = SD->getDebugLoc(); + // DBG_VALUE_LIST := "DBG_VALUE_LIST" var, expression, loc (, loc)* + const MCInstrDesc &DbgValDesc = TII->get(TargetOpcode::DBG_VALUE_LIST); + // Build the DBG_VALUE_LIST instruction base. + auto MIB = BuildMI(*MF, DL, DbgValDesc); MIB.addMetadata(Var); MIB.addMetadata(Expr); + AddDbgValueLocationOps(MIB, DbgValDesc, SD->getLocationOps(), VRBaseMap); return &*MIB; } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5569,6 +5569,8 @@ // the DIExpression. if (Indirect) NewDIExpr = DIExpression::prepend(FragExpr, DIExpression::DerefBefore); + SmallVector Ops({dwarf::DW_OP_LLVM_arg, 0}); + NewDIExpr = DIExpression::prependOpcodes(NewDIExpr, Ops); return BuildMI(MF, DL, Inst, false, MOs, Variable, NewDIExpr); } else { // Create a completely standard DBG_VALUE. 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 $noreg, $noreg, ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), 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 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 $noreg, $noreg, ![[C]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value), 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 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-sdag-empty-vreg.ll b/llvm/test/DebugInfo/X86/instr-ref-sdag-empty-vreg.ll --- a/llvm/test/DebugInfo/X86/instr-ref-sdag-empty-vreg.ll +++ b/llvm/test/DebugInfo/X86/instr-ref-sdag-empty-vreg.ll @@ -7,7 +7,8 @@ ;; vreg that is never defined, which risks a crash. Check that we don't crash, ;; and produce an empty variable location. -; CHECK: DBG_VALUE_LIST {{.+}}, $noreg +; CHECK: DBG_VALUE_LIST {{.+}}, $noreg +; CHECK: DBG_VALUE_LIST {{.+}}, $noreg, 4 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-unknown" @@ -20,6 +21,7 @@ _ZN4Vec39normalizeEv.exit: ; preds = %cond.false.i call void @llvm.dbg.value(metadata float %width, metadata !11, metadata !DIExpression()), !dbg !12 + call void @llvm.dbg.value(metadata !DIArgList(float %width, i32 4), metadata !11, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_mul, DW_OP_stack_value)), !dbg !12 %mul.i = fmul float %width, 0.000000e+00, !dbg !12 ret void, !dbg !12 } 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 @@ -26,8 +26,10 @@ ; NORMAL: %[[REG0:[0-9]+]]:gr32 = ADD32rr ; NORMAL-NEXT: DBG_VALUE %[[REG0]] +; NORMAL-NEXT: DBG_VALUE_LIST {{.+}}, %[[REG0]], 2 ; NORMAL-NEXT: %[[REG1:[0-9]+]]:gr32 = ADD32rr ; NORMAL-NEXT: DBG_VALUE %[[REG1]] +; NORMAL-NEXT: DBG_VALUE_LIST {{.+}}, %[[REG1]], %[[REG0]] ; 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 @@ -37,21 +39,26 @@ ; INSTRREF: ADD32rr ; INSTRREF-SAME: debug-instr-number 1 -; INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0) +; INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0) +; INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0), 2 ; INSTRREF-NEXT: ADD32rr ; INSTRREF-SAME: debug-instr-number 2 -; INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0), dbg-instr-ref(1, 0) -; Test that fast-isel will produce DBG_INSTR_REFs too. +; Test that fast-isel will produce DBG_INSTR_REFs too, except for debug values +; using DIArgList, which is not supported in FastIsel. ; FASTISEL-INSTRREF-LABEL: name: foo ; FASTISEL-INSTRREF: ADD32rr ; FASTISEL-INSTRREF-SAME: debug-instr-number 1 -; FASTISEL-INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0) +; FASTISEL-INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0) +; FASTISEL-INSTRREF-NEXT: DBG_VALUE $noreg, {{.+}} ; FASTISEL-INSTRREF-NEXT: ADD32rr ; FASTISEL-INSTRREF-SAME: debug-instr-number 2 -; FASTISEL-INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; FASTISEL-INSTRREF-NEXT: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; FASTISEL-INSTRREF-NEXT: DBG_VALUE $noreg, {{.+}} @glob32 = global i32 0 @glob16 = global i16 0 @@ -64,8 +71,10 @@ entry: %0 = add i32 %bar, %baz, !dbg !14 call void @llvm.dbg.value(metadata i32 %0, metadata !13, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata !DIArgList(i32 %0, i32 2), metadata !13, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !14 %1 = add i32 %0, %qux call void @llvm.dbg.value(metadata i32 %1, metadata !13, metadata !DIExpression()), !dbg !14 + call void @llvm.dbg.value(metadata !DIArgList(i32 %1, i32 %0), metadata !13, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !14 ret i32 %1, !dbg !14 } @@ -107,9 +116,9 @@ ;; 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 {{.+}}, dbg-instr-ref(2, 0) -; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(4, 0) -; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(6, 0) +; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(4, 0) +; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(6, 0) ;; In fast-isel, we get four DBG_INSTR_REFs (compared to three and one ;; DBG_VALUE with normal isel). We get additional substitutions as a result: @@ -129,10 +138,10 @@ ; FASTISEL-INSTRREF-NEXT: DBG_PHI $rdi, 2 ; FASTISEL-INSTRREF-NEXT: DBG_PHI $rdi, 1 -; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0) -; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(3, 0) -; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(6, 0) -; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(10, 0) +; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(1, 0) +; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(3, 0) +; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(6, 0) +; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(10, 0) define i32 @bar(i64 %bar) !dbg !20 { entry: @@ -172,7 +181,7 @@ ; INSTRREF-NEXT: - { srcinst: 2, srcop: 0, dstinst: 1, dstop: 6, subreg: 4 } ; INSTRREF: CALL64pcrel32 target-flags(x86-plt) @xyzzy, csr_64, implicit $rsp, implicit $ssp, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, debug-instr-number 1 -; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) ;; Fast-isel produces the same arrangement, a DBG_INSTR_REF pointing back to ;; the call instruction. However: the operand numbers are different (6 for @@ -186,7 +195,7 @@ ; FASTISEL-INSTRREF-NEXT: - { srcinst: 2, srcop: 0, dstinst: 1, dstop: 4, subreg: 4 } ; FASTISEL-INSTRREF: CALL64pcrel32 target-flags(x86-plt) @xyzzy, csr_64, implicit $rsp, implicit $ssp, implicit-def $rax, debug-instr-number 1 -; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) +; FASTISEL-INSTRREF: DBG_INSTR_REF {{.+}}, dbg-instr-ref(2, 0) declare i64 @xyzzy() @@ -208,7 +217,7 @@ ;; Test for dbg.declare of non-stack-slot Values. These turn up with NRVO and ;; other ABI scenarios where something is technically in memory, but we don't ;; refer to it relative to the stack pointer. We refer to these either with an -;; indirect DBG_VAUE, or a DBG_INSTR_REF with DW_OP_deref prepended. +;; indirect DBG_VALUE, or a DBG_INSTR_REF with DW_OP_deref prepended. ;; ;; Test an inlined dbg.declare in a different scope + block, to test behaviours ;; where the debug intrinsic isn't in the first block. The normal-mode DBG_VALUE @@ -231,17 +240,17 @@ ; INSTRREF: DBG_PHI $rdi, 1 ; INSTRREF-NEXT: DBG_VALUE $rdi, 0, ![[SOCKS]], !DIExpression(), ; INSTRREF-NEXT: %0:gr64 = COPY $rdi -; INSTRREF-NEXT: DBG_INSTR_REF ![[KNEES]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref), dbg-instr-ref(1, 0), +; INSTRREF-NEXT: DBG_INSTR_REF ![[KNEES]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref), dbg-instr-ref(1, 0), ; In fast-isel mode, neither variable are hoisted or forwarded to a physreg. ; FASTISEL-INSTRREF-LABEL: name: qux ; FASTISEL-INSTRREF: DBG_PHI $rdi, 1 -; FASTISEL-INSTRREF: DBG_INSTR_REF ![[SOCKS]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref), dbg-instr-ref(1, 0), +; FASTISEL-INSTRREF: DBG_INSTR_REF ![[SOCKS]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref), dbg-instr-ref(1, 0), ; FASTISEL-INSTRREF-LABEL: bb.1.lala: -; FASTISEL-INSTRREF: DBG_INSTR_REF ![[KNEES]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref), dbg-instr-ref(1, 0), +; FASTISEL-INSTRREF: DBG_INSTR_REF ![[KNEES]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref), dbg-instr-ref(1, 0), declare i64 @cheddar(i32 *%arg) define void @qux(i32* noalias sret(i32) %agg.result) !dbg !40 { 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,7 +5,7 @@ ; CHECK-LABEL: body: -; CHECK: DBG_VALUE $noreg, $noreg, ![[VAR:[0-9]+]] +; CHECK: DBG_VALUE_LIST ![[VAR:[0-9]+]], {{.+}}, $noreg, $noreg 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"