[Lldb-commits] [lldb] d25f10e - [lldb] Add bitwise shift operators and fix literals' sign in DIL (#192506)

via lldb-commits lldb-commits at lists.llvm.org
Tue Jun 2 07:20:41 PDT 2026


Author: Ilia Kuklin
Date: 2026-06-02T19:20:35+05:00
New Revision: d25f10e8b4a37c2759925883fb59a9da4ea0eb94

URL: https://github.com/llvm/llvm-project/commit/d25f10e8b4a37c2759925883fb59a9da4ea0eb94
DIFF: https://github.com/llvm/llvm-project/commit/d25f10e8b4a37c2759925883fb59a9da4ea0eb94.diff

LOG: [lldb] Add bitwise shift operators and fix literals' sign in DIL (#192506)

This patch add bitwise shift operators and fixes the Scalar's sign
inside of the literals with signed types. The only way to test this fix,
for now, is to use these literals in an arithmetic right shift that does
sign extension, so this is included in this patch.

Added: 
    lldb/test/API/commands/frame/var-dil/expr/Bitwise/Makefile
    lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
    lldb/test/API/commands/frame/var-dil/expr/Bitwise/main.cpp

Modified: 
    lldb/docs/dil-expr-lang.ebnf
    lldb/include/lldb/ValueObject/DILAST.h
    lldb/include/lldb/ValueObject/DILEval.h
    lldb/include/lldb/ValueObject/DILLexer.h
    lldb/include/lldb/ValueObject/DILParser.h
    lldb/source/ValueObject/DILAST.cpp
    lldb/source/ValueObject/DILEval.cpp
    lldb/source/ValueObject/DILLexer.cpp
    lldb/source/ValueObject/DILParser.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf
index b80533c015c95..7c4a187c9cf52 100644
--- a/lldb/docs/dil-expr-lang.ebnf
+++ b/lldb/docs/dil-expr-lang.ebnf
@@ -3,7 +3,10 @@
 (* This is currently a subset of the final DIL Language, matching the current
    DIL implementation. *)
 
-expression = additive_expression ;
+expression = shift_expression ;
+
+shift_expression = additive_expression {"<<" additive_expression}
+                 | additive_expression {">>" additive_expression} ;
 
 additive_expression = multiplicative_expression {"+" multiplicative_expression}
                       multiplicative_expression {"-" multiplicative_expression} ;

diff  --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h
index 50530d687c41f..3235887c27f2c 100644
--- a/lldb/include/lldb/ValueObject/DILAST.h
+++ b/lldb/include/lldb/ValueObject/DILAST.h
@@ -47,6 +47,8 @@ enum class BinaryOpKind {
   Mul, // "*"
   Div, // "/"
   Rem, // "%"
+  Shl, // "<<"
+  Shr, // ">>"
 };
 
 /// Translates DIL tokens to BinaryOpKind.

diff  --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h
index a67c9e81e2898..645c010a27825 100644
--- a/lldb/include/lldb/ValueObject/DILEval.h
+++ b/lldb/include/lldb/ValueObject/DILEval.h
@@ -106,6 +106,9 @@ class Interpreter : Visitor {
                                                        CompilerType result_type,
                                                        uint32_t location);
   llvm::Expected<lldb::ValueObjectSP>
+  EvaluateBinaryShift(BinaryOpKind kind, lldb::ValueObjectSP lhs,
+                      lldb::ValueObjectSP rhs, uint32_t location);
+  llvm::Expected<lldb::ValueObjectSP>
   EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                          uint32_t location);
   llvm::Expected<lldb::ValueObjectSP>

diff  --git a/lldb/include/lldb/ValueObject/DILLexer.h b/lldb/include/lldb/ValueObject/DILLexer.h
index 1672e52b2adb0..82fbecd81f13b 100644
--- a/lldb/include/lldb/ValueObject/DILLexer.h
+++ b/lldb/include/lldb/ValueObject/DILLexer.h
@@ -31,12 +31,14 @@ class Token {
     coloncolon,
     eof,
     float_constant,
+    greatergreater,
     identifier,
     integer_constant,
     kw_false,
     kw_true,
     l_paren,
     l_square,
+    lessless,
     minus,
     percent,
     period,

diff  --git a/lldb/include/lldb/ValueObject/DILParser.h b/lldb/include/lldb/ValueObject/DILParser.h
index 4d1ede2e62900..3fd6747f6db71 100644
--- a/lldb/include/lldb/ValueObject/DILParser.h
+++ b/lldb/include/lldb/ValueObject/DILParser.h
@@ -84,6 +84,7 @@ class DILParser {
   ASTNodeUP Run();
 
   ASTNodeUP ParseExpression();
+  ASTNodeUP ParseShiftExpression();
   ASTNodeUP ParseAdditiveExpression();
   ASTNodeUP ParseMultiplicativeExpression();
   ASTNodeUP ParseUnaryExpression();

diff  --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp
index a454cacbf494f..333c427a4bfa4 100644
--- a/lldb/source/ValueObject/DILAST.cpp
+++ b/lldb/source/ValueObject/DILAST.cpp
@@ -23,6 +23,10 @@ BinaryOpKind GetBinaryOpKindFromToken(Token::Kind token_kind) {
     return BinaryOpKind::Div;
   case Token::percent:
     return BinaryOpKind::Rem;
+  case Token::lessless:
+    return BinaryOpKind::Shl;
+  case Token::greatergreater:
+    return BinaryOpKind::Shr;
   default:
     break;
   }

diff  --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp
index b224e12730723..d3f7d303df660 100644
--- a/lldb/source/ValueObject/DILEval.cpp
+++ b/lldb/source/ValueObject/DILEval.cpp
@@ -636,6 +636,10 @@ Interpreter::EvaluateScalarOp(BinaryOpKind kind, lldb::ValueObjectSP lhs,
     return value_object(l / r);
   case BinaryOpKind::Rem:
     return value_object(l % r);
+  case BinaryOpKind::Shl:
+    return value_object(l << r);
+  case BinaryOpKind::Shr:
+    return value_object(l >> r);
   }
   return llvm::make_error<DILDiagnosticError>(
       m_expr, "invalid arithmetic operation", location);
@@ -833,6 +837,47 @@ llvm::Expected<lldb::ValueObjectSP> Interpreter::EvaluateBinaryRemainder(
   return EvaluateScalarOp(BinaryOpKind::Rem, lhs, rhs, result_type, location);
 }
 
+llvm::Expected<lldb::ValueObjectSP>
+Interpreter::EvaluateBinaryShift(BinaryOpKind kind, lldb::ValueObjectSP lhs,
+                                 lldb::ValueObjectSP rhs, uint32_t location) {
+  // Operations {'>>', '<<'} work for:
+  //  {integer,unscoped_enum} <-> {integer,unscoped_enum}
+  CompilerType orig_lhs_type = lhs->GetCompilerType();
+  CompilerType orig_rhs_type = rhs->GetCompilerType();
+  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.IsInteger() || !rhs_type.IsInteger()) {
+    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);
+  }
+
+  bool success;
+  uint64_t amount = rhs->GetValueAsUnsigned(0, &success);
+  if (!success)
+    return llvm::make_error<DILDiagnosticError>(
+        m_expr, "could not get the shift amount as an integer", location);
+  llvm::Expected<uint64_t> lhs_size =
+      lhs_type.GetBitSize(m_exe_ctx_scope.get());
+  if (!lhs_size)
+    return lhs_size.takeError();
+  if (amount >= *lhs_size)
+    return llvm::make_error<DILDiagnosticError>(m_expr, "invalid shift amount",
+                                                location);
+
+  return EvaluateScalarOp(kind, lhs, rhs, lhs_type, location);
+}
+
 llvm::Expected<lldb::ValueObjectSP>
 Interpreter::Visit(const BinaryOpNode &node) {
   auto lhs_or_err = EvaluateAndDereference(node.GetLHS());
@@ -865,6 +910,9 @@ Interpreter::Visit(const BinaryOpNode &node) {
     return EvaluateBinaryDivision(lhs, rhs, node.GetLocation());
   case BinaryOpKind::Rem:
     return EvaluateBinaryRemainder(lhs, rhs, node.GetLocation());
+  case BinaryOpKind::Shl:
+  case BinaryOpKind::Shr:
+    return EvaluateBinaryShift(node.GetKind(), lhs, rhs, node.GetLocation());
   }
 
   return llvm::make_error<DILDiagnosticError>(
@@ -1226,7 +1274,11 @@ Interpreter::Visit(const IntegerLiteralNode &node) {
       type->GetBitSize(m_exe_ctx_scope.get());
   if (!type_bitsize)
     return type_bitsize.takeError();
+  // Literal itself cannot be a negative value, so we do an unsigned extension.
   scalar.TruncOrExtendTo(*type_bitsize, false);
+  // If the picked compiler type is signed, make the scalar signed as well.
+  if (type->IsSigned())
+    scalar.MakeSigned();
   return ValueObject::CreateValueObjectFromScalar(m_exe_ctx_scope, scalar,
                                                   *type, "result");
 }

diff  --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp
index c9848484851a7..eebac7179053d 100644
--- a/lldb/source/ValueObject/DILLexer.cpp
+++ b/lldb/source/ValueObject/DILLexer.cpp
@@ -32,6 +32,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "eof";
   case Kind::float_constant:
     return "float_constant";
+  case Kind::greatergreater:
+    return "greatergreater";
   case Kind::identifier:
     return "identifier";
   case Kind::integer_constant:
@@ -44,6 +46,8 @@ llvm::StringRef Token::GetTokenName(Kind kind) {
     return "l_paren";
   case Kind::l_square:
     return "l_square";
+  case Kind::lessless:
+    return "lessless";
   case Kind::minus:
     return "minus";
   case Token::percent:
@@ -185,11 +189,22 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr,
   }
 
   constexpr std::pair<Token::Kind, const char *> operators[] = {
-      {Token::amp, "&"},   {Token::arrow, "->"},  {Token::coloncolon, "::"},
-      {Token::colon, ":"}, {Token::l_paren, "("}, {Token::l_square, "["},
-      {Token::minus, "-"}, {Token::percent, "%"}, {Token::period, "."},
-      {Token::plus, "+"},  {Token::r_paren, ")"}, {Token::r_square, "]"},
-      {Token::slash, "/"}, {Token::star, "*"},
+      {Token::arrow, "->"},
+      {Token::coloncolon, "::"},
+      {Token::greatergreater, ">>"},
+      {Token::lessless, "<<"},
+      {Token::amp, "&"},
+      {Token::colon, ":"},
+      {Token::l_paren, "("},
+      {Token::l_square, "["},
+      {Token::minus, "-"},
+      {Token::percent, "%"},
+      {Token::period, "."},
+      {Token::plus, "+"},
+      {Token::r_paren, ")"},
+      {Token::r_square, "]"},
+      {Token::slash, "/"},
+      {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 2393892e97d49..5819805e5ec91 100644
--- a/lldb/source/ValueObject/DILParser.cpp
+++ b/lldb/source/ValueObject/DILParser.cpp
@@ -126,14 +126,38 @@ ASTNodeUP DILParser::Run() {
 // Parse an expression.
 //
 //  expression:
-//    cast_expression
+//    shift_expression
 //
-ASTNodeUP DILParser::ParseExpression() { return ParseAdditiveExpression(); }
+ASTNodeUP DILParser::ParseExpression() { return ParseShiftExpression(); }
+
+// Parse a shift_expression.
+//
+//  shift_expression:
+//    additive_expression {"<<" additive_expression}
+//    additive_expression {">>" additive_expression}
+//
+ASTNodeUP DILParser::ParseShiftExpression() {
+  auto lhs = ParseAdditiveExpression();
+  assert(lhs && "ASTNodeUP must not contain a nullptr");
+
+  while (CurToken().IsOneOf({Token::lessless, Token::greatergreater})) {
+    Token token = CurToken();
+    m_dil_lexer.Advance();
+    auto rhs = ParseAdditiveExpression();
+    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 an additive_expression.
 //
 //  additive_expression:
 //    multiplicative_expression {"+" multiplicative_expression}
+//    multiplicative_expression {"-" multiplicative_expression}
 //
 ASTNodeUP DILParser::ParseAdditiveExpression() {
   auto lhs = ParseMultiplicativeExpression();

diff  --git a/lldb/test/API/commands/frame/var-dil/expr/Bitwise/Makefile b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git a/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
new file mode 100644
index 0000000000000..150a63d1ca975
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py
@@ -0,0 +1,56 @@
+"""
+Test DIL bitwise operators.
+"""
+
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from lldbsuite.test import lldbutil
+
+
+class TestFrameVarDILBitwise(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_bitwise(self):
+        self.build()
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
+            self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp")
+        )
+
+        self.runCmd("settings set target.experimental.use-DIL true")
+
+        # Check bitwise shifts
+        self.expect_var_path("(1 << 5)", value="32")
+        self.expect_var_path("(32 >> 2)", value="8")
+        self.expect_var_path("(-1 >> 10)", value="-1")
+        self.expect_var_path("(-100 >> 5)", value="-4")
+        self.expect_var_path("(-3 << 6)", value="-192")
+        self.expect_var_path("(-1 >> 1U)", value="-1")
+        self.expect_var_path("(0xFFFFFFFFu>>31)", value="1")
+        self.expect_var_path("(char)1 << 16", value="65536")
+        self.expect_var_path("(signed char)-123 >> 8", value="-1")
+        self.expect_var_path("enum_one << enum_one", value="2")
+        self.expect_var_path("2 >> enum_one", value="1")
+        self.expect_var_path("i64 << 63", type="uint64_t")
+
+        # Check errors
+        self.expect(
+            "frame var -- '1 << 1.0'",
+            error=True,
+            substrs=["invalid operands to binary expression ('int' and 'double')"],
+        )
+        self.expect(
+            "frame var -- 's << 1'",
+            error=True,
+            substrs=["invalid operands to binary expression ('S' and 'int')"],
+        )
+        self.expect(
+            "frame var -- '1 >> -1'",
+            error=True,
+            substrs=["invalid shift amount"],
+        )
+        self.expect(
+            "frame var -- 'i64 << 64'",
+            error=True,
+            substrs=["invalid shift amount"],
+        )

diff  --git a/lldb/test/API/commands/frame/var-dil/expr/Bitwise/main.cpp b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/main.cpp
new file mode 100644
index 0000000000000..2978946b757b9
--- /dev/null
+++ b/lldb/test/API/commands/frame/var-dil/expr/Bitwise/main.cpp
@@ -0,0 +1,12 @@
+#include <cstdint>
+enum UnscopedEnum { kZero, kOne };
+
+int main(int argc, char **argv) {
+  struct S {
+  } s;
+
+  auto enum_one = UnscopedEnum::kOne;
+  uint64_t i64 = 1;
+
+  return 0; // Set a breakpoint here
+}


        


More information about the lldb-commits mailing list