https://github.com/MrEven132 created 
https://github.com/llvm/llvm-project/pull/218335

DWARF v5 requires relational comparisons whose operands have the generic type
to be performed as signed operations. LLDB currently dispatches `DW_OP_lt`,
`DW_OP_le`, `DW_OP_gt`, and `DW_OP_ge` directly to `Scalar` comparisons, whose
C-like integer promotion makes an equal-width unsigned operand win. As a
result, the generic comparison of an all-one address-sized value with zero can
be evaluated as `UINT64_MAX < 0` instead of `-1 < 0`.

Reuse the evaluator's existing approximation for potentially generic integer
operands and mark temporary operand copies signed before evaluating the four
ordering operations. This keeps the change local to DWARF expression
semantics, without changing general `Scalar` comparisons or `DW_OP_eq` and
`DW_OP_ne`.

The expression stack does not yet preserve genericness explicitly, so this
uses the same address-width approximation as the existing operand-type check.
Precisely distinguishing generic values from explicit address-sized base types
requires the larger typed-stack work already noted in the source.

Add a unit test using the issue's operands and cover all four affected ordering
opcodes. The focused test, all `DWARFExpression` tests, and the complete
`ExpressionTests` binary pass locally. Component-level `check-lldb-unit` also
passes.

Fixes #202878

>From edd94cca70ccb11cadaff81bf7fc206089dc3d0c Mon Sep 17 00:00:00 2001
From: MrEven132 <[email protected]>
Date: Mon, 24 Aug 2026 15:10:21 +0800
Subject: [PATCH] [lldb] Compare generic DWARF relational operands as signed
 values

---
 lldb/source/Expression/DWARFExpression.cpp    | 53 +++++++++++++++----
 .../Expression/DWARFExpressionTest.cpp        | 39 ++++++++++++++
 2 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 91c47546eeac7..47a3753211d97 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1331,6 +1331,14 @@ static llvm::Error 
Evaluate_DW_OP_call_frame_cfa(EvalContext &eval_ctx) {
   return llvm::Error::success();
 }
 
+static bool ArePotentiallyGenericIntegerOperands(const Scalar &lhs,
+                                                 const Scalar &rhs,
+                                                 size_t address_size) {
+  return address_size != 0 && lhs.GetType() == Scalar::e_int &&
+         rhs.GetType() == Scalar::e_int && lhs.GetByteSize() >= address_size &&
+         rhs.GetByteSize() >= address_size;
+}
+
 static llvm::Error CheckScalarOperandsHaveSameType(const Scalar &lhs,
                                                    const Scalar &rhs,
                                                    LocationAtom opcode,
@@ -1366,8 +1374,7 @@ static llvm::Error CheckScalarOperandsHaveSameType(const 
Scalar &lhs,
   // https://github.com/llvm/llvm-project/issues/47431. A precise fix would
   // require tracking genericness directly, which is a larger type-system
   // change.
-  if (address_size != 0 && lhs.GetByteSize() >= address_size &&
-      rhs.GetByteSize() >= address_size)
+  if (ArePotentiallyGenericIntegerOperands(lhs, rhs, address_size))
     return llvm::Error::success();
 
   // For non-generic integer operands, size and signedness are part of the
@@ -1380,6 +1387,32 @@ static llvm::Error CheckScalarOperandsHaveSameType(const 
Scalar &lhs,
   return llvm::Error::success();
 }
 
+static bool CompareScalarOrderingOperands(Scalar lhs, Scalar rhs,
+                                          LocationAtom opcode,
+                                          size_t address_size) {
+  // Scalar cannot represent the generic type's unspecified signedness. Reuse
+  // the type check's approximation and apply DWARF's signed comparison rule to
+  // potentially generic integer operands. Operands outside that approximation
+  // keep the signedness carried by Scalar.
+  if (ArePotentiallyGenericIntegerOperands(lhs, rhs, address_size)) {
+    lhs.MakeSigned();
+    rhs.MakeSigned();
+  }
+
+  switch (opcode) {
+  case DW_OP_ge:
+    return lhs >= rhs;
+  case DW_OP_gt:
+    return lhs > rhs;
+  case DW_OP_le:
+    return lhs <= rhs;
+  case DW_OP_lt:
+    return lhs < rhs;
+  default:
+    llvm_unreachable("not an ordering operation");
+  }
+}
+
 llvm::Expected<Value> DWARFExpression::Evaluate(
     ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
     lldb::ModuleSP module_sp, const DataExtractor &opcodes,
@@ -1745,8 +1778,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() =
-          to_generic(stack.back().GetScalar() >= tmp.GetScalar());
+      stack.back().GetScalar() = to_generic(CompareScalarOrderingOperands(
+          stack.back().GetScalar(), tmp.GetScalar(), opcode, address_size));
       break;
 
     case DW_OP_gt:
@@ -1756,8 +1789,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() =
-          to_generic(stack.back().GetScalar() > tmp.GetScalar());
+      stack.back().GetScalar() = to_generic(CompareScalarOrderingOperands(
+          stack.back().GetScalar(), tmp.GetScalar(), opcode, address_size));
       break;
 
     case DW_OP_le:
@@ -1767,8 +1800,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() =
-          to_generic(stack.back().GetScalar() <= tmp.GetScalar());
+      stack.back().GetScalar() = to_generic(CompareScalarOrderingOperands(
+          stack.back().GetScalar(), tmp.GetScalar(), opcode, address_size));
       break;
 
     case DW_OP_lt:
@@ -1778,8 +1811,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() =
-          to_generic(stack.back().GetScalar() < tmp.GetScalar());
+      stack.back().GetScalar() = to_generic(CompareScalarOrderingOperands(
+          stack.back().GetScalar(), tmp.GetScalar(), opcode, address_size));
       break;
 
     case DW_OP_ne:
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 094cfaf790a9a..50bdc96be7c93 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -766,6 +766,45 @@ TEST(DWARFExpression, RelationalOpsProduceGenericResult) {
   }
 }
 
+TEST(DWARFExpression, GenericRelationalOpsUseSignedComparison) {
+  struct TestCase {
+    uint8_t opcode;
+    uint8_t expected;
+  };
+  constexpr TestCase test_cases[] = {
+      {DW_OP_lt, 1}, {DW_OP_le, 1}, {DW_OP_gt, 0}, {DW_OP_ge, 0}};
+
+  for (const TestCase &test : test_cases) {
+    // Generic relational operands are compared as signed values, so the
+    // unsigned encoding of all-one bits below represents -1 for comparison.
+    const std::vector<uint8_t> expr = {
+        DW_OP_const8u,
+        0xff,
+        0xff,
+        0xff,
+        0xff,
+        0xff,
+        0xff,
+        0xff,
+        0xff,
+        DW_OP_consts,
+        0x00,
+        test.opcode,
+        DW_OP_stack_value,
+    };
+    DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
+                            /*addr_size=*/8);
+
+    EXPECT_THAT_EXPECTED(
+        DWARFExpression::Evaluate(
+            /*exe_ctx=*/nullptr, /*reg_ctx=*/nullptr, /*module_sp=*/{},
+            extractor, /*unit=*/nullptr, lldb::eRegisterKindLLDB,
+            /*initial_value_ptr=*/nullptr, /*object_address_ptr=*/nullptr),
+        ExpectScalar(64, test.expected, false))
+        << "opcode 0x" << llvm::utohexstr(test.opcode);
+  }
+}
+
 TEST(DWARFExpression, DW_OP_stack_value) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
 }

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

Reply via email to