https://github.com/firmiana402 created 
https://github.com/llvm/llvm-project/pull/204353


This PR fixes two related DWARF constant-handling bugs that were blocking each 
other.

First, LLDB's DWARF expression evaluator in 
[`DWARFExpression.cpp`](https://github.com/llvm/llvm-project/blob/main/lldb/source/Expression/DWARFExpression.cpp)
 handled `DW_OP_constu` and `DW_OP_consts` without going through `to_generic`. 
Under DWARF, these operators push a generic value: an address-sized integral 
value with unspecified signedness. That means the result should be truncated to 
the target address size (via `to_generic`).

Second, LLVM already had a producer-side issue tracked as 
[#47431](https://github.com/llvm/llvm-project/issues/47431): on 32-bit targets, 
LLVM could emit `DW_OP_consts` / `DW_OP_constu` for source integer constants 
wider than the target generic type. If LLDB were fixed alone, those 
producer-emitted constants would become truncated as DWARF requires, exposing 
incorrect debug info for wide source values.

This patch fixes both sides together.

## What Changed

On the LLDB consumer side:

- `DW_OP_constu` now uses `to_generic`.
- `DW_OP_consts` now uses `to_generic`.
- The corresponding LLDB DWARF expression tests were updated to expect 
address-sized generic values.

On the LLVM producer side:

- Wide integer debug-location constants that cannot be represented by the 
target generic type are emitted as `DW_OP_implicit_value` instead of 
`DW_OP_const*`.
- This preserves the source value bytes instead of relying on an address-sized 
DWARF generic constant.
- The producer-side change is limited to complete constant values, where there 
are no remaining `DIExpression` operations.

## Validation

Locally verified with:

```text
build/tools/lldb/unittests/Expression/ExpressionTests 
--gtest_filter='DWARFExpression.*'
74 tests passed

build/bin/llvm-lit -sv llvm/test/DebugInfo/X86/constant-loclist.ll
1 test passed

ninja -C build check-lldb -j12
No unexpected failures

ninja -C build check-all -j12
Completed with one unrelated local failure in Clang Tools :: 
clang-doc/DR-141990.cpp, caused by host warning-option output. No DebugInfo, 
DWARF, LLDB expression, or AsmPrinter-related failures were observed.

```

>From d3248dd31deea96f173dbbd0ba2ad514ea2a15bf Mon Sep 17 00:00:00 2001
From: firmiana402 <[email protected]>
Date: Wed, 17 Jun 2026 19:17:07 +0800
Subject: [PATCH] [DebugInfo][LLDB] Fix generic DW_OP_const handling

Make LLDB evaluate DW_OP_constu and DW_OP_consts as generic address-sized 
values, and teach LLVM to use DW_OP_implicit_value for wide integer constants 
that cannot be represented by a target generic value.
---
 lldb/source/Expression/DWARFExpression.cpp    |  6 ++--
 .../Expression/DWARFExpressionTest.cpp        |  6 ++--
 llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp    | 35 +++++++++++++++++--
 .../CodeGen/AsmPrinter/DwarfExpression.cpp    | 21 +++++++++++
 llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h |  3 ++
 llvm/test/DebugInfo/X86/constant-loclist.ll   | 16 +++++++++
 6 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index dd436e0c8afd9..7966673bb65ed 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1411,13 +1411,11 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
     case DW_OP_const8s:
       stack.push_back(to_generic(static_cast<int64_t>(op->getRawOperand(0))));
       break;
-    // These should also use to_generic, but we can't do that due to a
-    // producer-side bug in llvm. See llvm.org/pr48087.
     case DW_OP_constu:
-      stack.push_back(Scalar(op->getRawOperand(0)));
+      stack.push_back(to_generic(op->getRawOperand(0)));
       break;
     case DW_OP_consts:
-      stack.push_back(Scalar(static_cast<int64_t>(op->getRawOperand(0))));
+      stack.push_back(to_generic(static_cast<int64_t>(op->getRawOperand(0))));
       break;
 
     case DW_OP_dup:
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 6d4a624505390..7feacb2b9da24 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -388,13 +388,13 @@ TEST(DWARFExpression, DW_OP_const) {
       Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 
0x88}),
       ExpectScalar(0x33221100));
 
-  // Don't truncate to address size for compatibility with clang (pr48087).
+  // LEB constants also push generic values, so truncate to address size.
   EXPECT_THAT_EXPECTED(
       Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
-      ExpectScalar(0x01010101010101));
+      ExpectScalar(32, 0x01010101, false));
   EXPECT_THAT_EXPECTED(
       Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
-      ExpectScalar(0xffff010101010101));
+      ExpectScalar(32, 0x01010101, true));
 }
 
 TEST(DWARFExpression, DW_OP_skip) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 3479485cf866c..02e1d8667cc62 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -50,6 +50,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Target/TargetLoweringObjectFile.h"
 #include "llvm/Target/TargetMachine.h"
@@ -3251,10 +3252,38 @@ void DwarfDebug::emitDebugLocValue(const AsmPrinter 
&AP, const DIBasicType *BT,
                             &AP](const DbgValueLocEntry &Entry,
                                  DIExpressionCursor &Cursor) -> bool {
     if (Entry.isInt()) {
-      if (BT && (BT->getEncoding() == dwarf::DW_ATE_boolean))
+      if (BT && (BT->getEncoding() == dwarf::DW_ATE_boolean)) {
         DwarfExpr.addBooleanConstant(Entry.getInt());
-      else if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
-                      BT->getEncoding() == dwarf::DW_ATE_signed_char))
+        return true;
+      }
+
+      bool IsSigned = BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
+                             BT->getEncoding() == dwarf::DW_ATE_signed_char);
+      unsigned GenericBitSize = AP.MAI.getCodePointerSize() * 8;
+      if (BT && AP.getDwarfVersion() >= 4 &&
+          !AP.getDwarfDebug()->tuneForSCE() && !Cursor) {
+        // DW_OP_const* pushes a generic, address-sized value. For a wider
+        // source integer value that cannot fit in the generic type, use
+        // DW_OP_implicit_value to preserve the source bytes instead. Keep this
+        // limited to complete constant values: SCE tuning already avoids
+        // DW_OP_implicit_value for compatibility, and expressions with
+        // remaining operations may need a scalar stack value rather than an
+        // implicit value block.
+        uint64_t TypeBitSize = BT->getSizeInBits();
+        bool IsByteSized = TypeBitSize % 8 == 0;
+        bool IsOutOfRange =
+            IsSigned ? !isIntN(GenericBitSize, Entry.getInt())
+                     : !isUIntN(GenericBitSize,
+                                static_cast<uint64_t>(Entry.getInt()));
+        if (TypeBitSize > GenericBitSize && IsByteSized && IsOutOfRange) {
+          DwarfExpr.addImplicitValue(
+              APInt(static_cast<unsigned>(TypeBitSize),
+                    static_cast<uint64_t>(Entry.getInt()), IsSigned));
+          return true;
+        }
+      }
+
+      if (IsSigned)
         DwarfExpr.addSignedConstant(Entry.getInt());
       else
         DwarfExpr.addUnsignedConstant(Entry.getInt());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp 
b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
index d9b2deb6ccf3d..4057605d973c3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -236,6 +236,27 @@ void DwarfExpression::addUnsignedConstant(const APInt 
&Value) {
   }
 }
 
+void DwarfExpression::addImplicitValue(const APInt &Value) {
+  assert(isImplicitLocation() || isUnknownLocation());
+  assert(DwarfVersion >= 4);
+
+  APInt API = Value;
+  unsigned NumBytes = API.getBitWidth() / 8;
+  assert(API.getBitWidth() == NumBytes * 8 &&
+         "implicit value must be byte-sized");
+
+  emitOp(dwarf::DW_OP_implicit_value);
+  emitUnsigned(NumBytes);
+
+  // The loop below is emitting the value starting at the least significant
+  // byte, so byte-swap first for big-endian targets.
+  if (CU.getAsmPrinter()->getDataLayout().isBigEndian())
+    API = API.byteSwap();
+
+  for (unsigned I = 0; I < NumBytes; ++I)
+    emitData1(API.extractBits(8, I * 8).getZExtValue());
+}
+
 void DwarfExpression::addConstantFP(const APFloat &APF, const AsmPrinter &AP) {
   assert(isImplicitLocation() || isUnknownLocation());
   APInt API = APF.bitcastToAPInt();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h 
b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
index c4929aed1c197..14357168c52c9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
@@ -240,6 +240,9 @@ class DwarfExpression {
   /// Emit an unsigned constant.
   void addUnsignedConstant(const APInt &Value);
 
+  /// Emit an implicit value.
+  void addImplicitValue(const APInt &Value);
+
   /// Emit an floating point constant.
   void addConstantFP(const APFloat &Value, const AsmPrinter &AP);
 
diff --git a/llvm/test/DebugInfo/X86/constant-loclist.ll 
b/llvm/test/DebugInfo/X86/constant-loclist.ll
index 630c652ba0ccf..7d33bfd4d3341 100644
--- a/llvm/test/DebugInfo/X86/constant-loclist.ll
+++ b/llvm/test/DebugInfo/X86/constant-loclist.ll
@@ -1,4 +1,5 @@
 ; RUN: llc -filetype=obj %s -o - -experimental-debug-variable-locations=true | 
llvm-dwarfdump -v -debug-info - | FileCheck %s
+; RUN: llc -filetype=obj %s -o - -experimental-debug-variable-locations=true 
-mtriple=i386-unknown-linux-gnu -dwarf-version=4 | llvm-dwarfdump -v 
-debug-info - | FileCheck %s --check-prefix=I386
 
 ; A hand-written testcase to check 64-bit constant handling in location lists.
 
@@ -18,6 +19,21 @@
 ; CHECK-NEXT:   {{.*}}: DW_OP_constu 0x4000000000000000)
 ; CHECK-NEXT: DW_AT_name {{.*}}"d"
 
+; On 32-bit targets, source integer constants that do not fit in the
+; address-sized DWARF generic type must use DW_OP_implicit_value to avoid
+; truncating the source value.
+; I386: .debug_info contents:
+; I386: DW_TAG_variable
+; I386-NEXT: DW_AT_location
+; I386-NEXT:   {{.*}}: DW_OP_lit0
+; I386-NEXT:   {{.*}}: DW_OP_implicit_value 0x8 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x40)
+; I386-NEXT: DW_AT_name {{.*}}"u"
+; I386: DW_TAG_variable
+; I386-NEXT: DW_AT_location
+; I386-NEXT:   {{.*}}: DW_OP_consts +0
+; I386-NEXT:   {{.*}}: DW_OP_implicit_value 0x8 0x00 0x00 0x00 0x00 0x00 0x00 
0x00 0x40)
+; I386-NEXT: DW_AT_name {{.*}}"i"
+
 source_filename = "test.c"
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx"

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to