llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Ilia Kuklin (kuilpd)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/177208.diff


9 Files Affected:

- (modified) lldb/docs/dil-expr-lang.ebnf (+3-1) 
- (modified) lldb/include/lldb/ValueObject/DILAST.h (+35) 
- (modified) lldb/include/lldb/ValueObject/DILEval.h (+16) 
- (modified) lldb/include/lldb/ValueObject/DILParser.h (+1) 
- (modified) lldb/source/ValueObject/DILAST.cpp (+14) 
- (modified) lldb/source/ValueObject/DILEval.cpp (+155) 
- (modified) lldb/source/ValueObject/DILParser.cpp (+21-1) 
- (modified) 
lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py
 (+34-1) 
- (modified) lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp 
(+17) 


``````````diff
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 bd2fc373cd9b5..d36e9084dfcb5 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -87,6 +87,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 68a2a228962fb..e6f701b54c7f4 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -139,6 +139,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;
@@ -405,6 +484,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 7dc284c8e070e..2283e96ff95e2 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -85,7 +85,27 @@ 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();
+
+  while (CurToken().Is(Token::plus)) {
+    Token token = CurToken();
+    m_dil_lexer.Advance();
+    auto rhs = ParseCastExpression();
+    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
 }

``````````

</details>


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

Reply via email to