[llvm] [DebugInfo] Accept DW_OP_xderef_size and DW_OP_lit1..DW_OP_lit31. (PR #227839)
Matt Davis via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 12:53:35 PDT 2026
https://github.com/enferex updated https://github.com/llvm/llvm-project/pull/227839
>From e69ffe63482df2f217d625b316d84c8eae4fb1b4 Mon Sep 17 00:00:00 2001
From: Matt Davis <mattd at nvidia.com>
Date: Mon, 28 Sep 2026 01:39:36 +0000
Subject: [PATCH 1/2] [DebugInfo] Accept DW_OP_xderef_size and
DW_OP_lit1..DW_OP_lit31.
- Accept DW_OP_lit0..DW_OP_lit31 and DW_OP_xderef_size in
DIExpression::isValid and DwarfExpression::addExpression.
- Treat DW_OP_lit<n> as DW_OP_constu n in DIExpression::isConstant; add
getConstantValue() for callers.
- extractAddressClass: match the trailing address space sequence (it
previously matched at the front but stripped the tail), accept the
DW_OP_lit<n> and DW_OP_xderef_size forms, and return multi-location
expressions unchanged rather than as a spurious match with an
uninitialized address class.
- Reject DW_OP_(x)deref_size operands that do not fit in a byte instead of
truncating them, and stop describeLoadedValue and PrologEpilogInserter
from producing them.
- PrologEpilogInserter: drop implicit locations of stack objects larger
than an address instead of emitting an invalid DW_OP_deref_size.
- Document the new operators in SourceLevelDebugging.
Assisted-by: LLM
---
llvm/docs/SourceLevelDebugging.md | 4 +
llvm/include/llvm/IR/DebugInfoMetadata.h | 15 ++-
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 2 +-
.../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 2 +-
.../CodeGen/AsmPrinter/DwarfExpression.cpp | 11 +-
llvm/lib/CodeGen/PrologEpilogInserter.cpp | 10 ++
llvm/lib/CodeGen/TargetInstrInfo.cpp | 8 +-
.../LogicalView/Readers/LVIRReader.cpp | 2 +-
llvm/lib/IR/DIExpressionOptimizer.cpp | 2 +-
llvm/lib/IR/DebugInfoMetadata.cpp | 104 ++++++++++-----
llvm/test/Assembler/diexpression.ll | 8 +-
...invalid-diexpression-deref-size-operand.ll | 17 +++
.../invalid-diexpression-xderef-size.ll | 9 ++
.../CodeGen/X86/prologepilog_deref_size.mir | 52 ++++++++
.../NVPTX/debug-addr-class-lit-xderef-size.ll | 58 +++++++++
.../X86/diexpression-lit-xderef-size.ll | 38 ++++++
llvm/unittests/IR/MetadataTest.cpp | 120 ++++++++++++++++++
17 files changed, 417 insertions(+), 45 deletions(-)
create mode 100644 llvm/test/Assembler/invalid-diexpression-deref-size-operand.ll
create mode 100644 llvm/test/Assembler/invalid-diexpression-xderef-size.ll
create mode 100644 llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll
create mode 100644 llvm/test/DebugInfo/X86/diexpression-lit-xderef-size.ll
diff --git a/llvm/docs/SourceLevelDebugging.md b/llvm/docs/SourceLevelDebugging.md
index 1f8ad9a795cff..0a99f92437982 100644
--- a/llvm/docs/SourceLevelDebugging.md
+++ b/llvm/docs/SourceLevelDebugging.md
@@ -439,6 +439,10 @@ vocabulary is limited, but includes at least:
of the stack is treated as an address. The second stack entry is treated as an
address space identifier. The two entries are popped and then an
implementation defined value is pushed on the stack.
+- `DW_OP_xderef_size, 4` behaves like `DW_OP_xderef`, but the size in bytes
+ of the value read is given by its operand (`4` as an example).
+- `DW_OP_lit0` through `DW_OP_lit31` push the literal values 0 through 31
+ onto the stack; `DW_OP_lit5` is equivalent to `DW_OP_constu, 5`.
- `DW_OP_stack_value` may appear at most once in an expression, and must be
the last opcode if `DW_OP_LLVM_fragment` is not present, or the second last
opcode if `DW_OP_LLVM_fragment` is present. It pops the top value of the
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index aca4949bd3f94..da220bf958565 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -3517,6 +3517,13 @@ class DIExpression : public MDNode {
// return it's sign information.
LLVM_ABI std::optional<SignedOrUnsignedConstant> isConstant() const;
+ /// Return the value of a constant expression, as recognized by isConstant().
+ /// This accounts for DW_OP_lit<n>, which encodes its value in the opcode.
+ LLVM_ABI uint64_t getConstantValue() const;
+
+ /// Return true if \p Op is one of DW_OP_lit0 through DW_OP_lit31.
+ LLVM_ABI static bool isLitOp(uint64_t Op);
+
/// Return the number of unique location operands referred to (via
/// DW_OP_LLVM_arg) in this expression; this is not necessarily the number of
/// instances of DW_OP_LLVM_arg within the expression.
@@ -3918,9 +3925,11 @@ class DIExpression : public MDNode {
/// `DW_OP_LLVM_arg, n` for all n in [0, N).
LLVM_ABI bool hasAllLocationOps(unsigned N) const;
- /// Checks if the last 4 elements of the expression are DW_OP_constu <DWARF
- /// Address Space> DW_OP_swap DW_OP_xderef and extracts the <DWARF Address
- /// Space>.
+ /// Checks if the expression ends with <DWARF Address Space> DW_OP_swap
+ /// DW_OP_xderef[_size], where the address space is pushed by DW_OP_constu or
+ /// DW_OP_lit<n>, and extracts the <DWARF Address Space>. Returns the
+ /// expression with that sequence removed (nullptr if nothing remains), or
+ /// \p Expr unchanged if the sequence is not present.
LLVM_ABI static const DIExpression *
extractAddressClass(const DIExpression *Expr, unsigned &AddrClass);
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 84ea5e349f01d..0d81019ed0159 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -3478,7 +3478,7 @@ void CodeViewDebug::emitDebugInfoForGlobal(const CVGlobalVariable &CVGV) {
bool isUnsigned = isFloatDIType(DIGV->getType())
? true
: DebugHandlerBase::isUnsignedDIType(DIGV->getType());
- APSInt Value(APInt(/*BitWidth=*/64, DIE->getElement(1)), isUnsigned);
+ APSInt Value(APInt(/*BitWidth=*/64, DIE->getConstantValue()), isUnsigned);
emitConstantSymbolRecord(DIGV->getType(), Value, QualifiedName);
}
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
index bb7dba9f37585..7c4237f7eff00 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
@@ -244,7 +244,7 @@ void DwarfCompileUnit::addLocationAttribute(
*VariableDIE,
DIExpression::SignedOrUnsignedConstant::UnsignedConstant ==
*Expr->isConstant(),
- Expr->getElement(1));
+ Expr->getConstantValue());
break;
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index 2e022f30842e7..ef97345812546 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -561,7 +561,8 @@ bool DwarfExpression::addExpression(
auto Op = ExprCursor.take();
uint64_t OpNum = Op->getOp();
- if (OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) {
+ if ((OpNum >= dwarf::DW_OP_reg0 && OpNum <= dwarf::DW_OP_reg31) ||
+ DIExpression::isLitOp(OpNum)) {
emitOp(OpNum);
continue;
} else if (OpNum >= dwarf::DW_OP_breg0 && OpNum <= dwarf::DW_OP_breg31) {
@@ -682,7 +683,6 @@ bool DwarfExpression::addExpression(
case dwarf::DW_OP_shl:
case dwarf::DW_OP_shr:
case dwarf::DW_OP_shra:
- case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
case dwarf::DW_OP_push_object_address:
@@ -754,7 +754,14 @@ bool DwarfExpression::addExpression(
assert(!isRegisterLocation());
emitOp(dwarf::DW_OP_xderef);
break;
+ case dwarf::DW_OP_xderef_size:
+ assert(!isRegisterLocation());
+ assert(isUInt<8>(Op->getArg(0)) && "size operand does not fit in a byte");
+ emitOp(dwarf::DW_OP_xderef_size);
+ emitData1(Op->getArg(0));
+ break;
case dwarf::DW_OP_deref_size:
+ assert(isUInt<8>(Op->getArg(0)) && "size operand does not fit in a byte");
emitOp(dwarf::DW_OP_deref_size);
emitData1(Op->getArg(0));
break;
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 7654014f2a1cb..49fa0f89d616c 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -1424,6 +1424,16 @@ bool PEIImpl::replaceFrameIndexDebugInstr(MachineFunction &MF, MachineInstr &MI,
// location expression. Also after doing this we change the DBG_VALUE
// to be direct.
if (MI.isIndirectDebugValue() && DIExpr->isImplicit()) {
+ // DW_OP_deref_size may not read more than the size of an address.
+ if (Size > MF.getDataLayout().getPointerSize()) {
+ LLVM_DEBUG(dbgs() << "Dropping location of object larger than an "
+ "address: "
+ << MI);
+ MI.setDebugValueUndef();
+ return true;
+ }
+ assert(isUInt<8>(Size) &&
+ "DW_OP_deref_size operand must fit in a byte");
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, Size};
bool WithStackValue = true;
DIExpr = DIExpression::prependOpcodes(DIExpr, Ops, WithStackValue);
diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp
index 92fc628e888e5..2fd34f818193b 100644
--- a/llvm/lib/CodeGen/TargetInstrInfo.cpp
+++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp
@@ -1932,13 +1932,17 @@ TargetInstrInfo::describeLoadedValue(const MachineInstr &MI,
if (MI.getNumExplicitDefs() != 1)
return std::nullopt;
+ // DW_OP_deref_size needs a known size that fits in its one-byte operand.
+ if (!MMO->getSize().hasValue() || MMO->getSize().isScalable() ||
+ !isUInt<8>(MMO->getSize().getValue().getFixedValue()))
+ return std::nullopt;
+
// TODO: In what way do we need to take Reg into consideration here?
SmallVector<uint64_t, 8> Ops;
DIExpression::appendOffset(Ops, Offset);
Ops.push_back(dwarf::DW_OP_deref_size);
- Ops.push_back(MMO->getSize().hasValue() ? MMO->getSize().getValue()
- : ~UINT64_C(0));
+ Ops.push_back(MMO->getSize().getValue().getFixedValue());
Expr = DIExpression::prependOpcodes(Expr, Ops);
return ParamLoadedValue(*BaseOp, Expr);
}
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
index 1f8ccbd9a512e..b0b0ff964a72b 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVIRReader.cpp
@@ -301,7 +301,7 @@ void LVIRReader::addConstantValue(LVElement *Element,
if (Constant == std::nullopt)
return;
std::stringstream Stream;
- uint64_t Value = DIExpr->getElement(1);
+ uint64_t Value = DIExpr->getConstantValue();
if (DIExpression::SignedOrUnsignedConstant::SignedConstant == Constant) {
if (int64_t SignedValue = static_cast<int64_t>(Value); SignedValue < 0) {
Stream << "-";
diff --git a/llvm/lib/IR/DIExpressionOptimizer.cpp b/llvm/lib/IR/DIExpressionOptimizer.cpp
index 7e19da303d6b8..50cc3417b2c8b 100644
--- a/llvm/lib/IR/DIExpressionOptimizer.cpp
+++ b/llvm/lib/IR/DIExpressionOptimizer.cpp
@@ -123,7 +123,7 @@ canonicalizeDwarfOperations(ArrayRef<uint64_t> WorkingOps) {
break;
auto OpRaw = Op->getOp();
- if (OpRaw >= dwarf::DW_OP_lit0 && OpRaw <= dwarf::DW_OP_lit31) {
+ if (DIExpression::isLitOp(OpRaw)) {
ResultOps.push_back(dwarf::DW_OP_constu);
ResultOps.push_back(OpRaw - dwarf::DW_OP_lit0);
consumeOneOperator(Cursor, Loc, *Cursor.peek());
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 7da33a7abc48a..1d687b0362a31 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -1746,6 +1746,7 @@ unsigned DIExpression::ExprOperand::getSize() const {
case dwarf::DW_OP_constu:
case dwarf::DW_OP_consts:
case dwarf::DW_OP_deref_size:
+ case dwarf::DW_OP_xderef_size:
case dwarf::DW_OP_plus_uconst:
case dwarf::DW_OP_LLVM_tag_offset:
case dwarf::DW_OP_LLVM_entry_value:
@@ -1798,6 +1799,10 @@ bool DIExpression::PlusUconstOp::classof(const ExprOperand *Op) {
return Op->is(dwarf::DW_OP_plus_uconst);
}
+bool DIExpression::isLitOp(uint64_t Op) {
+ return Op >= dwarf::DW_OP_lit0 && Op <= dwarf::DW_OP_lit31;
+}
+
bool DIExpression::isValid() const {
for (auto I = expr_op_begin(), E = expr_op_end(); I != E; ++I) {
// Check that there's space for the operand.
@@ -1806,7 +1811,7 @@ bool DIExpression::isValid() const {
uint64_t Op = I->getOp();
if ((Op >= dwarf::DW_OP_reg0 && Op <= dwarf::DW_OP_reg31) ||
- (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31))
+ (Op >= dwarf::DW_OP_breg0 && Op <= dwarf::DW_OP_breg31) || isLitOp(Op))
continue;
// Check that the operand is valid.
@@ -1851,6 +1856,12 @@ bool DIExpression::isValid() const {
return false;
break;
}
+ case dwarf::DW_OP_deref_size:
+ case dwarf::DW_OP_xderef_size:
+ // The size operand is encoded as a single byte.
+ if (!isUInt<8>(I->getArg(0)))
+ return false;
+ break;
case dwarf::DW_OP_LLVM_implicit_pointer:
case dwarf::DW_OP_LLVM_convert:
case dwarf::DW_OP_LLVM_arg:
@@ -1871,9 +1882,7 @@ bool DIExpression::isValid() const {
case dwarf::DW_OP_shr:
case dwarf::DW_OP_shra:
case dwarf::DW_OP_deref:
- case dwarf::DW_OP_deref_size:
case dwarf::DW_OP_xderef:
- case dwarf::DW_OP_lit0:
case dwarf::DW_OP_not:
case dwarf::DW_OP_dup:
case dwarf::DW_OP_regx:
@@ -2202,27 +2211,38 @@ bool DIExpression::hasAllLocationOps(unsigned N) const {
const DIExpression *DIExpression::extractAddressClass(const DIExpression *Expr,
unsigned &AddrClass) {
- // FIXME: This seems fragile. Nothing that verifies that these elements
- // actually map to ops and not operands.
+ if (!Expr->isValid())
+ return Expr;
auto SingleLocEltsOpt = Expr->getSingleLocationExpressionElements();
if (!SingleLocEltsOpt)
- return nullptr;
- auto SingleLocElts = *SingleLocEltsOpt;
+ return Expr;
+ ArrayRef<uint64_t> SingleLocElts = *SingleLocEltsOpt;
+
+ // Walk the operations, rather than the raw elements, so that operands are
+ // never mistaken for opcodes.
+ SmallVector<ExprOperand, 8> Ops(expr_op_iterator(SingleLocElts.begin()),
+ expr_op_iterator(SingleLocElts.end()));
+ if (Ops.size() < 3)
+ return Expr;
+ const ExprOperand &AddrSpaceOp = Ops[Ops.size() - 3];
+ const ExprOperand &SwapOp = Ops[Ops.size() - 2];
+ const ExprOperand &XDerefOp = Ops[Ops.size() - 1];
+ if (!SwapOp.is(dwarf::DW_OP_swap) || !(XDerefOp.is(dwarf::DW_OP_xderef) ||
+ XDerefOp.is(dwarf::DW_OP_xderef_size)))
+ return Expr;
- const unsigned PatternSize = 4;
- if (SingleLocElts.size() >= PatternSize &&
- SingleLocElts[PatternSize - 4] == dwarf::DW_OP_constu &&
- SingleLocElts[PatternSize - 2] == dwarf::DW_OP_swap &&
- SingleLocElts[PatternSize - 1] == dwarf::DW_OP_xderef) {
- AddrClass = SingleLocElts[PatternSize - 3];
+ uint64_t Op = AddrSpaceOp.getOp();
+ if (Op == dwarf::DW_OP_constu)
+ AddrClass = AddrSpaceOp.getArg(0);
+ else if (isLitOp(Op))
+ AddrClass = Op - dwarf::DW_OP_lit0;
+ else
+ return Expr;
- if (SingleLocElts.size() == PatternSize)
- return nullptr;
- return DIExpression::get(
- Expr->getContext(),
- ArrayRef(&*SingleLocElts.begin(), SingleLocElts.size() - PatternSize));
- }
- return Expr;
+ if (AddrSpaceOp.get() == SingleLocElts.begin())
+ return nullptr;
+ return DIExpression::get(Expr->getContext(),
+ ArrayRef(SingleLocElts.begin(), AddrSpaceOp.get()));
}
DIExpression *DIExpression::prepend(const DIExpression *Expr, uint8_t Flags,
@@ -2612,24 +2632,44 @@ DIExpression::isConstant() const {
// An signed constants can be represented as DW_OP_consts C DW_OP_stack_value
// (DW_OP_LLVM_fragment of Len).
// An unsigned constant can be represented as
- // DW_OP_constu C DW_OP_stack_value (DW_OP_LLVM_fragment of Len).
+ // DW_OP_constu C DW_OP_stack_value (DW_OP_LLVM_fragment of Len), or as
+ // DW_OP_lit<C> DW_OP_stack_value (DW_OP_LLVM_fragment of Len).
- if ((getNumElements() != 2 && getNumElements() != 3 &&
- getNumElements() != 6) ||
- (getElement(0) != dwarf::DW_OP_consts &&
- getElement(0) != dwarf::DW_OP_constu))
+ if (getNumElements() == 0)
+ return std::nullopt;
+ uint64_t Op = getElement(0);
+ if (Op != dwarf::DW_OP_consts && Op != dwarf::DW_OP_constu && !isLitOp(Op))
+ return std::nullopt;
+
+ // The number of elements used by the constant: DW_OP_lit<C> encodes its
+ // value in the opcode, while DW_OP_constu/DW_OP_consts take an operand.
+ unsigned ConstSize = expr_op_begin()->getSize();
+ unsigned NumElements = getNumElements();
+ // The constant may be followed by DW_OP_stack_value (1 element), and then
+ // by DW_OP_LLVM_fragment, offset, size (3 more elements).
+ if (NumElements != ConstSize && NumElements != ConstSize + 1 &&
+ NumElements != ConstSize + 4)
return std::nullopt;
- if (getNumElements() == 2 && getElement(0) == dwarf::DW_OP_consts)
+ if (NumElements == ConstSize && Op == dwarf::DW_OP_consts)
return SignedOrUnsignedConstant::SignedConstant;
- if ((getNumElements() == 3 && getElement(2) != dwarf::DW_OP_stack_value) ||
- (getNumElements() == 6 && (getElement(2) != dwarf::DW_OP_stack_value ||
- getElement(3) != dwarf::DW_OP_LLVM_fragment)))
+ if ((NumElements == ConstSize + 1 &&
+ getElement(ConstSize) != dwarf::DW_OP_stack_value) ||
+ (NumElements == ConstSize + 4 &&
+ (getElement(ConstSize) != dwarf::DW_OP_stack_value ||
+ getElement(ConstSize + 1) != dwarf::DW_OP_LLVM_fragment)))
return std::nullopt;
- return getElement(0) == dwarf::DW_OP_constu
- ? SignedOrUnsignedConstant::UnsignedConstant
- : SignedOrUnsignedConstant::SignedConstant;
+ return Op == dwarf::DW_OP_consts ? SignedOrUnsignedConstant::SignedConstant
+ : SignedOrUnsignedConstant::UnsignedConstant;
+}
+
+uint64_t DIExpression::getConstantValue() const {
+ assert(isConstant() && "Expression is not a constant");
+ uint64_t Op = getElement(0);
+ if (isLitOp(Op))
+ return Op - dwarf::DW_OP_lit0;
+ return getElement(1);
}
DIExpression::ExtOps DIExpression::getExtOps(unsigned FromSize, unsigned ToSize,
diff --git a/llvm/test/Assembler/diexpression.ll b/llvm/test/Assembler/diexpression.ll
index 93674acd3e715..24ca854eccc2a 100644
--- a/llvm/test/Assembler/diexpression.ll
+++ b/llvm/test/Assembler/diexpression.ll
@@ -10,9 +10,11 @@
; CHECK-SAME: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef),
; CHECK-SAME: !DIExpression(DW_OP_plus_uconst, 3)
; CHECK-SAME: !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_signed)
-; CHECK-SAME: !DIExpression(DW_OP_LLVM_tag_offset, 1)}
+; CHECK-SAME: !DIExpression(DW_OP_LLVM_tag_offset, 1)
+; CHECK-SAME: !DIExpression(DW_OP_lit0, DW_OP_lit5, DW_OP_lit31)
+; CHECK-SAME: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef_size, 4)}
-!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
+!named = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10}
!0 = !DIExpression()
!1 = !DIExpression(DW_OP_deref)
@@ -23,3 +25,5 @@
!6 = !DIExpression(DW_OP_plus_uconst, 3)
!7 = !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_signed)
!8 = !DIExpression(DW_OP_LLVM_tag_offset, 1)
+!9 = !DIExpression(DW_OP_lit0, DW_OP_lit5, DW_OP_lit31)
+!10 = !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef_size, 4)
diff --git a/llvm/test/Assembler/invalid-diexpression-deref-size-operand.ll b/llvm/test/Assembler/invalid-diexpression-deref-size-operand.ll
new file mode 100644
index 0000000000000..bb8ff5be884c2
--- /dev/null
+++ b/llvm/test/Assembler/invalid-diexpression-deref-size-operand.ll
@@ -0,0 +1,17 @@
+; The size operand of DW_OP_deref_size and DW_OP_xderef_size is encoded as a
+; single byte in DWARF, so larger values must be rejected rather than silently
+; truncated when emitted.
+
+; RUN: split-file %s %t
+; RUN: not llvm-as -disable-output < %t/deref-size.ll 2>&1 | FileCheck %s
+; RUN: not llvm-as -disable-output < %t/xderef-size.ll 2>&1 | FileCheck %s
+
+; CHECK: assembly parsed, but does not verify
+
+;--- deref-size.ll
+!named = !{!0}
+!0 = !DIExpression(DW_OP_deref_size, 256)
+
+;--- xderef-size.ll
+!named = !{!0}
+!0 = !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef_size, 256)
diff --git a/llvm/test/Assembler/invalid-diexpression-xderef-size.ll b/llvm/test/Assembler/invalid-diexpression-xderef-size.ll
new file mode 100644
index 0000000000000..4b1cdde0f66b9
--- /dev/null
+++ b/llvm/test/Assembler/invalid-diexpression-xderef-size.ll
@@ -0,0 +1,9 @@
+; DW_OP_xderef_size takes a one-byte size operand. A trailing occurrence with
+; no operand must be rejected, which only happens if ExprOperand::getSize()
+; accounts for the operand.
+
+; RUN: not llvm-as -disable-output < %s 2>&1 | FileCheck %s
+
+; CHECK: assembly parsed, but does not verify
+!named = !{!0}
+!0 = !DIExpression(DW_OP_xderef_size)
diff --git a/llvm/test/CodeGen/X86/prologepilog_deref_size.mir b/llvm/test/CodeGen/X86/prologepilog_deref_size.mir
index 73699f93ae425..9a212b0772d81 100644
--- a/llvm/test/CodeGen/X86/prologepilog_deref_size.mir
+++ b/llvm/test/CodeGen/X86/prologepilog_deref_size.mir
@@ -1,4 +1,8 @@
# RUN: llc -run-pass=prolog-epilog -o - %s | FileCheck %s
+
+# An indirect DBG_VALUE of a frame index with an implicit expression is
+# rewritten to load the object with DW_OP_deref_size. That is only valid for an
+# object no larger than an address; for a larger one the location is dropped.
--- |
; ModuleID = 'dbg.opt.ll'
source_filename = "dbg.c"
@@ -12,6 +16,16 @@
ret i16 %x
}
+ define dso_local void @ptrsize() #0 !dbg !40 {
+ entry:
+ ret void
+ }
+
+ define dso_local void @toobig() #0 !dbg !50 {
+ entry:
+ ret void
+ }
+
; Function Attrs: nounwind readnone speculatable
declare void @llvm.dbg.value(metadata, metadata, metadata) #1
@@ -37,6 +51,15 @@
!32 = !DILocalVariable(name: "y", scope: !7, file: !1, line: 3, type: !33)
!33 = !DIBasicType(name: "signed int", size: 32, encoding: DW_ATE_signed)
!34 = !DILocation(line: 3, column: 20, scope: !7)
+ !40 = distinct !DISubprogram(name: "ptrsize", scope: !1, file: !1, line: 5, type: !41, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+ !41 = !DISubroutineType(types: !42)
+ !42 = !{null}
+ !43 = !DILocalVariable(name: "p", scope: !40, file: !1, line: 6, type: !44)
+ !44 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed)
+ !45 = !DILocation(line: 6, column: 1, scope: !40)
+ !50 = distinct !DISubprogram(name: "toobig", scope: !1, file: !1, line: 8, type: !41, scopeLine: 8, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
+ !51 = !DILocalVariable(name: "b", scope: !50, file: !1, line: 9, type: !44)
+ !52 = !DILocation(line: 9, column: 1, scope: !50)
...
---
@@ -55,5 +78,34 @@ body: |
DBG_VALUE %fixed-stack.0, 0, !32, !DIExpression(DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value), debug-location !34
RET 0, $ax
...
+# CHECK-LABEL: name: foo
# CHECK: machineFunctionInfo
# CHECK: DBG_VALUE $rsp, $noreg, !12, !DIExpression(DW_OP_plus_uconst, {{[0-9]+}}, DW_OP_deref_size, 2, DW_OP_LLVM_convert, 16, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value), debug-location !14
+
+# An 8-byte object is exactly the size of an address, so it is still loaded.
+---
+name: ptrsize
+tracksRegLiveness: true
+stack:
+ - { id: 0, type: default, offset: 0, size: 8, alignment: 8, stack-id: default }
+body: |
+ bb.0.entry:
+ DBG_VALUE %stack.0, 0, !43, !DIExpression(DW_OP_stack_value), debug-location !45
+ RET 0
+...
+# CHECK-LABEL: name: ptrsize
+# CHECK: DBG_VALUE $rsp, $noreg, !{{[0-9]+}}, !DIExpression({{.*}}DW_OP_deref_size, 8, DW_OP_stack_value)
+
+# A 16-byte object has no correct implicit value, so its location is dropped.
+---
+name: toobig
+tracksRegLiveness: true
+stack:
+ - { id: 0, type: default, offset: 0, size: 16, alignment: 8, stack-id: default }
+body: |
+ bb.0.entry:
+ DBG_VALUE %stack.0, 0, !51, !DIExpression(DW_OP_stack_value), debug-location !52
+ RET 0
+...
+# CHECK-LABEL: name: toobig
+# CHECK: DBG_VALUE $noreg, 0, !{{[0-9]+}}, !DIExpression(DW_OP_stack_value)
diff --git a/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll b/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll
new file mode 100644
index 0000000000000..e23ebdf6a69ef
--- /dev/null
+++ b/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll
@@ -0,0 +1,58 @@
+; RUN: llc -mtriple=nvptx64-nvidia-cuda < %s | FileCheck %s
+
+; The DWARF address space may be pushed with DW_OP_lit<n> as well as
+; DW_OP_constu, and dereferenced with DW_OP_xderef_size as well as
+; DW_OP_xderef. In every case the sequence is stripped from the location and
+; emitted as DW_AT_address_class instead, leaving a bare 9-byte
+; DW_OP_addr <address> location.
+;
+; Each variable uses a different address space, none of which is the shared
+; space (8) that would be derived from the globals' IR address space, so each
+; DW_AT_address_class can only come from its own expression.
+
+; CHECK: .b8 65 // DW_AT_name
+; CHECK: .b8 5 // DW_AT_address_class
+; CHECK-NEXT: .b8 9 // DW_AT_location
+; CHECK-NEXT: .b8 3
+; CHECK-NEXT: .b64 A
+; CHECK: .b8 66 // DW_AT_name
+; CHECK: .b8 4 // DW_AT_address_class
+; CHECK-NEXT: .b8 9 // DW_AT_location
+; CHECK-NEXT: .b8 3
+; CHECK-NEXT: .b64 B
+; CHECK: .b8 67 // DW_AT_name
+; CHECK: .b8 6 // DW_AT_address_class
+; CHECK-NEXT: .b8 9 // DW_AT_location
+; CHECK-NEXT: .b8 3
+; CHECK-NEXT: .b64 C
+
+ at A = addrspace(3) externally_initialized global i32 undef, align 4, !dbg !0
+ at B = addrspace(3) externally_initialized global i32 undef, align 4, !dbg !5
+ at C = addrspace(3) externally_initialized global i32 undef, align 4, !dbg !7
+
+define ptx_kernel void @test() !dbg !14 {
+ store i32 0, ptr addrspacecast (ptr addrspace(3) @A to ptr), align 4, !dbg !17
+ store i32 0, ptr addrspacecast (ptr addrspace(3) @B to ptr), align 4, !dbg !17
+ store i32 0, ptr addrspacecast (ptr addrspace(3) @C to ptr), align 4, !dbg !17
+ ret void, !dbg !17
+}
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!11, !12}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_lit5, DW_OP_swap, DW_OP_xderef))
+!1 = distinct !DIGlobalVariable(name: "A", scope: !2, file: !3, line: 1, type: !10, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, emissionKind: FullDebug, globals: !4, nameTableKind: None)
+!3 = !DIFile(filename: "test.cu", directory: "/tmp")
+!4 = !{!0, !5, !7}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression(DW_OP_constu, 4, DW_OP_swap, DW_OP_xderef_size, 4))
+!6 = distinct !DIGlobalVariable(name: "B", scope: !2, file: !3, line: 2, type: !10, isLocal: false, isDefinition: true)
+!7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression(DW_OP_lit6, DW_OP_swap, DW_OP_xderef_size, 4))
+!8 = distinct !DIGlobalVariable(name: "C", scope: !2, file: !3, line: 3, type: !10, isLocal: false, isDefinition: true)
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{i32 2, !"Dwarf Version", i32 2}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!14 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 5, type: !15, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !2)
+!15 = !DISubroutineType(types: !16)
+!16 = !{null}
+!17 = !DILocation(line: 6, column: 1, scope: !14)
diff --git a/llvm/test/DebugInfo/X86/diexpression-lit-xderef-size.ll b/llvm/test/DebugInfo/X86/diexpression-lit-xderef-size.ll
new file mode 100644
index 0000000000000..c39a090561f08
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/diexpression-lit-xderef-size.ll
@@ -0,0 +1,38 @@
+; Check that DW_OP_lit<n> and DW_OP_xderef_size survive DWARF emission.
+; DwarfExpression::addExpression() previously handled only DW_OP_lit0 and had
+; no DW_OP_xderef_size case, so either would hit its llvm_unreachable default.
+; Note that emitConstu() also encodes small DW_OP_constu operands as
+; DW_OP_lit<n>, so the output cannot distinguish the two; this checks that
+; DW_OP_lit<n> in the IR is accepted and lowered rather than crashing.
+
+; RUN: llc -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t.o < %s
+; RUN: llvm-dwarfdump -debug-info %t.o | FileCheck %s
+
+; CHECK: DW_AT_name{{.*}}"lit"
+; CHECK: DW_AT_location (DW_OP_addrx 0x0, DW_OP_lit31, DW_OP_plus)
+; CHECK: DW_AT_name{{.*}}"xd"
+; CHECK: DW_AT_location (DW_OP_addrx 0x1, DW_OP_lit2, DW_OP_swap, DW_OP_xderef_size 0x4)
+
+; DW_OP_lit<n> DW_OP_stack_value is a constant, like DW_OP_constu n
+; DW_OP_stack_value, so a global with no address still gets a value.
+; CHECK: DW_AT_name{{.*}}"litconst"
+; CHECK: DW_AT_const_value (5)
+
+ at lit = global i32 0, align 4, !dbg !0
+ at xd = global i32 0, align 4, !dbg !5
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!7, !8}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression(DW_OP_lit31, DW_OP_plus))
+!1 = distinct !DIGlobalVariable(name: "lit", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, emissionKind: FullDebug, globals: !4)
+!3 = !DIFile(filename: "a.c", directory: "/")
+!4 = !{!0, !5, !10}
+!5 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef_size, 4))
+!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{i32 2, !"Dwarf Version", i32 5}
+!9 = distinct !DIGlobalVariable(name: "xd", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true)
+!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression(DW_OP_lit5, DW_OP_stack_value))
+!11 = distinct !DIGlobalVariable(name: "litconst", scope: !2, file: !3, line: 3, type: !6, isLocal: true, isDefinition: true)
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index e9af072ea800e..be9d92b5ef882 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -4452,6 +4452,14 @@ TEST_F(DIExpressionTest, isValid) {
EXPECT_VALID(dwarf::DW_OP_LLVM_entry_value, 1);
EXPECT_VALID(dwarf::DW_OP_LLVM_entry_value, 1, dwarf::DW_OP_plus_uconst, 6);
EXPECT_VALID(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_entry_value, 1);
+ EXPECT_VALID(dwarf::DW_OP_lit0);
+ EXPECT_VALID(dwarf::DW_OP_lit31);
+ EXPECT_VALID(dwarf::DW_OP_lit7, dwarf::DW_OP_plus);
+ EXPECT_VALID(dwarf::DW_OP_constu, 1, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef_size, 4);
+ EXPECT_VALID(dwarf::DW_OP_deref_size, 255);
+ EXPECT_VALID(dwarf::DW_OP_constu, 1, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef_size, 255);
// Invalid constructions.
EXPECT_INVALID(~0u);
@@ -4467,6 +4475,11 @@ TEST_F(DIExpressionTest, isValid) {
EXPECT_INVALID(dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_plus_uconst, 5,
dwarf::DW_OP_LLVM_entry_value, 1);
EXPECT_INVALID(dwarf::DW_OP_LLVM_arg, 1, dwarf::DW_OP_LLVM_entry_value, 1);
+ EXPECT_INVALID(dwarf::DW_OP_xderef_size);
+ // The size operand is encoded in a single byte.
+ EXPECT_INVALID(dwarf::DW_OP_deref_size, 256);
+ EXPECT_INVALID(dwarf::DW_OP_constu, 1, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef_size, 256);
// A valid operation doesn't make a malformed suffix valid.
EXPECT_INVALID(dwarf::DW_OP_reg0, dwarf::DW_OP_stack_value,
@@ -4555,6 +4568,113 @@ TEST_F(DIExpressionTest, createFragmentExpression) {
#undef EXPECT_INVALID_FRAGMENT
}
+TEST_F(DIExpressionTest, isConstant) {
+#define EXPECT_CONSTANT(Kind, Value, ...) \
+ do { \
+ uint64_t Elements[] = {__VA_ARGS__}; \
+ DIExpression *Expr = DIExpression::get(Context, Elements); \
+ EXPECT_EQ(Expr->isConstant(), DIExpression::Kind); \
+ EXPECT_EQ(Expr->getConstantValue(), Value); \
+ } while (false)
+#define EXPECT_NOT_CONSTANT(...) \
+ do { \
+ uint64_t Elements[] = {__VA_ARGS__}; \
+ EXPECT_FALSE(DIExpression::get(Context, Elements)->isConstant()); \
+ } while (false)
+
+ EXPECT_CONSTANT(UnsignedConstant, 5u, dwarf::DW_OP_constu, 5,
+ dwarf::DW_OP_stack_value);
+ EXPECT_CONSTANT(SignedConstant, uint64_t(-3), dwarf::DW_OP_consts,
+ uint64_t(-3), dwarf::DW_OP_stack_value);
+ EXPECT_CONSTANT(SignedConstant, 7u, dwarf::DW_OP_consts, 7);
+ EXPECT_CONSTANT(UnsignedConstant, 5u, dwarf::DW_OP_constu, 5,
+ dwarf::DW_OP_stack_value, dwarf::DW_OP_LLVM_fragment, 0, 32);
+
+ // DW_OP_lit<n> is shorthand for DW_OP_constu n.
+ EXPECT_CONSTANT(UnsignedConstant, 0u, dwarf::DW_OP_lit0,
+ dwarf::DW_OP_stack_value);
+ EXPECT_CONSTANT(UnsignedConstant, 31u, dwarf::DW_OP_lit31,
+ dwarf::DW_OP_stack_value);
+ EXPECT_CONSTANT(UnsignedConstant, 5u, dwarf::DW_OP_lit5);
+ EXPECT_CONSTANT(UnsignedConstant, 5u, dwarf::DW_OP_lit5,
+ dwarf::DW_OP_stack_value, dwarf::DW_OP_LLVM_fragment, 0, 32);
+
+ EXPECT_NOT_CONSTANT(dwarf::DW_OP_deref);
+ EXPECT_NOT_CONSTANT(dwarf::DW_OP_constu, 5, dwarf::DW_OP_plus);
+ EXPECT_NOT_CONSTANT(dwarf::DW_OP_lit5, dwarf::DW_OP_plus);
+ EXPECT_NOT_CONSTANT(dwarf::DW_OP_lit5, dwarf::DW_OP_lit6,
+ dwarf::DW_OP_stack_value);
+ EXPECT_FALSE(DIExpression::get(Context, {})->isConstant());
+
+#undef EXPECT_CONSTANT
+#undef EXPECT_NOT_CONSTANT
+}
+
+TEST_F(DIExpressionTest, isLitOp) {
+ EXPECT_TRUE(DIExpression::isLitOp(dwarf::DW_OP_lit0));
+ EXPECT_TRUE(DIExpression::isLitOp(dwarf::DW_OP_lit5));
+ EXPECT_TRUE(DIExpression::isLitOp(dwarf::DW_OP_lit31));
+ // The neighbouring opcodes on either side of the range.
+ EXPECT_FALSE(DIExpression::isLitOp(dwarf::DW_OP_lit0 - 1));
+ EXPECT_FALSE(DIExpression::isLitOp(dwarf::DW_OP_lit31 + 1));
+ EXPECT_FALSE(DIExpression::isLitOp(dwarf::DW_OP_reg0));
+ EXPECT_FALSE(DIExpression::isLitOp(dwarf::DW_OP_constu));
+}
+
+TEST_F(DIExpressionTest, extractAddressClass) {
+ unsigned AddrClass;
+ auto Extract = [&](ArrayRef<uint64_t> Elements) {
+ AddrClass = ~0u;
+ const DIExpression *Expr = DIExpression::get(Context, Elements);
+ const DIExpression *Result =
+ DIExpression::extractAddressClass(Expr, AddrClass);
+ return std::make_pair(Expr, Result);
+ };
+
+ // The whole expression is the address space sequence.
+ for (const SmallVector<uint64_t, 6> &Elements :
+ {SmallVector<uint64_t, 6>{dwarf::DW_OP_constu, 8, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef},
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_lit8, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef},
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_constu, 8, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef_size, 4},
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_lit8, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef_size, 4}}) {
+ auto [Expr, Result] = Extract(Elements);
+ EXPECT_EQ(Result, nullptr);
+ EXPECT_EQ(AddrClass, 8u);
+ }
+
+ // A preceding address computation is kept; the sequence is a suffix.
+ {
+ auto [Expr, Result] =
+ Extract({dwarf::DW_OP_plus_uconst, 4, dwarf::DW_OP_lit3,
+ dwarf::DW_OP_swap, dwarf::DW_OP_xderef});
+ EXPECT_EQ(AddrClass, 3u);
+ ASSERT_NE(Result, nullptr);
+ EXPECT_EQ(Result->getElements(),
+ ArrayRef<uint64_t>({dwarf::DW_OP_plus_uconst, 4}));
+ }
+
+ // Not an address space sequence: the expression is returned unchanged.
+ for (const SmallVector<uint64_t, 6> &Elements :
+ {SmallVector<uint64_t, 6>{},
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_deref},
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_constu, 8, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef, dwarf::DW_OP_plus_uconst,
+ 4},
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_consts, 8, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef},
+ // The operand of DW_OP_constu must not be mistaken for an opcode.
+ SmallVector<uint64_t, 6>{dwarf::DW_OP_constu, dwarf::DW_OP_swap,
+ dwarf::DW_OP_xderef}}) {
+ auto [Expr, Result] = Extract(Elements);
+ EXPECT_EQ(Result, Expr);
+ EXPECT_EQ(AddrClass, ~0u);
+ }
+}
+
TEST_F(DIExpressionTest, extractLeadingOffset) {
int64_t Offset;
SmallVector<uint64_t> Remaining;
>From 7dc77fb91f627645923f00489a5c0dc7709ffb1c Mon Sep 17 00:00:00 2001
From: Matt Davis <mattd at nvidia.com>
Date: Wed, 30 Sep 2026 19:52:08 +0000
Subject: [PATCH 2/2] [DebugInfo][NVPTX] Use poison instead of undef in address
class test.
- Initialize the addrspace(3) globals in
debug-addr-class-lit-xderef-size.ll with poison rather than the
deprecated undef.
Assisted-by: LLM
---
.../DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll b/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll
index e23ebdf6a69ef..65d8fd0035482 100644
--- a/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll
+++ b/llvm/test/DebugInfo/NVPTX/debug-addr-class-lit-xderef-size.ll
@@ -26,9 +26,9 @@
; CHECK-NEXT: .b8 3
; CHECK-NEXT: .b64 C
- at A = addrspace(3) externally_initialized global i32 undef, align 4, !dbg !0
- at B = addrspace(3) externally_initialized global i32 undef, align 4, !dbg !5
- at C = addrspace(3) externally_initialized global i32 undef, align 4, !dbg !7
+ at A = addrspace(3) externally_initialized global i32 poison, align 4, !dbg !0
+ at B = addrspace(3) externally_initialized global i32 poison, align 4, !dbg !5
+ at C = addrspace(3) externally_initialized global i32 poison, align 4, !dbg !7
define ptx_kernel void @test() !dbg !14 {
store i32 0, ptr addrspacecast (ptr addrspace(3) @A to ptr), align 4, !dbg !17
More information about the llvm-commits
mailing list