[llvm] da0faa0 - [DebugInfo] Produce variadic DBG_INSTR_REFs from ISel
Stephen Tozer via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 9 00:58:59 PST 2023
Author: Stephen Tozer
Date: 2023-01-09T08:58:33Z
New Revision: da0faa0594b9df6d401d1e5686ff32766148b075
URL: https://github.com/llvm/llvm-project/commit/da0faa0594b9df6d401d1e5686ff32766148b075
DIFF: https://github.com/llvm/llvm-project/commit/da0faa0594b9df6d401d1e5686ff32766148b075.diff
LOG: [DebugInfo] Produce variadic DBG_INSTR_REFs from ISel
This patch modifies SelectionDAG and FastISel to produce DBG_INSTR_REFs with
variadic expressions, and produce DBG_INSTR_REFs for debug values with variadic
location expressions. The former essentially means just prepending
DW_OP_LLVM_arg, 0 to the existing expression. The latter is achieved in
MachineFunction::finalizeDebugInstrRefs and InstrEmitter::EmitDbgInstrRef.
Reviewed By: jmorse, Orlando
Differential Revision: https://reviews.llvm.org/D133929
Added:
Modified:
llvm/include/llvm/IR/DebugInfoMetadata.h
llvm/lib/CodeGen/MachineFunction.cpp
llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
llvm/lib/IR/DebugInfoMetadata.cpp
llvm/test/CodeGen/X86/pr57673.ll
llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
llvm/test/DebugInfo/X86/instr-ref-sdag-empty-vreg.ll
llvm/test/DebugInfo/X86/instr-ref-selectiondag.ll
llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll
llvm/test/DebugInfo/X86/safestack-byval.ll
llvm/unittests/IR/MetadataTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index f3602b62a3a71..def3ce2b56eab 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -2799,6 +2799,14 @@ class DIExpression : public MDNode {
/// DW_OP_LLVM_arg op as its first operand, or if it contains none.
bool isSingleLocationExpression() const;
+ /// Removes all elements from \p Expr that do not apply to an undef debug
+ /// value, which includes every operator that computes the value/location on
+ /// the DWARF stack, including any DW_OP_LLVM_arg elements (making the result
+ /// of this function always a single-location expression) while leaving
+ /// everything that defines what the computed value applies to, i.e. the
+ /// fragment information.
+ static const DIExpression *convertToUndefExpression(const DIExpression *Expr);
+
/// If \p Expr is a non-variadic expression (i.e. one that does not contain
/// DW_OP_LLVM_arg), returns \p Expr converted to variadic form by adding a
/// leading [DW_OP_LLVM_arg, 0] to the expression; otherwise returns \p Expr.
diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp
index 9625099cfe2cf..ba73abd9f3d96 100644
--- 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"
@@ -1136,52 +1135,58 @@ void MachineFunction::finalizeDebugInstrRefs() {
auto MakeUndefDbgValue = [&](MachineInstr &MI) {
const MCInstrDesc &RefII = TII->get(TargetOpcode::DBG_VALUE_LIST);
MI.setDesc(RefII);
- MI.getDebugOperand(0).setReg(0);
+ MI.setDebugValueUndef();
};
DenseMap<Register, DebugInstrOperandPair> 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
index af51223554728..bc48d168d7171 100644
--- a/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
@@ -1256,8 +1256,9 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
// 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<uint64_t, 3> 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 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
/* isKill */ false, /* isDead */ false,
/* isUndef */ false, /* isEarlyClobber */ false,
/* SubReg */ 0, /* isDebug */ true)});
+ SmallVector<uint64_t, 2> 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.cpp b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
index 2ee4a047a1deb..dbf0f8a421768 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.cpp
@@ -678,7 +678,6 @@ MachineInstr *
InstrEmitter::EmitDbgValue(SDDbgValue *SD,
DenseMap<SDValue, Register> &VRBaseMap) {
MDNode *Var = SD->getVariable();
- MDNode *Expr = SD->getExpression();
DebugLoc DL = SD->getDebugLoc();
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
@@ -691,29 +690,41 @@ InstrEmitter::EmitDbgValue(SDDbgValue *SD,
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 they have not been
+ // emitted as instruction references.
+ if (SD->isVariadic())
+ return EmitDbgValueList(SD, VRBaseMap);
+
+ // Emit single-location dbg_value nodes as DBG_VALUE if they have not been
+ // emitted as instruction references.
return EmitDbgValueFromSingleOp(SD, VRBaseMap);
}
+MachineOperand GetMOForConstDbgOp(const SDDbgOperand &Op) {
+ const Value *V = Op.getConst();
+ if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
+ if (CI->getBitWidth() > 64)
+ return MachineOperand::CreateCImm(CI);
+ return MachineOperand::CreateImm(CI->getSExtValue());
+ }
+ if (const ConstantFP *CF = dyn_cast<ConstantFP>(V))
+ return MachineOperand::CreateFPImm(CF);
+ // Note: This assumes that all nullptr constants are zero-valued.
+ if (isa<ConstantPointerNull>(V))
+ return MachineOperand::CreateImm(0);
+ // Undef or unhandled value type, so return an undef operand.
+ return MachineOperand::CreateReg(
+ /* Reg */ 0U, /* isDef */ false, /* isImp */ false,
+ /* isKill */ false, /* isDead */ false,
+ /* isUndef */ false, /* isEarlyClobber */ false,
+ /* SubReg */ 0, /* isDebug */ true);
+}
+
void InstrEmitter::AddDbgValueLocationOps(
MachineInstrBuilder &MIB, const MCInstrDesc &DbgValDesc,
ArrayRef<SDDbgOperand> LocationOps,
@@ -739,24 +750,9 @@ void InstrEmitter::AddDbgValueLocationOps(
AddOperand(MIB, V, (*MIB).getNumOperands(), &DbgValDesc, VRBaseMap,
/*IsDebug=*/true, /*IsClone=*/false, /*IsCloned=*/false);
} break;
- case SDDbgOperand::CONST: {
- const Value *V = Op.getConst();
- if (const ConstantInt *CI = dyn_cast<ConstantInt>(V)) {
- if (CI->getBitWidth() > 64)
- MIB.addCImm(CI);
- else
- MIB.addImm(CI->getSExtValue());
- } else if (const ConstantFP *CF = dyn_cast<ConstantFP>(V)) {
- MIB.addFPImm(CF);
- } else if (isa<ConstantPointerNull>(V)) {
- // Note: This assumes that all nullptr constants are zero-valued.
- MIB.addImm(0);
- } else {
- // Could be an Undef. In any case insert an Undef so we can see what we
- // dropped.
- MIB.addReg(0U);
- }
- } break;
+ case SDDbgOperand::CONST:
+ MIB.add(GetMOForConstDbgOp(Op));
+ break;
}
}
}
@@ -764,101 +760,130 @@ void InstrEmitter::AddDbgValueLocationOps(
MachineInstr *
InstrEmitter::EmitDbgInstrRef(SDDbgValue *SD,
DenseMap<SDValue, Register> &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<uint64_t> 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<MachineOperand> 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<MachineOperand, 1> 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<SDValue, Register>::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<SDValue, Register>::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);
+ MOs.push_back(GetMOForConstDbgOp(DbgOperand));
+ 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<MachineOperand, 1> 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);
}
@@ -866,14 +891,27 @@ 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.
+ DIVariable *Var = SD->getVariable();
+ const DIExpression *Expr =
+ DIExpression::convertToUndefExpression(SD->getExpression());
+ DebugLoc DL = SD->getDebugLoc();
+ const MCInstrDesc &Desc = TII->get(TargetOpcode::DBG_VALUE);
+ return BuildMI(*MF, DL, Desc, false, 0U, Var, Expr);
+}
+
+MachineInstr *
+InstrEmitter::EmitDbgValueList(SDDbgValue *SD,
+ DenseMap<SDValue, Register> &VRBaseMap) {
MDNode *Var = SD->getVariable();
- MDNode *Expr = SD->getExpression();
+ DIExpression *Expr = SD->getExpression();
DebugLoc DL = SD->getDebugLoc();
- auto MIB = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE));
- MIB.addReg(0U);
- MIB.addReg(0U);
+ // 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/InstrEmitter.h b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
index 0da4b962450cb..909d1a95560d9 100644
--- a/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
+++ b/llvm/lib/CodeGen/SelectionDAG/InstrEmitter.h
@@ -126,6 +126,10 @@ class LLVM_LIBRARY_VISIBILITY InstrEmitter {
/// 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<SDValue, Register> &VRBaseMap);
+
/// Emit a DBG_VALUE from the operands to SDDbgValue.
MachineInstr *EmitDbgValueFromSingleOp(SDDbgValue *SD,
DenseMap<SDValue, Register> &VRBaseMap);
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 954628d779f30..1fb7ab1cc3606 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5590,6 +5590,8 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
// the DIExpression.
if (Indirect)
NewDIExpr = DIExpression::prepend(FragExpr, DIExpression::DerefBefore);
+ SmallVector<uint64_t, 2> 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/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 905a1884e2692..fb9a7b8822204 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -1462,6 +1462,16 @@ bool DIExpression::isSingleLocationExpression() const {
});
}
+const DIExpression *
+DIExpression::convertToUndefExpression(const DIExpression *Expr) {
+ SmallVector<uint64_t, 3> UndefOps;
+ if (auto FragmentInfo = Expr->getFragmentInfo()) {
+ UndefOps.append({dwarf::DW_OP_LLVM_fragment, FragmentInfo->OffsetInBits,
+ FragmentInfo->SizeInBits});
+ }
+ return DIExpression::get(Expr->getContext(), UndefOps);
+}
+
const DIExpression *
DIExpression::convertToVariadicExpression(const DIExpression *Expr) {
if (any_of(Expr->expr_ops(), [](auto ExprOp) {
diff --git a/llvm/test/CodeGen/X86/pr57673.ll b/llvm/test/CodeGen/X86/pr57673.ll
index 5e7102059c0d2..d20704d58eda5 100644
--- a/llvm/test/CodeGen/X86/pr57673.ll
+++ b/llvm/test/CodeGen/X86/pr57673.ll
@@ -1,4 +1,7 @@
-; RUN: llc -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -stop-after=x86-optimize-LEAs < %s | FileCheck %s
+; RUN: llc -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -stop-after=x86-optimize-LEAs -experimental-debug-variable-locations=false < %s \
+; RUN: | FileCheck %s --check-prefix=NORMAL
+; RUN: llc -mtriple=x86_64-unknown-unknown -mcpu=x86-64 -stop-after=x86-optimize-LEAs -experimental-debug-variable-locations < %s \
+; RUN: | FileCheck %s --check-prefix=INSTRREF
; The LEA optimization pass used to crash on this testcase.
@@ -9,7 +12,8 @@
; CHECK: LEA64r
; CHECK-NOT: LEA64r
-; CHECK: DBG_VALUE_LIST
+; NORMAL: DBG_VALUE_LIST
+; INSTRREF: DBG_INSTR_REF
target triple = "x86_64-unknown-linux-gnu"
diff --git a/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll b/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
index a817f9aef8c66..828cebfd0728d 100644
--- a/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
+++ b/llvm/test/DebugInfo/X86/arg-dbg-value-list.ll
@@ -1,50 +1,51 @@
-;; FIXME: We currently don't do any special bookkeeping for unused args used by
-;; variadic dbg_values. When/if we support them, the DBG_VALUE_LIST should be
-;; updated accordingly.
-
-; RUN: llc %s -start-after=codegenprepare -stop-before=finalize-isel -o - | FileCheck %s
-
-;; Check that unused argument values are handled the same way for variadic
-;; dbg_values as non-variadics.
-
-; CHECK: ![[A:[0-9]+]] = !DILocalVariable(name: "a",
-; CHECK: ![[B:[0-9]+]] = !DILocalVariable(name: "b",
-; CHECK: ![[C:[0-9]+]] = !DILocalVariable(name: "c",
-
-; 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
-
-target triple = "x86_64-pc-windows-msvc19.16.27034"
-define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {
-entry:
- call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !17
- call void @llvm.dbg.value(metadata i32 %b, metadata !15, metadata !DIExpression()), !dbg !17
- call void @llvm.dbg.value(metadata !DIArgList(i32 %a, i32 %b), metadata !16, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !17
- ret i32 0
-}
-
-declare void @llvm.dbg.value(metadata, metadata, metadata)
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!3, !4, !5, !6}
-!llvm.ident = !{!7}
-
-!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, nameTableKind: None)
-!1 = !DIFile(filename: "test.cpp", directory: "/")
-!2 = !{}
-!3 = !{i32 2, !"CodeView", i32 1}
-!4 = !{i32 2, !"Debug Info Version", i32 3}
-!5 = !{i32 1, !"wchar_size", i32 2}
-!6 = !{i32 7, !"PIC Level", i32 2}
-!7 = !{!"clang version 11.0.0"}
-!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAHHH at Z", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
-!9 = !DIFile(filename: "test.cpp", directory: "/")
-!10 = !DISubroutineType(types: !11)
-!11 = !{!12, !12, !12}
-!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!13 = !{!14, !15, !16}
-!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !9, line: 1, type: !12)
-!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !9, line: 1, type: !12)
-!16 = !DILocalVariable(name: "c", scope: !8, file: !9, line: 2, type: !12)
-!17 = !DILocation(line: 0, scope: !8)
+;; FIXME: We currently don't do any special bookkeeping for unused args used by
+;; variadic dbg_values. When/if we support them, the DBG_VALUE_LIST should be
+;; updated accordingly.
+
+; RUN: llc %s -start-after=codegenprepare --experimental-debug-variable-locations=false -stop-before=finalize-isel -o - | FileCheck %s
+; RUN: llc %s -start-after=codegenprepare --experimental-debug-variable-locations -stop-before=finalize-isel -o - | FileCheck %s
+
+;; Check that unused argument values are handled the same way for variadic
+;; dbg_values as non-variadics.
+
+; CHECK: ![[A:[0-9]+]] = !DILocalVariable(name: "a",
+; CHECK: ![[B:[0-9]+]] = !DILocalVariable(name: "b",
+; CHECK: ![[C:[0-9]+]] = !DILocalVariable(name: "c",
+
+; 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(), debug-location
+
+target triple = "x86_64-pc-windows-msvc19.16.27034"
+define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {
+entry:
+ call void @llvm.dbg.value(metadata i32 %a, metadata !14, metadata !DIExpression()), !dbg !17
+ call void @llvm.dbg.value(metadata i32 %b, metadata !15, metadata !DIExpression()), !dbg !17
+ call void @llvm.dbg.value(metadata !DIArgList(i32 %a, i32 %b), metadata !16, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !17
+ ret i32 0
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!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, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 11.0.0"}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAHHH at Z", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
+!9 = !DIFile(filename: "test.cpp", directory: "/")
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12, !12, !12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !{!14, !15, !16}
+!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !9, line: 1, type: !12)
+!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !9, line: 1, type: !12)
+!16 = !DILocalVariable(name: "c", scope: !8, file: !9, line: 2, type: !12)
+!17 = !DILocation(line: 0, scope: !8)
diff --git a/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll b/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
index 8aa641d0c0fc8..4b58d631dcba3 100644
--- a/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
+++ b/llvm/test/DebugInfo/X86/dbg-val-list-undef.ll
@@ -1,41 +1,42 @@
-; RUN: llc %s -start-after=codegenprepare -stop-before=finalize-isel -o - | FileCheck %s
-
-;; %y is unused and cannot (FIXME: currently) be salvaged. Ensure that the
-;; 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
-
-target triple = "x86_64-pc-windows-msvc19.16.27034"
-define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {
-entry:
- %x = add i32 %a, %b
- %y = mul i32 %x, %b
- call void @llvm.dbg.value(metadata !DIArgList(i32 %x, i32 %y), metadata !16, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !17
- ret i32 %x
-}
-
-declare void @llvm.dbg.value(metadata, metadata, metadata)
-
-!llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!3, !4, !5, !6}
-!llvm.ident = !{!7}
-
-!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, nameTableKind: None)
-!1 = !DIFile(filename: "test.cpp", directory: "/")
-!2 = !{}
-!3 = !{i32 2, !"CodeView", i32 1}
-!4 = !{i32 2, !"Debug Info Version", i32 3}
-!5 = !{i32 1, !"wchar_size", i32 2}
-!6 = !{i32 7, !"PIC Level", i32 2}
-!7 = !{!"clang version 11.0.0"}
-!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAHHH at Z", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
-!9 = !DIFile(filename: "test.cpp", directory: "/")
-!10 = !DISubroutineType(types: !11)
-!11 = !{!12, !12, !12}
-!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!13 = !{!14, !15, !16}
-!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !9, line: 1, type: !12)
-!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !9, line: 1, type: !12)
-!16 = !DILocalVariable(name: "c", scope: !8, file: !9, line: 2, type: !12)
-!17 = !DILocation(line: 0, scope: !8)
+; RUN: llc %s -start-after=codegenprepare --experimental-debug-variable-locations=false -stop-before=finalize-isel -o - | FileCheck %s
+; RUN: llc %s -start-after=codegenprepare --experimental-debug-variable-locations -stop-before=finalize-isel -o - | FileCheck %s
+
+;; %y is unused and cannot (FIXME: currently) be salvaged. Ensure that the
+;; variadic dbg_value using %y becomes undef.
+
+; CHECK: ![[C:[0-9]+]] = !DILocalVariable(name: "c",
+; CHECK: DBG_VALUE $noreg, $noreg, ![[C]], !DIExpression(), debug-location
+
+target triple = "x86_64-pc-windows-msvc19.16.27034"
+define dso_local i32 @"?foo@@YAHHH at Z"(i32 %a, i32 %b) local_unnamed_addr !dbg !8 {
+entry:
+ %x = add i32 %a, %b
+ %y = mul i32 %x, %b
+ call void @llvm.dbg.value(metadata !DIArgList(i32 %x, i32 %y), metadata !16, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_stack_value)), !dbg !17
+ ret i32 %x
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5, !6}
+!llvm.ident = !{!7}
+
+!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, nameTableKind: None)
+!1 = !DIFile(filename: "test.cpp", directory: "/")
+!2 = !{}
+!3 = !{i32 2, !"CodeView", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 7, !"PIC Level", i32 2}
+!7 = !{!"clang version 11.0.0"}
+!8 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAHHH at Z", scope: !9, file: !9, line: 1, type: !10, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !13)
+!9 = !DIFile(filename: "test.cpp", directory: "/")
+!10 = !DISubroutineType(types: !11)
+!11 = !{!12, !12, !12}
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !{!14, !15, !16}
+!14 = !DILocalVariable(name: "a", arg: 1, scope: !8, file: !9, line: 1, type: !12)
+!15 = !DILocalVariable(name: "b", arg: 2, scope: !8, file: !9, line: 1, type: !12)
+!16 = !DILocalVariable(name: "c", scope: !8, file: !9, line: 2, type: !12)
+!17 = !DILocation(line: 0, scope: !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
index fc53edbbba12a..279a7b79503ac 100644
--- 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 @@ cond.false.i:
_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
index 003f5f57b36c1..dbbef2b39587d 100644
--- 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
@@ -38,20 +40,25 @@
; 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), 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), 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_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_VALUE $noreg, {{.+}}
@glob32 = global i32 0
@glob16 = global i16 0
@@ -64,8 +71,10 @@ 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
+ 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
}
@@ -208,7 +217,7 @@ shoes:
;; 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
diff erent scope + block, to test behaviours
;; where the debug intrinsic isn't in the first block. The normal-mode DBG_VALUE
diff --git a/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll b/llvm/test/DebugInfo/X86/invalidated-dbg-value-is-undef.ll
index b69021637c05a..4c6921519bb2d 100644
--- 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 $noreg, $noreg, ![[VAR:[0-9]+]], !DIExpression()
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"
diff --git a/llvm/test/DebugInfo/X86/safestack-byval.ll b/llvm/test/DebugInfo/X86/safestack-byval.ll
index e0e26dddba98a..acaa8031537ca 100644
--- a/llvm/test/DebugInfo/X86/safestack-byval.ll
+++ b/llvm/test/DebugInfo/X86/safestack-byval.ll
@@ -1,7 +1,8 @@
; Test dwarf codegen for DILocalVariable of a byval function argument that
; points to neither an argument nor an alloca. This kind of IR is generated by
; SafeStack for unsafe byval arguments.
-; RUN: llc -mtriple=x86_64-unknown-unknown -stop-after finalize-isel %s -o - | FileCheck %s
+; RUN: llc -mtriple=x86_64-unknown-unknown --experimental-debug-variable-locations=false -stop-after finalize-isel %s -o - | FileCheck %s --check-prefixes=CHECK,NORMAL
+; RUN: llc -mtriple=x86_64-unknown-unknown --experimental-debug-variable-locations -stop-after finalize-isel %s -o - | FileCheck %s --check-prefixes=CHECK,INSTRREF
; This was built by compiling the following source with SafeStack and
; simplifying the result a little.
@@ -13,8 +14,9 @@
; return zzz.a[len];
; }
-; CHECK: ![[ZZZ:.*]] = !DILocalVariable(name: "zzz",
-; CHECK: DBG_VALUE {{.*}} ![[ZZZ]], !DIExpression(DW_OP_deref, DW_OP_constu, 400, DW_OP_minus)
+; CHECK: ![[ZZZ:.*]] = !DILocalVariable(name: "zzz",
+; NORMAL: DBG_VALUE {{.*}} ![[ZZZ]], !DIExpression(DW_OP_deref, DW_OP_constu, 400, DW_OP_minus)
+; INSTRREF: DBG_INSTR_REF ![[ZZZ]], !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref, DW_OP_constu, 400, DW_OP_minus, DW_OP_deref)
%struct.S = type { [100 x i32] }
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index f1d86daf54616..3b60a719780c7 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -3089,6 +3089,66 @@ TEST_F(DIExpressionTest, createFragmentExpression) {
#undef EXPECT_INVALID_FRAGMENT
}
+TEST_F(DIExpressionTest, convertToUndefExpression) {
+#define EXPECT_UNDEF_OPS_EQUAL(TestExpr, Expected) \
+ do { \
+ const DIExpression *Undef = \
+ DIExpression::convertToUndefExpression(TestExpr); \
+ EXPECT_EQ(Undef, Expected); \
+ } while (false)
+#define GET_EXPR(...) DIExpression::get(Context, {__VA_ARGS__})
+
+ // Expressions which are single-location and non-complex should be unchanged.
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(), GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 32),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 32));
+
+ // Variadic expressions should become single-location.
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0), GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(
+ GET_EXPR(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_fragment, 32, 32),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 32, 32));
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0,
+ dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul),
+ GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_LLVM_arg, 0,
+ dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_mul,
+ dwarf::DW_OP_LLVM_fragment, 64, 32),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 64, 32));
+
+ // Any stack-computing ops should be removed.
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_plus_uconst, 8), GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(
+ GET_EXPR(dwarf::DW_OP_plus_uconst, 8, dwarf::DW_OP_LLVM_fragment, 0, 16),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 16));
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 24, dwarf::DW_OP_shra),
+ GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 24, dwarf::DW_OP_shra,
+ dwarf::DW_OP_LLVM_fragment, 8, 16),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 8, 16));
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_deref), GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(
+ GET_EXPR(dwarf::DW_OP_deref, dwarf::DW_OP_LLVM_fragment, 16, 16),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 16, 16));
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 4, dwarf::DW_OP_minus),
+ GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_constu, 4, dwarf::DW_OP_minus,
+ dwarf::DW_OP_LLVM_fragment, 24, 16),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 24, 16));
+
+ // Stack-value operators are also not preserved.
+ EXPECT_UNDEF_OPS_EQUAL(
+ GET_EXPR(dwarf::DW_OP_plus_uconst, 8, dwarf::DW_OP_stack_value),
+ GET_EXPR());
+ EXPECT_UNDEF_OPS_EQUAL(GET_EXPR(dwarf::DW_OP_plus_uconst, 8,
+ dwarf::DW_OP_stack_value,
+ dwarf::DW_OP_LLVM_fragment, 32, 16),
+ GET_EXPR(dwarf::DW_OP_LLVM_fragment, 32, 16));
+
+#undef EXPECT_UNDEF_OPS_EQUAL
+#undef GET_EXPR
+}
+
TEST_F(DIExpressionTest, convertToVariadicExpression) {
#define EXPECT_CONVERT_IS_NOOP(TestExpr) \
do { \
More information about the llvm-commits
mailing list