https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/192506
>From 847e3c13c16377b24127f31767caeb10e8e43dec Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Thu, 16 Apr 2026 17:36:51 +0500 Subject: [PATCH 1/2] [lldb] Add bitwise shift operators and fix literals' sign in DIL --- lldb/docs/dil-expr-lang.ebnf | 5 +- lldb/include/lldb/ValueObject/DILAST.h | 2 + lldb/include/lldb/ValueObject/DILEval.h | 3 + lldb/include/lldb/ValueObject/DILLexer.h | 2 + lldb/include/lldb/ValueObject/DILParser.h | 1 + lldb/source/ValueObject/DILAST.cpp | 4 ++ lldb/source/ValueObject/DILEval.cpp | 52 +++++++++++++++++ lldb/source/ValueObject/DILLexer.cpp | 25 +++++++-- lldb/source/ValueObject/DILParser.cpp | 28 +++++++++- .../frame/var-dil/expr/Bitwise/Makefile | 3 + .../expr/Bitwise/TestFrameVarDILBitwise.py | 56 +++++++++++++++++++ .../frame/var-dil/expr/Bitwise/main.cpp | 12 ++++ 12 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Bitwise/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Bitwise/TestFrameVarDILBitwise.py create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Bitwise/main.cpp 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 c5f41b5a0bc76..4def783520c0a 100644 --- a/lldb/include/lldb/ValueObject/DILEval.h +++ b/lldb/include/lldb/ValueObject/DILEval.h @@ -101,6 +101,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 351eea6d0d268..b9cd32d0807d4 100644 --- a/lldb/include/lldb/ValueObject/DILParser.h +++ b/lldb/include/lldb/ValueObject/DILParser.h @@ -93,6 +93,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 7801b9225f19e..0d7182a4dd772 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -615,6 +615,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); @@ -812,6 +816,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} + auto orig_lhs_type = lhs->GetCompilerType(); + auto 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()); @@ -844,6 +889,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>( @@ -1218,7 +1266,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 51bdffd5087ca..e56abc6ca545e 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -148,14 +148,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 +} >From 3a507891fd7bc5c852426370d39c06d04c3b1f81 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <[email protected]> Date: Thu, 14 May 2026 23:51:37 +0500 Subject: [PATCH 2/2] Update lldb/source/ValueObject/DILEval.cpp Co-authored-by: Adrian Prantl <[email protected]> --- lldb/source/ValueObject/DILEval.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 0d7182a4dd772..e942210d17426 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -821,7 +821,7 @@ Interpreter::EvaluateBinaryShift(BinaryOpKind kind, lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs, uint32_t location) { // Operations {'>>', '<<'} work for: // {integer,unscoped_enum} <-> {integer,unscoped_enum} - auto orig_lhs_type = lhs->GetCompilerType(); + CompilerType orig_lhs_type = lhs->GetCompilerType(); auto orig_rhs_type = rhs->GetCompilerType(); auto lhs_or_err = UnaryConversion(lhs, location); if (!lhs_or_err) _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
