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/134428.diff


9 Files Affected:

- (modified) lldb/docs/dil-expr-lang.ebnf (+3-1) 
- (modified) lldb/include/lldb/ValueObject/DILAST.h (+32) 
- (modified) lldb/include/lldb/ValueObject/DILEval.h (+29) 
- (modified) lldb/include/lldb/ValueObject/DILLexer.h (+2) 
- (modified) lldb/include/lldb/ValueObject/DILParser.h (+1) 
- (modified) lldb/source/ValueObject/DILAST.cpp (+4) 
- (modified) lldb/source/ValueObject/DILEval.cpp (+136-3) 
- (modified) lldb/source/ValueObject/DILLexer.cpp (+6-3) 
- (modified) lldb/source/ValueObject/DILParser.cpp (+31-1) 


``````````diff
diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index 0bbbecbdc78c1..13b9cc22e6000 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 = primary_expression ;
+expression = unary_expression ;
+
+unary_expression = unary_operator primary_expression ;
 
 primary_expression = id_expression
                    | "(" expression ")";
diff --git a/lldb/include/lldb/ValueObject/DILAST.h 
b/lldb/include/lldb/ValueObject/DILAST.h
index 05d87e9cc4b6b..323ebe8dd49ec 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -20,6 +20,13 @@ namespace lldb_private::dil {
 enum class NodeKind {
   eErrorNode,
   eIdentifierNode,
+  eUnaryOpNode,
+};
+
+/// The Unary operators recognized by DIL.
+enum class UnaryOpKind {
+  AddrOf, // "&"
+  Deref,  // "*"
 };
 
 /// Forward declaration, for use in DIL AST nodes. Definition is at the very
@@ -44,6 +51,8 @@ class ASTNode {
 
   virtual llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const = 0;
 
+  virtual bool is_rvalue() const { return false; }
+
   uint32_t GetLocation() const { return m_location; }
   NodeKind GetKind() const { return m_kind; }
 
@@ -81,6 +90,27 @@ class IdentifierNode : public ASTNode {
   std::string m_name;
 };
 
+class UnaryOpNode : public ASTNode {
+public:
+  UnaryOpNode(uint32_t location, UnaryOpKind kind, ASTNodeUP rhs)
+      : ASTNode(location, NodeKind::eUnaryOpNode), m_kind(kind),
+        m_rhs(std::move(rhs)) {}
+
+  llvm::Expected<lldb::ValueObjectSP> Accept(Visitor *v) const override;
+  bool is_rvalue() const override { return m_kind != UnaryOpKind::Deref; }
+
+  UnaryOpKind kind() const { return m_kind; }
+  ASTNode *rhs() const { return m_rhs.get(); }
+
+  static bool classof(const ASTNode *node) {
+    return node->GetKind() == NodeKind::eUnaryOpNode;
+  }
+
+private:
+  UnaryOpKind m_kind;
+  ASTNodeUP m_rhs;
+};
+
 /// This class contains one Visit method for each specialized type of
 /// DIL AST node. The Visit methods are used to dispatch a DIL AST node to
 /// the correct function in the DIL expression evaluator for evaluating that
@@ -90,6 +120,8 @@ class Visitor {
   virtual ~Visitor() = default;
   virtual llvm::Expected<lldb::ValueObjectSP>
   Visit(const IdentifierNode *node) = 0;
+  virtual llvm::Expected<lldb::ValueObjectSP>
+  Visit(const UnaryOpNode *node) = 0;
 };
 
 } // namespace lldb_private::dil
diff --git a/lldb/include/lldb/ValueObject/DILEval.h 
b/lldb/include/lldb/ValueObject/DILEval.h
index 335035d3f9248..0080f4dba9291 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -38,6 +38,18 @@ lldb::ValueObjectSP LookupGlobalIdentifier(llvm::StringRef 
name_ref,
                                            lldb::DynamicValueType use_dynamic,
                                            CompilerType *scope_ptr = nullptr);
 
+class FlowAnalysis {
+public:
+  FlowAnalysis(bool address_of_is_pending)
+      : m_address_of_is_pending(address_of_is_pending) {}
+
+  bool AddressOfIsPending() const { return m_address_of_is_pending; }
+  void DiscardAddressOf() { m_address_of_is_pending = false; }
+
+private:
+  bool m_address_of_is_pending;
+};
+
 class Interpreter : Visitor {
 public:
   Interpreter(lldb::TargetSP target, llvm::StringRef expr,
@@ -47,12 +59,29 @@ class Interpreter : Visitor {
   llvm::Expected<lldb::ValueObjectSP> Evaluate(const ASTNode *node);
 
 private:
+  llvm::Expected<lldb::ValueObjectSP>
+  EvaluateNode(const ASTNode *node, FlowAnalysis *flow = nullptr);
+
   llvm::Expected<lldb::ValueObjectSP>
   Visit(const IdentifierNode *node) override;
+  llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode *node) override;
+
+  lldb::ValueObjectSP EvaluateDereference(lldb::ValueObjectSP rhs);
+
+  FlowAnalysis *flow_analysis() { return m_flow_analysis_chain.back(); }
 
   // Used by the interpreter to create objects, perform casts, etc.
   lldb::TargetSP m_target;
   llvm::StringRef m_expr;
+  // Flow analysis chain represents the expression evaluation flow for the
+  // current code branch. Each node in the chain corresponds to an AST node,
+  // describing the semantics of the evaluation for it. Currently, flow 
analysis
+  // propagates the information about the pending address-of operator, so that
+  // combination of address-of and a subsequent dereference can be eliminated.
+  // End of the chain (i.e. `back()`) contains the flow analysis instance for
+  // the current node. It may be `nullptr` if no relevant information is
+  // available, the caller/user is supposed to check.
+  std::vector<FlowAnalysis *> m_flow_analysis_chain;
   lldb::ValueObjectSP m_scope;
   lldb::DynamicValueType m_default_dynamic;
   std::shared_ptr<StackFrame> m_exe_ctx_scope;
diff --git a/lldb/include/lldb/ValueObject/DILLexer.h 
b/lldb/include/lldb/ValueObject/DILLexer.h
index d15fc382d1623..3508b8b7a85c6 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -24,11 +24,13 @@ namespace lldb_private::dil {
 class Token {
 public:
   enum Kind {
+    amp,
     coloncolon,
     eof,
     identifier,
     l_paren,
     r_paren,
+    star,
   };
 
   Token(Kind kind, std::string spelling, uint32_t start)
diff --git a/lldb/include/lldb/ValueObject/DILParser.h 
b/lldb/include/lldb/ValueObject/DILParser.h
index 9b7a6cd487939..9f09994a54729 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -83,6 +83,7 @@ class DILParser {
   ASTNodeUP Run();
 
   ASTNodeUP ParseExpression();
+  ASTNodeUP ParseUnaryExpression();
   ASTNodeUP ParsePrimaryExpression();
 
   std::string ParseNestedNameSpecifier();
diff --git a/lldb/source/ValueObject/DILAST.cpp 
b/lldb/source/ValueObject/DILAST.cpp
index e75958d784627..ea847587501ee 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -19,4 +19,8 @@ llvm::Expected<lldb::ValueObjectSP> 
IdentifierNode::Accept(Visitor *v) const {
   return v->Visit(this);
 }
 
+llvm::Expected<lldb::ValueObjectSP> UnaryOpNode::Accept(Visitor *v) const {
+  return v->Visit(this);
+}
+
 } // namespace lldb_private::dil
diff --git a/lldb/source/ValueObject/DILEval.cpp 
b/lldb/source/ValueObject/DILEval.cpp
index 4889834c7a3c1..b6aa349a62e62 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -18,6 +18,22 @@
 
 namespace lldb_private::dil {
 
+static lldb::ValueObjectSP
+ArrayToPointerConversion(lldb::ValueObjectSP valobj,
+                         std::shared_ptr<ExecutionContextScope> ctx) {
+  assert(valobj->IsArrayType() &&
+         "an argument to array-to-pointer conversion must be an array");
+
+  uint64_t addr = valobj->GetLoadAddress();
+  llvm::StringRef name = "result";
+  ExecutionContext exe_ctx;
+  ctx->CalculateExecutionContext(exe_ctx);
+  return ValueObject::CreateValueObjectFromAddress(
+      name, addr, exe_ctx,
+      
valobj->GetCompilerType().GetArrayElementType(ctx.get()).GetPointerType(),
+      /* do_deref */ false);
+}
+
 static lldb::ValueObjectSP LookupStaticIdentifier(
     VariableList &variable_list, std::shared_ptr<StackFrame> exe_scope,
     llvm::StringRef name_ref, llvm::StringRef unqualified_name) {
@@ -206,10 +222,25 @@ Interpreter::Interpreter(lldb::TargetSP target, 
llvm::StringRef expr,
     : m_target(std::move(target)), m_expr(expr), 
m_default_dynamic(use_dynamic),
       m_exe_ctx_scope(frame_sp) {}
 
-llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *node) 
{
+llvm::Expected<lldb::ValueObjectSP> Interpreter::Evaluate(const ASTNode *tree) 
{
+  // Evaluate an AST.
+  auto value_or_error = EvaluateNode(tree);
+
+  // Return the computed result-or-error.
+  return value_or_error;
+}
 
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::EvaluateNode(const ASTNode *node, FlowAnalysis *flow) {
+  // Set up the evaluation context for the current node.
+  m_flow_analysis_chain.push_back(flow);
   // Traverse an AST pointed by the `node`.
-  return node->Accept(this);
+  auto value_or_error = node->Accept(this);
+  // Cleanup the context.
+  m_flow_analysis_chain.pop_back();
+  // Return the computed value-or-error. The caller is responsible for
+  // checking if an error occured during the evaluation.
+  return value_or_error;
 }
 
 llvm::Expected<lldb::ValueObjectSP>
@@ -232,4 +263,106 @@ Interpreter::Visit(const IdentifierNode *node) {
   return identifier;
 }
 
-} // namespace lldb_private::dil
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::Visit(const UnaryOpNode *node) {
+  FlowAnalysis rhs_flow(
+      /* address_of_is_pending */ node->kind() == UnaryOpKind::AddrOf);
+
+  Status error;
+  auto rhs_or_err = EvaluateNode(node->rhs(), &rhs_flow);
+  if (!rhs_or_err) {
+    return rhs_or_err;
+  }
+  lldb::ValueObjectSP rhs = *rhs_or_err;
+
+  if (rhs->GetCompilerType().IsReferenceType()) {
+    rhs = rhs->Dereference(error);
+    if (error.Fail()) {
+      return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
+                                                  node->GetLocation(), 1);
+    }
+  }
+  CompilerType rhs_type = rhs->GetCompilerType();
+  switch (node->kind()) {
+  case UnaryOpKind::Deref: {
+    if (rhs_type.IsArrayType())
+      rhs = ArrayToPointerConversion(rhs, m_exe_ctx_scope);
+
+    lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_default_dynamic);
+    if (dynamic_rhs)
+      rhs = dynamic_rhs;
+
+    if (rhs->GetCompilerType().IsPointerType())
+      return EvaluateDereference(rhs);
+    lldb::ValueObjectSP child_sp = rhs->Dereference(error);
+    if (error.Success())
+      rhs = child_sp;
+
+    return rhs;
+  }
+  case UnaryOpKind::AddrOf: {
+    if (node->rhs()->is_rvalue()) {
+      std::string errMsg =
+          llvm::formatv("cannot take the address of an rvalue of type {0}",
+                        rhs_type.TypeDescription());
+      return llvm::make_error<DILDiagnosticError>(m_expr, errMsg,
+                                                  node->GetLocation(), 1);
+    }
+    if (rhs->IsBitfield()) {
+      return llvm::make_error<DILDiagnosticError>(
+          m_expr, "address of bit-field requested", node->GetLocation(), 1);
+    }
+    // If the address-of operation wasn't cancelled during the evaluation of
+    // RHS (e.g. because of the address-of-a-dereference elision), apply it
+    // here.
+    if (rhs_flow.AddressOfIsPending()) {
+      Status error;
+      lldb::ValueObjectSP value = rhs->AddressOf(error);
+      if (error.Fail()) {
+        return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(),
+                                                    node->GetLocation(), 1);
+      }
+      return value;
+    }
+    return rhs;
+  }
+  }
+
+  // Unsupported/invalid operation.
+  return llvm::make_error<DILDiagnosticError>(
+      m_expr, "invalid ast: unexpected binary operator", node->GetLocation(),
+      1);
+}
+
+lldb::ValueObjectSP Interpreter::EvaluateDereference(lldb::ValueObjectSP rhs) {
+  // If rhs is a reference, dereference it first.
+  Status error;
+  if (rhs->GetCompilerType().IsReferenceType())
+    rhs = rhs->Dereference(error);
+
+  assert(rhs->GetCompilerType().IsPointerType() &&
+         "invalid ast: must be a pointer type");
+
+  if (rhs->GetDerefValobj())
+    return rhs->GetDerefValobj()->GetSP();
+
+  CompilerType pointer_type = rhs->GetCompilerType();
+  lldb::addr_t base_addr = rhs->GetValueAsUnsigned(0);
+
+  llvm::StringRef name = "result";
+  ExecutionContext exe_ctx(m_target.get(), false);
+  lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress(
+      name, base_addr, exe_ctx, pointer_type,
+      /* do_deref */ false);
+
+  // If we're in the address-of context, skip the dereference and cancel the
+  // pending address-of operation as well.
+  if (flow_analysis() && flow_analysis()->AddressOfIsPending()) {
+    flow_analysis()->DiscardAddressOf();
+    return value;
+  }
+
+  return value->Dereference(error);
+}
+
+} // namespace lldb_private::dil
\ No newline at end of file
diff --git a/lldb/source/ValueObject/DILLexer.cpp 
b/lldb/source/ValueObject/DILLexer.cpp
index 1f013288c839b..b9c2e7971e3b4 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -19,6 +19,8 @@ namespace lldb_private::dil {
 
 llvm::StringRef Token::GetTokenName(Kind kind) {
   switch (kind) {
+  case Kind::amp:
+    return "amp";
   case Kind::coloncolon:
     return "coloncolon";
   case Kind::eof:
@@ -29,6 +31,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "l_paren";
   case Kind::r_paren:
     return "r_paren";
+  case Token::star:
+    return "star";
   }
   llvm_unreachable("Unknown token name");
 }
@@ -82,9 +86,8 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
     return Token(Token::identifier, maybe_word->str(), position);
 
   constexpr std::pair<Token::Kind, const char *> operators[] = {
-      {Token::l_paren, "("},
-      {Token::r_paren, ")"},
-      {Token::coloncolon, "::"},
+      {Token::amp, "&"},     {Token::coloncolon, "::"}, {Token::l_paren, "("},
+      {Token::r_paren, ")"}, {Token::star, "*"},
   };
   for (auto [kind, str] : operators) {
     if (remainder.consume_front(str))
diff --git a/lldb/source/ValueObject/DILParser.cpp 
b/lldb/source/ValueObject/DILParser.cpp
index a8baba2c06e7a..c233c535c0355 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -82,7 +82,37 @@ ASTNodeUP DILParser::Run() {
 //  expression:
 //    primary_expression
 //
-ASTNodeUP DILParser::ParseExpression() { return ParsePrimaryExpression(); }
+ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); }
+
+// Parse an unary_expression.
+//
+//  unary_expression:
+//    unary_operator primary_expression
+//
+//  unary_operator:
+//    "&"
+//    "*"
+//
+ASTNodeUP DILParser::ParseUnaryExpression() {
+  if (CurToken().IsOneOf({Token::amp, Token::star})) {
+    Token token = CurToken();
+    uint32_t loc = token.GetLocation();
+    m_dil_lexer.Advance();
+    auto rhs = ParsePrimaryExpression();
+    switch (token.GetKind()) {
+    case Token::star:
+      return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Deref,
+                                           std::move(rhs));
+    case Token::amp:
+      return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::AddrOf,
+                                           std::move(rhs));
+
+    default:
+      llvm_unreachable("invalid token kind");
+    }
+  }
+  return ParsePrimaryExpression();
+}
 
 // Parse a primary_expression.
 //

``````````

</details>


https://github.com/llvm/llvm-project/pull/134428
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to