https://github.com/kuilpd updated 
https://github.com/llvm/llvm-project/pull/177208

>From baf85a70b387461a3db522d999ad35b09c9f3e0f Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Tue, 20 Jan 2026 21:24:32 +0500
Subject: [PATCH 1/6] [lldb] Add binary addition to DIL

---
 lldb/docs/dil-expr-lang.ebnf                  |   4 +-
 lldb/include/lldb/ValueObject/DILAST.h        |  35 ++++
 lldb/include/lldb/ValueObject/DILEval.h       |  16 ++
 lldb/include/lldb/ValueObject/DILParser.h     |   1 +
 lldb/source/ValueObject/DILAST.cpp            |  14 ++
 lldb/source/ValueObject/DILEval.cpp           | 155 ++++++++++++++++++
 lldb/source/ValueObject/DILParser.cpp         |  24 ++-
 .../Arithmetic/TestFrameVarDILArithmetic.py   |  35 +++-
 .../frame/var-dil/expr/Arithmetic/main.cpp    |  17 ++
 9 files changed, 298 insertions(+), 3 deletions(-)

diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 99a8b0fcaa006..127c1d6337efa 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -3,7 +3,9 @@
 (* This is currently a subset of the final DIL Language, matching the current
    DIL implementation. *)
 
-expression = cast_expression;
+expression = additive_expression ;
+
+additive_expression = cast_expression {"+" cast_expression} ;
 
 cast_expression = unary_expression
                 | "(" type_id ")" cast_expression;
diff --git a/lldb/include/lldb/ValueObject/DILAST.h 
b/lldb/include/lldb/ValueObject/DILAST.h
index da7659959093a..226f80ac70c5e 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_VALUEOBJECT_DILAST_H
 #define LLDB_VALUEOBJECT_DILAST_H
 
+#include "lldb/ValueObject/DILLexer.h"
 #include "lldb/ValueObject/ValueObject.h"
 #include "llvm/Support/Error.h"
 #include <cstdint>
@@ -19,6 +20,7 @@ namespace lldb_private::dil {
 /// The various types DIL AST nodes (used by the DIL parser).
 enum class NodeKind {
   eArraySubscriptNode,
+  eBinaryOpNode,
   eBitExtractionNode,
   eBooleanLiteralNode,
   eCastNode,
@@ -38,6 +40,14 @@ enum class UnaryOpKind {
   Plus,   // "+"
 };
 
+/// The binary operators recognized by DIL.
+enum class BinaryOpKind {
+  Add, // "+"
+};
+
+/// Translates DIL tokens to BinaryOpKind.
+BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind);
+
 /// The type casts allowed by DIL.
 enum class CastKind {
   eArithmetic,  ///< Casting to a scalar.
@@ -148,6 +158,29 @@ class UnaryOpNode : public ASTNode {
   ASTNodeUP m_operand;
 };
 
+class BinaryOpNode : public ASTNode {
+public:
+  BinaryOpNode(uint32_t location, BinaryOpKind kind, ASTNodeUP lhs,
+               ASTNodeUP rhs)
+      : ASTNode(location, NodeKind::eBinaryOpNode), m_kind(kind),
+        m_lhs(std::move(lhs)), m_rhs(std::move(rhs)) {}
+
+  llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+
+  BinaryOpKind GetKind() const { return m_kind; }
+  ASTNode &GetLHS() const { return *m_lhs; }
+  ASTNode &GetRHS() const { return *m_rhs; }
+
+  static bool classof(const ASTNode *node) {
+    return node->GetKind() == NodeKind::eBinaryOpNode;
+  }
+
+private:
+  BinaryOpKind m_kind;
+  ASTNodeUP m_lhs;
+  ASTNodeUP m_rhs;
+};
+
 class ArraySubscriptNode : public ASTNode {
 public:
   ArraySubscriptNode(uint32_t location, ASTNodeUP base, ASTNodeUP index)
@@ -292,6 +325,8 @@ class Visitor {
   virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const UnaryOpNode &node) = 0;
   virtual llvm::Expected<lldb::ValueObjectSP>
+  Visit(const BinaryOpNode &node) = 0;
+  virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const ArraySubscriptNode &node) = 0;
   virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const BitFieldExtractionNode &node) = 0;
diff --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index 550f5083b1dc6..6807a6616b846 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -57,6 +57,7 @@ class Interpreter : Visitor {
   Visit(const IdentifierNode &node) override;
   llvm::Expected<lldb::ValueObjectSP> Visit(const MemberOfNode &node) override;
   llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode &node) override;
+  llvm::Expected<lldb::ValueObjectSP> Visit(const BinaryOpNode &node) override;
   llvm::Expected<lldb::ValueObjectSP>
   Visit(const ArraySubscriptNode &node) override;
   llvm::Expected<lldb::ValueObjectSP>
@@ -73,6 +74,21 @@ class Interpreter : Visitor {
   /// includes array-to-pointer and integral promotion for eligible types.
   llvm::Expected<lldb::ValueObjectSP>
   UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location);
+
+  /// Perform an arithmetic conversion on two values from an arithmetic
+  /// operation.
+  /// \returns The result type of an arithmetic operation.
+  llvm::Expected<CompilerType> ArithmeticConversion(lldb::ValueObjectSP &lhs,
+                                                    lldb::ValueObjectSP &rhs,
+                                                    uint32_t location);
+  llvm::Expected<lldb::ValueObjectSP> EvaluateScalarOp(BinaryOpKind kind,
+                                                       lldb::ValueObjectSP lhs,
+                                                       lldb::ValueObjectSP rhs,
+                                                       CompilerType 
result_type,
+                                                       uint32_t location);
+  llvm::Expected<lldb::ValueObjectSP>
+  EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
+                         uint32_t location);
   llvm::Expected<CompilerType>
   PickIntegerType(lldb::TypeSystemSP type_system,
                   std::shared_ptr<ExecutionContextScope> ctx,
diff --git a/lldb/include/lldb/ValueObject/DILParser.h 
b/lldb/include/lldb/ValueObject/DILParser.h
index 3bac4b2bb4171..d093f95cde841 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -94,6 +94,7 @@ class DILParser {
   ASTNodeUP Run();
 
   ASTNodeUP ParseExpression();
+  ASTNodeUP ParseAdditiveExpression();
   ASTNodeUP ParseUnaryExpression();
   ASTNodeUP ParsePostfixExpression();
   ASTNodeUP ParsePrimaryExpression();
diff --git a/lldb/source/ValueObject/DILAST.cpp 
b/lldb/source/ValueObject/DILAST.cpp
index d8a714d33712d..180708f79c269 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -11,6 +11,16 @@
 
 namespace lldb_private::dil {
 
+BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
+  switch (token_kind) {
+  case Token::plus:
+    return BinaryOpKind::Add;
+  default:
+    break;
+  }
+  llvm_unreachable("Unknown binary operator kind.");
+}
+
 llvm::Expected<lldb::ValueObjectSP> ErrorNode::Accept(Visitor *v) const {
   llvm_unreachable("Attempting to Visit a DIL ErrorNode.");
 }
@@ -27,6 +37,10 @@ llvm::Expected<lldb::ValueObjectSP> 
UnaryOpNode::Accept(Visitor *v) const {
   return v->Visit(*this);
 }
 
+llvm::Expected<lldb::ValueObjectSP> BinaryOpNode::Accept(Visitor *v) const {
+  return v->Visit(*this);
+}
+
 llvm::Expected<lldb::ValueObjectSP>
 ArraySubscriptNode::Accept(Visitor *v) const {
   return v->Visit(*this);
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index 187cc9bb16180..b30632ca7800d 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -127,6 +127,85 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, 
uint32_t location) {
   return valobj;
 }
 
+static size_t IntegerConversionRank(CompilerType type) {
+  switch (type.GetCanonicalType().GetBasicTypeEnumeration()) {
+  case lldb::eBasicTypeBool:
+    return 1;
+  case lldb::eBasicTypeChar:
+  case lldb::eBasicTypeSignedChar:
+  case lldb::eBasicTypeUnsignedChar:
+    return 2;
+  case lldb::eBasicTypeShort:
+  case lldb::eBasicTypeUnsignedShort:
+    return 3;
+  case lldb::eBasicTypeInt:
+  case lldb::eBasicTypeUnsignedInt:
+    return 4;
+  case lldb::eBasicTypeLong:
+  case lldb::eBasicTypeUnsignedLong:
+    return 5;
+  case lldb::eBasicTypeLongLong:
+  case lldb::eBasicTypeUnsignedLongLong:
+    return 6;
+  case lldb::eBasicTypeInt128:
+  case lldb::eBasicTypeUnsignedInt128:
+    return 7;
+  default:
+    break;
+  }
+  return 0;
+}
+
+llvm::Expected<CompilerType>
+Interpreter::ArithmeticConversion(lldb::ValueObjectSP &lhs,
+                                  lldb::ValueObjectSP &rhs, uint32_t location) 
{
+  // Apply unary conversion for both operands.
+  auto lhs_or_err = UnaryConversion(lhs, location);
+  if (!lhs_or_err)
+    return lhs_or_err.takeError();
+  lhs = *lhs_or_err;
+  auto rhs_or_err = UnaryConversion(rhs, location);
+  if (!rhs_or_err)
+    return rhs_or_err.takeError();
+  rhs = *rhs_or_err;
+
+  CompilerType lhs_type = lhs->GetCompilerType();
+  CompilerType rhs_type = rhs->GetCompilerType();
+
+  if (lhs_type.CompareTypes(rhs_type))
+    return lhs_type;
+
+  // If either of the operands is not arithmetic (e.g. pointer), we're done.
+  if (!lhs_type.IsScalarType() || !rhs_type.IsScalarType())
+    return CompilerType();
+
+  // Handle conversions for floating types (float, double).
+  if (lhs_type.IsFloat() || rhs_type.IsFloat()) {
+    // If both are floats, convert the smaller operand to the bigger.
+    if (lhs_type.IsFloat() && rhs_type.IsFloat()) {
+      if (lhs_type.GetBasicTypeEnumeration() >
+          rhs_type.GetBasicTypeEnumeration())
+        return lhs_type;
+      return rhs_type;
+    }
+    if (lhs_type.IsFloat() && rhs_type.IsInteger())
+      return lhs_type;
+    return rhs_type;
+  }
+
+  if (lhs_type.IsInteger() && rhs_type.IsInteger()) {
+    using Rank = std::tuple<size_t, bool>;
+    Rank l_rank = {IntegerConversionRank(lhs_type), !lhs_type.IsSigned()};
+    Rank r_rank = {IntegerConversionRank(rhs_type), !rhs_type.IsSigned()};
+
+    if (l_rank < r_rank)
+      return rhs_type;
+    if (l_rank > r_rank)
+      return lhs_type;
+  }
+  return rhs_type;
+}
+
 static lldb::VariableSP DILFindVariable(ConstString name,
                                         VariableList &variable_list) {
   lldb::VariableSP exact_match;
@@ -393,6 +472,82 @@ Interpreter::Visit(const UnaryOpNode &node) {
                                               node.GetLocation());
 }
 
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::EvaluateScalarOp(BinaryOpKind kind, lldb::ValueObjectSP lhs,
+                              lldb::ValueObjectSP rhs, CompilerType 
result_type,
+                              uint32_t location) {
+  Scalar l, r;
+  bool l_resolved = lhs->ResolveValue(l);
+  bool r_resolved = rhs->ResolveValue(r);
+
+  if (!l_resolved || !r_resolved)
+    return llvm::make_error<DILDiagnosticError>(m_expr, "invalid scalar value",
+                                                location);
+
+  auto value_object = [this, result_type](Scalar scalar) {
+    return ValueObject::CreateValueObjectFromScalar(m_target, scalar,
+                                                    result_type, "result");
+  };
+
+  switch (kind) {
+  case BinaryOpKind::Add:
+    return value_object(l + r);
+  }
+  return llvm::make_error<DILDiagnosticError>(
+      m_expr, "invalid arithmetic operation", location);
+}
+
+llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryAddition(
+    lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) {
+  // Operation '+' works for:
+  //   {scalar,unscoped_enum} <-> {scalar,unscoped_enum}
+  // TODO: Pointer arithmetics
+  auto orig_lhs_type = lhs->GetCompilerType();
+  auto orig_rhs_type = rhs->GetCompilerType();
+  auto type_or_err = ArithmeticConversion(lhs, rhs, location);
+  if (!type_or_err)
+    return type_or_err.takeError();
+  CompilerType result_type = *type_or_err;
+
+  if (result_type.IsScalarType())
+    return EvaluateScalarOp(BinaryOpKind::Add, lhs, rhs, result_type, 
location);
+
+  std::string errMsg =
+      llvm::formatv("invalid operands to binary expression ('{0}' and '{1}')",
+                    orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
+  return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, location);
+}
+
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const BinaryOpNode &node) {
+  auto lhs_or_err = EvaluateAndDereference(node.GetLHS());
+  if (!lhs_or_err)
+    return lhs_or_err;
+  lldb::ValueObjectSP lhs = *lhs_or_err;
+  auto rhs_or_err = EvaluateAndDereference(node.GetRHS());
+  if (!rhs_or_err)
+    return rhs_or_err;
+  lldb::ValueObjectSP rhs = *rhs_or_err;
+
+  lldb::TypeSystemSP lhs_system =
+      lhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+  lldb::TypeSystemSP rhs_system =
+      rhs->GetCompilerType().GetTypeSystem().GetSharedPointer();
+  if (lhs_system->GetPluginName() != rhs_system->GetPluginName()) {
+    // TODO: Attempt to convert values to current CU's type system
+    return llvm::make_error<DILDiagnosticError>(
+        m_expr, "operands have different type systems", node.GetLocation());
+  }
+
+  switch (node.GetKind()) {
+  case BinaryOpKind::Add:
+    return EvaluateBinaryAddition(lhs, rhs, node.GetLocation());
+  }
+
+  return llvm::make_error<DILDiagnosticError>(
+      m_expr, "unimplemented binary operation", node.GetLocation());
+}
+
 llvm::Expected<lldb::ValueObjectSP>
 Interpreter::Visit(const MemberOfNode &node) {
   auto base_or_err = Evaluate(node.GetBase());
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index df8d4d271c410..f07607c93d927 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -127,7 +127,29 @@ ASTNodeUP DILParser::Run() {
 //  expression:
 //    cast_expression
 //
-ASTNodeUP DILParser::ParseExpression() { return ParseCastExpression(); }
+ASTNodeUP DILParser::ParseExpression() { return ParseAdditiveExpression(); }
+
+// Parse an additive_expression.
+//
+//  additive_expression:
+//    cast_expression {"+" cast_expression}
+//
+ASTNodeUP DILParser::ParseAdditiveExpression() {
+  auto lhs = ParseCastExpression();
+  assert(lhs && "ASTNodeUP must not contain a nullptr");
+
+  while (CurToken().Is(Token::plus)) {
+    Token token = CurToken();
+    m_dil_lexer.Advance();
+    auto rhs = ParseCastExpression();
+    assert(rhs && "ASTNodeUP must not contain a nullptr");
+    lhs = std::make_unique<BinaryOpNode>(
+        token.GetLocation(), GetBinaryOpKindFromToken(token.GetKind()),
+        std::move(lhs), std::move(rhs));
+  }
+
+  return lhs;
+}
 
 // Parse a cast_expression.
 //
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
index 53a85fed303f4..fe8ee99835311 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -13,7 +13,7 @@ class TestFrameVarDILArithmetic(TestBase):
 
     def test_arithmetic(self):
         self.build()
-        lldbutil.run_to_source_breakpoint(
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
             self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
         )
 
@@ -44,3 +44,36 @@ def test_arithmetic(self):
         self.expect_var_path("+bitfield.b", value="2", type="int")
         self.expect_var_path("+bitfield.c", value="3", type="unsigned int")
         self.expect_var_path("+bitfield.d", value="4", type="uint64_t")
+
+        # Check basic math and resulting types
+        self.expect_var_path("1 + 2", value="3", type="int")
+        self.expect_var_path("1 + true", value="2", type="int")
+        self.expect_var_path("1L + wchar", value="2", type="long")
+        self.expect_var_path("1L + char16", value="3", type="long")
+        self.expect_var_path("1LL + char32", value="4", type="long long")
+        self.expect_var_path("1UL + 1L", value="2", type="unsigned long")
+        self.expect_var_path("s + x", value="12", type="int")
+        self.expect_var_path("s + l", value="15", type="long")
+        self.expect_var_path("1.0 + 2.5", value="3.5", type="double")
+        self.expect_var_path("1 + 2.5f", value="3.5", type="float")
+        self.expect_var_path("2. + .5", value="2.5", type="double")
+        self.expect_var_path("2.f + .5f", value="2.5", type="float")
+        self.expect_var_path("f + d", value="3.5", type="double")
+
+        # Check limits and overflows
+        frame = thread.GetFrameAtIndex(0)
+        int_min = frame.GetValueForVariablePath("int_min").GetValue()
+        int_max = frame.GetValueForVariablePath("int_max").GetValue()
+        uint_max = frame.GetValueForVariablePath("uint_max").GetValue()
+        ll_max = frame.GetValueForVariablePath("ll_max").GetValue()
+        ll_min = frame.GetValueForVariablePath("ll_min").GetValue()
+        ull_max = frame.GetValueForVariablePath("ull_max").GetValue()
+        self.expect_var_path("int_max + 1", value=int_min)
+        self.expect_var_path("uint_max + 1", value="0")
+        self.expect_var_path("ll_max + 1", value=ll_min)
+        self.expect_var_path("ull_max + 1", value="0")
+
+        # Check references and typedefs
+        self.expect_var_path("ref + 1", value="3")
+        self.expect_var_path("my_ref + 1", value="3")
+        self.expect_var_path("ref + my_ref", value="4")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
index 2c70e93433f5f..129a4214a42c4 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
@@ -1,11 +1,19 @@
 #include <cstdint>
+#include <limits>
 
 int main(int argc, char **argv) {
   short s = 10;
   unsigned short us = 1;
+  long l = 5;
+  float f = 1.0f;
+  double d = 2.5;
 
   int x = 2;
   int &ref = x;
+  int *p = &x;
+  typedef int &myref;
+  myref my_ref = x;
+
   enum Enum { kZero, kOne } enum_one = kOne;
   wchar_t wchar = 1;
   char16_t char16 = 2;
@@ -19,5 +27,14 @@ int main(int argc, char **argv) {
   };
   BitFieldStruct bitfield = {1, 2, 3, 4};
 
+  int int_max = std::numeric_limits<int>::max();
+  int int_min = std::numeric_limits<int>::min();
+  unsigned int uint_max = std::numeric_limits<unsigned int>::max();
+  unsigned int uint_zero = 0;
+  long long ll_max = std::numeric_limits<long long>::max();
+  long long ll_min = std::numeric_limits<long long>::min();
+  unsigned long long ull_max = std::numeric_limits<unsigned long long>::max();
+  unsigned long long ull_zero = 0;
+
   return 0; // Set a breakpoint here
 }

>From 0eaffcd2e6c2599c95ab954d25ea68531b8d7c93 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Fri, 13 Feb 2026 19:08:09 +0500
Subject: [PATCH 2/6] Fix IsFloat() after rebase

---
 lldb/source/ValueObject/DILEval.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index b30632ca7800d..fdd27401b4078 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -180,15 +180,17 @@ Interpreter::ArithmeticConversion(lldb::ValueObjectSP 
&lhs,
     return CompilerType();
 
   // Handle conversions for floating types (float, double).
-  if (lhs_type.IsFloat() || rhs_type.IsFloat()) {
+  if (lhs_type.IsRealFloatingPointType() ||
+      rhs_type.IsRealFloatingPointType()) {
     // If both are floats, convert the smaller operand to the bigger.
-    if (lhs_type.IsFloat() && rhs_type.IsFloat()) {
+    if (lhs_type.IsRealFloatingPointType() &&
+        rhs_type.IsRealFloatingPointType()) {
       if (lhs_type.GetBasicTypeEnumeration() >
           rhs_type.GetBasicTypeEnumeration())
         return lhs_type;
       return rhs_type;
     }
-    if (lhs_type.IsFloat() && rhs_type.IsInteger())
+    if (lhs_type.IsRealFloatingPointType() && rhs_type.IsInteger())
       return lhs_type;
     return rhs_type;
   }

>From ca9822741ee1e76b9e047bbaa862de41dd65e752 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Mon, 16 Feb 2026 17:41:53 +0500
Subject: [PATCH 3/6] Add more tests

---
 .../frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
index fe8ee99835311..75f13f79f83da 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -59,6 +59,9 @@ def test_arithmetic(self):
         self.expect_var_path("2. + .5", value="2.5", type="double")
         self.expect_var_path("2.f + .5f", value="2.5", type="float")
         self.expect_var_path("f + d", value="3.5", type="double")
+        self.expect_var_path("1 + s + (x + l)", value="18", type="long")
+        self.expect_var_path("+2 + (-1)", value="1", type="int")
+        self.expect_var_path("-2 + (+1)", value="-1", type="int")
 
         # Check limits and overflows
         frame = thread.GetFrameAtIndex(0)

>From 3c5e3f4e0f7e8c8856bf8bbdde18384b4646a498 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 19 Feb 2026 00:48:27 +0500
Subject: [PATCH 4/6] Redo ConversionRank logic, add comments, adjust
 formatting

---
 lldb/source/ValueObject/DILEval.cpp           | 46 ++++++++-----------
 .../Arithmetic/TestFrameVarDILArithmetic.py   |  1 +
 .../frame/var-dil/expr/Arithmetic/main.cpp    |  1 +
 3 files changed, 20 insertions(+), 28 deletions(-)

diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index fdd27401b4078..12f69579b0908 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -127,7 +127,9 @@ Interpreter::UnaryConversion(lldb::ValueObjectSP valobj, 
uint32_t location) {
   return valobj;
 }
 
-static size_t IntegerConversionRank(CompilerType type) {
+/// Basic types with a lower rank are converted to the basic type
+/// with a higher rank.
+static size_t ConversionRank(CompilerType type) {
   switch (type.GetCanonicalType().GetBasicTypeEnumeration()) {
   case lldb::eBasicTypeBool:
     return 1;
@@ -150,6 +152,14 @@ static size_t IntegerConversionRank(CompilerType type) {
   case lldb::eBasicTypeInt128:
   case lldb::eBasicTypeUnsignedInt128:
     return 7;
+  case lldb::eBasicTypeHalf:
+    return 8;
+  case lldb::eBasicTypeFloat:
+    return 9;
+  case lldb::eBasicTypeDouble:
+    return 10;
+  case lldb::eBasicTypeLongDouble:
+    return 11;
   default:
     break;
   }
@@ -172,6 +182,7 @@ Interpreter::ArithmeticConversion(lldb::ValueObjectSP &lhs,
   CompilerType lhs_type = lhs->GetCompilerType();
   CompilerType rhs_type = rhs->GetCompilerType();
 
+  // If types already match, no need for further conversions
   if (lhs_type.CompareTypes(rhs_type))
     return lhs_type;
 
@@ -179,32 +190,10 @@ Interpreter::ArithmeticConversion(lldb::ValueObjectSP 
&lhs,
   if (!lhs_type.IsScalarType() || !rhs_type.IsScalarType())
     return CompilerType();
 
-  // Handle conversions for floating types (float, double).
-  if (lhs_type.IsRealFloatingPointType() ||
-      rhs_type.IsRealFloatingPointType()) {
-    // If both are floats, convert the smaller operand to the bigger.
-    if (lhs_type.IsRealFloatingPointType() &&
-        rhs_type.IsRealFloatingPointType()) {
-      if (lhs_type.GetBasicTypeEnumeration() >
-          rhs_type.GetBasicTypeEnumeration())
-        return lhs_type;
-      return rhs_type;
-    }
-    if (lhs_type.IsRealFloatingPointType() && rhs_type.IsInteger())
-      return lhs_type;
-    return rhs_type;
-  }
-
-  if (lhs_type.IsInteger() && rhs_type.IsInteger()) {
-    using Rank = std::tuple<size_t, bool>;
-    Rank l_rank = {IntegerConversionRank(lhs_type), !lhs_type.IsSigned()};
-    Rank r_rank = {IntegerConversionRank(rhs_type), !rhs_type.IsSigned()};
-
-    if (l_rank < r_rank)
-      return rhs_type;
-    if (l_rank > r_rank)
-      return lhs_type;
-  }
+  using Rank = std::tuple<size_t, bool>;
+  if (Rank{ConversionRank(lhs_type), !lhs_type.IsSigned()} >
+      Rank{ConversionRank(rhs_type), !rhs_type.IsSigned()})
+    return lhs_type;
   return rhs_type;
 }
 
@@ -517,7 +506,8 @@ llvm::Expected<lldb::ValueObjectSP> 
Interpreter::EvaluateBinaryAddition(
   std::string errMsg =
       llvm::formatv("invalid operands to binary expression ('{0}' and '{1}')",
                     orig_lhs_type.GetTypeName(), orig_rhs_type.GetTypeName());
-  return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, location);
+  return llvm::make_error<DILDiagnosticError>(m_expr, std::move(errMsg),
+                                              location);
 }
 
 llvm::Expected<lldb::ValueObjectSP>
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
index 75f13f79f83da..22b22ecaf2e5a 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -54,6 +54,7 @@ def test_arithmetic(self):
         self.expect_var_path("1UL + 1L", value="2", type="unsigned long")
         self.expect_var_path("s + x", value="12", type="int")
         self.expect_var_path("s + l", value="15", type="long")
+        self.expect_var_path("l + ul", value="11", type="unsigned long")
         self.expect_var_path("1.0 + 2.5", value="3.5", type="double")
         self.expect_var_path("1 + 2.5f", value="3.5", type="float")
         self.expect_var_path("2. + .5", value="2.5", type="double")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
index 129a4214a42c4..0961199add9cb 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
@@ -5,6 +5,7 @@ int main(int argc, char **argv) {
   short s = 10;
   unsigned short us = 1;
   long l = 5;
+  unsigned long ul = 6;
   float f = 1.0f;
   double d = 2.5;
 

>From af3dfe34d988d283668e7c2e289026f0d53ef89a Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 19 Feb 2026 03:48:32 +0500
Subject: [PATCH 5/6] Add PromoteSignedInteger

---
 lldb/include/lldb/ValueObject/DILEval.h       |  7 ++
 lldb/source/ValueObject/DILEval.cpp           | 81 +++++++++++++++++--
 .../Arithmetic/TestFrameVarDILArithmetic.py   | 16 +++-
 .../frame/var-dil/expr/Arithmetic/main.cpp    |  4 +-
 4 files changed, 97 insertions(+), 11 deletions(-)

diff --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index 6807a6616b846..1846035070a14 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -75,6 +75,13 @@ class Interpreter : Visitor {
   llvm::Expected<lldb::ValueObjectSP>
   UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location);
 
+  /// If `lhs_type` is unsigned and `rhs_type` is signed, check whether it
+  /// can represent all of the values of `lhs_type`.
+  /// If not, then promote `rhs_type` to the unsigned version of its type.
+  /// \returns Unchanged `rhs_type` or promoted unsigned version.
+  llvm::Expected<CompilerType> PromoteSignedInteger(CompilerType &lhs_type,
+                                                    CompilerType &rhs_type);
+
   /// Perform an arithmetic conversion on two values from an arithmetic
   /// operation.
   /// \returns The result type of an arithmetic operation.
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index 12f69579b0908..c0db985005ae3 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -166,6 +166,55 @@ static size_t ConversionRank(CompilerType type) {
   return 0;
 }
 
+static lldb::BasicType BasicTypeToUnsigned(lldb::BasicType basic_type) {
+  switch (basic_type) {
+  case lldb::eBasicTypeChar:
+  case lldb::eBasicTypeSignedChar:
+    return lldb::eBasicTypeUnsignedChar;
+  case lldb::eBasicTypeShort:
+    return lldb::eBasicTypeUnsignedShort;
+  case lldb::eBasicTypeInt:
+    return lldb::eBasicTypeUnsignedInt;
+  case lldb::eBasicTypeLong:
+    return lldb::eBasicTypeUnsignedLong;
+  case lldb::eBasicTypeLongLong:
+    return lldb::eBasicTypeUnsignedLongLong;
+  case lldb::eBasicTypeInt128:
+    return lldb::eBasicTypeUnsignedInt128;
+  default:
+    return basic_type;
+  }
+}
+
+llvm::Expected<CompilerType>
+Interpreter::PromoteSignedInteger(CompilerType &lhs_type,
+                                  CompilerType &rhs_type) {
+  // This expects that Rank(lhs_type) < Rank(rhs_type).
+  if (!lhs_type.IsSigned() && rhs_type.IsSigned()) {
+    llvm::Expected<uint64_t> lhs_size =
+        lhs_type.GetBitSize(m_exe_ctx_scope.get());
+    if (!lhs_size)
+      return lhs_size.takeError();
+    llvm::Expected<uint64_t> rhs_size =
+        rhs_type.GetBitSize(m_exe_ctx_scope.get());
+    if (!rhs_size)
+      return rhs_size.takeError();
+
+    if (*rhs_size == *lhs_size) {
+      llvm::Expected<lldb::TypeSystemSP> type_system =
+          GetTypeSystemFromCU(m_exe_ctx_scope);
+      if (!type_system)
+        return type_system.takeError();
+      CompilerType r_type_unsigned = GetBasicType(
+          *type_system,
+          BasicTypeToUnsigned(
+              rhs_type.GetCanonicalType().GetBasicTypeEnumeration()));
+      return r_type_unsigned;
+    }
+  }
+  return rhs_type;
+}
+
 llvm::Expected<CompilerType>
 Interpreter::ArithmeticConversion(lldb::ValueObjectSP &lhs,
                                   lldb::ValueObjectSP &rhs, uint32_t location) 
{
@@ -182,7 +231,7 @@ Interpreter::ArithmeticConversion(lldb::ValueObjectSP &lhs,
   CompilerType lhs_type = lhs->GetCompilerType();
   CompilerType rhs_type = rhs->GetCompilerType();
 
-  // If types already match, no need for further conversions
+  // If types already match, no need for further conversions.
   if (lhs_type.CompareTypes(rhs_type))
     return lhs_type;
 
@@ -190,11 +239,33 @@ Interpreter::ArithmeticConversion(lldb::ValueObjectSP 
&lhs,
   if (!lhs_type.IsScalarType() || !rhs_type.IsScalarType())
     return CompilerType();
 
-  using Rank = std::tuple<size_t, bool>;
-  if (Rank{ConversionRank(lhs_type), !lhs_type.IsSigned()} >
-      Rank{ConversionRank(rhs_type), !rhs_type.IsSigned()})
+  size_t l_rank = ConversionRank(lhs_type);
+  size_t r_rank = ConversionRank(rhs_type);
+  // If both operands are integer, check if we need to promote
+  // the higher ranked signed type.
+  if (lhs_type.IsInteger() && rhs_type.IsInteger()) {
+    using Rank = std::tuple<size_t, bool>;
+    Rank int_l_rank = {l_rank, !lhs_type.IsSigned()};
+    Rank int_r_rank = {r_rank, !rhs_type.IsSigned()};
+    if (int_l_rank < int_r_rank) {
+      auto type_or_err = PromoteSignedInteger(lhs_type, rhs_type);
+      if (!type_or_err)
+        return type_or_err.takeError();
+      return *type_or_err;
+    }
+    if (int_l_rank > int_r_rank) {
+      auto type_or_err = PromoteSignedInteger(rhs_type, lhs_type);
+      if (!type_or_err)
+        return type_or_err.takeError();
+      return *type_or_err;
+    }
     return lhs_type;
-  return rhs_type;
+  }
+
+  // Handle other combinations of integer and floating point operands.
+  if (l_rank < r_rank)
+    return rhs_type;
+  return lhs_type;
 }
 
 static lldb::VariableSP DILFindVariable(ConstString name,
diff --git 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
index 22b22ecaf2e5a..5b68c493ba3a5 100644
--- 
a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
+++ 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
@@ -67,16 +67,24 @@ def test_arithmetic(self):
         # Check limits and overflows
         frame = thread.GetFrameAtIndex(0)
         int_min = frame.GetValueForVariablePath("int_min").GetValue()
-        int_max = frame.GetValueForVariablePath("int_max").GetValue()
-        uint_max = frame.GetValueForVariablePath("uint_max").GetValue()
-        ll_max = frame.GetValueForVariablePath("ll_max").GetValue()
         ll_min = frame.GetValueForVariablePath("ll_min").GetValue()
-        ull_max = frame.GetValueForVariablePath("ull_max").GetValue()
         self.expect_var_path("int_max + 1", value=int_min)
         self.expect_var_path("uint_max + 1", value="0")
         self.expect_var_path("ll_max + 1", value=ll_min)
         self.expect_var_path("ull_max + 1", value="0")
 
+        # Check signed integer promotion when different types have the same 
size
+        uint = frame.GetValueForVariablePath("ui")
+        long = frame.GetValueForVariablePath("l")
+        if uint.GetByteSize() == long.GetByteSize():
+            self.expect_var_path("ui + l", value="9", type="unsigned long")
+            self.expect_var_path("l + ui", value="9", type="unsigned long")
+        ulong = frame.GetValueForVariablePath("ul")
+        longlong = frame.GetValueForVariablePath("ll")
+        if ulong.GetByteSize() == longlong.GetByteSize():
+            self.expect_var_path("ul + ll", value="13", type="unsigned long 
long")
+            self.expect_var_path("ll + ul", value="13", type="unsigned long 
long")
+
         # Check references and typedefs
         self.expect_var_path("ref + 1", value="3")
         self.expect_var_path("my_ref + 1", value="3")
diff --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp 
b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
index 0961199add9cb..f41b89beb2bde 100644
--- a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
+++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp
@@ -4,8 +4,10 @@
 int main(int argc, char **argv) {
   short s = 10;
   unsigned short us = 1;
+  unsigned int ui = 4;
   long l = 5;
   unsigned long ul = 6;
+  long long ll = 7;
   float f = 1.0f;
   double d = 2.5;
 
@@ -31,11 +33,9 @@ int main(int argc, char **argv) {
   int int_max = std::numeric_limits<int>::max();
   int int_min = std::numeric_limits<int>::min();
   unsigned int uint_max = std::numeric_limits<unsigned int>::max();
-  unsigned int uint_zero = 0;
   long long ll_max = std::numeric_limits<long long>::max();
   long long ll_min = std::numeric_limits<long long>::min();
   unsigned long long ull_max = std::numeric_limits<unsigned long long>::max();
-  unsigned long long ull_zero = 0;
 
   return 0; // Set a breakpoint here
 }

>From 807bd01ceca359477c0d0ac8d03c0f8ffa8f4e3f Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <[email protected]>
Date: Thu, 19 Feb 2026 03:50:36 +0500
Subject: [PATCH 6/6] Check if conversion rank is 0

---
 lldb/source/ValueObject/DILEval.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index c0db985005ae3..b64e4723473d1 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -241,6 +241,10 @@ Interpreter::ArithmeticConversion(lldb::ValueObjectSP &lhs,
 
   size_t l_rank = ConversionRank(lhs_type);
   size_t r_rank = ConversionRank(rhs_type);
+  if (l_rank == 0 || r_rank == 0)
+    return llvm::make_error<DILDiagnosticError>(
+        m_expr, "unexpected basic type in arithmetic operation", location);
+
   // If both operands are integer, check if we need to promote
   // the higher ranked signed type.
   if (lhs_type.IsInteger() && rhs_type.IsInteger()) {

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

Reply via email to