https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/155617
>From 4d14bbb31d0411c45b95778d1659ccc416165be1 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Mon, 4 Aug 2025 19:11:55 +0500 Subject: [PATCH 1/6] [LLDB] Add unary plus and minus to DIL --- lldb/include/lldb/ValueObject/DILAST.h | 2 + lldb/source/ValueObject/DILEval.cpp | 155 ++++++++++++++++-- lldb/source/ValueObject/DILLexer.cpp | 1 - lldb/source/ValueObject/DILParser.cpp | 10 +- .../frame/var-dil/expr/Arithmetic/Makefile | 3 + .../Arithmetic/TestFrameVarDILArithmetic.py | 40 +++++ .../frame/var-dil/expr/Arithmetic/main.cpp | 9 + 7 files changed, 203 insertions(+), 17 deletions(-) create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py create mode 100644 lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp diff --git a/lldb/include/lldb/ValueObject/DILAST.h b/lldb/include/lldb/ValueObject/DILAST.h index 1d10755c46e39..900eb8a792a1e 100644 --- a/lldb/include/lldb/ValueObject/DILAST.h +++ b/lldb/include/lldb/ValueObject/DILAST.h @@ -32,6 +32,8 @@ enum class NodeKind { enum class UnaryOpKind { AddrOf, // "&" Deref, // "*" + Minus, // "-" + Plus, // "+" }; /// Forward declaration, for use in DIL AST nodes. Definition is at the very diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index c6cf41ee9e9ee..595c25085bfed 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -21,6 +21,73 @@ namespace lldb_private::dil { +static CompilerType GetBasicTypeFromCU(std::shared_ptr<StackFrame> ctx, + lldb::BasicType basic_type) { + SymbolContext symbol_context = + ctx->GetSymbolContext(lldb::eSymbolContextCompUnit); + auto language = symbol_context.comp_unit->GetLanguage(); + + symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule); + auto type_system = + symbol_context.module_sp->GetTypeSystemForLanguage(language); + + if (type_system) + if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type)) + return compiler_type; + + return CompilerType(); +} + +static CompilerType GetIntCompilerTypeForSize(uint32_t size, bool is_signed, + lldb::TypeSystemSP type_system, + std::shared_ptr<StackFrame> ctx) { + lldb::BasicType promote_types[] = { + // lldb::eBasicTypeChar, lldb::eBasicTypeUnsignedChar, + // lldb::eBasicTypeShort, lldb::eBasicTypeUnsignedShort, + lldb::eBasicTypeInt, lldb::eBasicTypeUnsignedInt, + lldb::eBasicTypeLong, lldb::eBasicTypeUnsignedLong, + lldb::eBasicTypeLongLong, lldb::eBasicTypeUnsignedLongLong, + }; + for (auto &basic_type : promote_types) { + uint64_t byte_size = 0; + CompilerType type = GetBasicType(type_system, basic_type); + if (auto temp = type.GetByteSize(ctx.get())) + byte_size = *temp; + if (size < byte_size || + (size == byte_size && + is_signed == (bool)(type.GetTypeInfo() & lldb::eTypeIsSigned))) { + return type; + } + } + + llvm_unreachable("size could not fit into long long"); + return CompilerType(); +} + +static llvm::Expected<Scalar> +GetScalarFromValueObject(lldb::ValueObjectSP valobj, + std::shared_ptr<StackFrame> ctx) { + auto type = valobj->GetCompilerType(); + Scalar scalar; + bool resolved = valobj->ResolveValue(scalar); + if (resolved) { + if (scalar.GetType() == scalar.e_int) { + auto apsint = scalar.GetAPSInt(); + auto type_bitsize = type.GetBitSize(ctx.get()); + if (type_bitsize) { + llvm::APSInt adjusted; + if (type.IsSigned()) + adjusted = apsint.sextOrTrunc(*type_bitsize); + else + adjusted = apsint.zextOrTrunc(*type_bitsize); + return Scalar(adjusted); + } + } else + return scalar; + } + return Scalar(); +} + static lldb::VariableSP DILFindVariable(ConstString name, VariableList &variable_list) { lldb::VariableSP exact_match; @@ -175,21 +242,21 @@ Interpreter::Visit(const IdentifierNode *node) { llvm::Expected<lldb::ValueObjectSP> Interpreter::Visit(const UnaryOpNode *node) { Status error; - auto rhs_or_err = Evaluate(node->GetOperand()); - if (!rhs_or_err) - return rhs_or_err; + auto op_or_err = Evaluate(node->GetOperand()); + if (!op_or_err) + return op_or_err; - lldb::ValueObjectSP rhs = *rhs_or_err; + lldb::ValueObjectSP operand = *op_or_err; switch (node->GetKind()) { case UnaryOpKind::Deref: { - lldb::ValueObjectSP dynamic_rhs = rhs->GetDynamicValue(m_use_dynamic); - if (dynamic_rhs) - rhs = dynamic_rhs; + lldb::ValueObjectSP dynamic_op = operand->GetDynamicValue(m_use_dynamic); + if (dynamic_op) + operand = dynamic_op; - lldb::ValueObjectSP child_sp = rhs->Dereference(error); + lldb::ValueObjectSP child_sp = operand->Dereference(error); if (!child_sp && m_use_synthetic) { - if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) { + if (lldb::ValueObjectSP synth_obj_sp = operand->GetSyntheticValue()) { error.Clear(); child_sp = synth_obj_sp->Dereference(error); } @@ -202,18 +269,78 @@ Interpreter::Visit(const UnaryOpNode *node) { } case UnaryOpKind::AddrOf: { Status error; - lldb::ValueObjectSP value = rhs->AddressOf(error); + lldb::ValueObjectSP value = operand->AddressOf(error); if (error.Fail()) return llvm::make_error<DILDiagnosticError>(m_expr, error.AsCString(), node->GetLocation()); return value; } + case UnaryOpKind::Minus: { + auto operand_type = operand->GetCompilerType(); + if (!operand_type.IsScalarType()) { + std::string errMsg = + llvm::formatv("invalid argument type '{0}' to unary expression", + operand_type.GetTypeName()); + return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, + node->GetLocation()); + } + auto scalar = GetScalarFromValueObject(operand, m_exe_ctx_scope); + if (!scalar) + break; + + bool negated = scalar->UnaryNegate(); + if (scalar->GetType() == Scalar::e_int) { + auto promo_type = GetIntCompilerTypeForSize( + scalar->GetByteSize(), scalar->IsSigned(), + operand_type.GetTypeSystem().GetSharedPointer(), m_exe_ctx_scope); + auto type_bitsize = promo_type.GetBitSize(m_exe_ctx_scope.get()); + + if (type_bitsize && negated) { + scalar->IntegralPromote(*type_bitsize, promo_type.IsSigned()); + return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, + promo_type, "result"); + } + } else + return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, + operand_type, "result"); + break; } - - // Unsupported/invalid operation. - return llvm::make_error<DILDiagnosticError>( - m_expr, "invalid ast: unexpected binary operator", node->GetLocation()); + case UnaryOpKind::Plus: { + auto operand_type = operand->GetCompilerType(); + // Unary plus is allowed for pointers. + if (operand_type.IsPointerType()) + return operand; + if (!operand_type.IsScalarType()) { + std::string errMsg = + llvm::formatv("invalid argument type '{0}' to unary expression", + operand_type.GetTypeName()); + return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, + node->GetLocation()); + } + auto scalar = GetScalarFromValueObject(operand, m_exe_ctx_scope); + if (!scalar) + break; + + if (scalar->GetType() == Scalar::e_int) { + auto promo_type = GetIntCompilerTypeForSize( + scalar->GetByteSize(), scalar->IsSigned(), + operand_type.GetTypeSystem().GetSharedPointer(), m_exe_ctx_scope); + auto type_bitsize = promo_type.GetBitSize(m_exe_ctx_scope.get()); + + if (type_bitsize) { + scalar->IntegralPromote(*type_bitsize, promo_type.IsSigned()); + return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, + promo_type, "result"); + } + } else + return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, + operand_type, "result"); + break; + } + } + return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary operation", + node->GetLocation()); } llvm::Expected<lldb::ValueObjectSP> diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp index 0b2288a9d9230..77879f50cc9ad 100644 --- a/lldb/source/ValueObject/DILLexer.cpp +++ b/lldb/source/ValueObject/DILLexer.cpp @@ -42,7 +42,6 @@ llvm::StringRef Token::GetTokenName(Kind kind) { return "minus"; case Kind::period: return "period"; - return "l_square"; case Kind::plus: return "plus"; case Kind::r_paren: diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index 8c4f7fdb25bea..b88345d18a6d4 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -95,7 +95,8 @@ ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); } // "*" // ASTNodeUP DILParser::ParseUnaryExpression() { - if (CurToken().IsOneOf({Token::amp, Token::star})) { + if (CurToken().IsOneOf( + {Token::amp, Token::star, Token::minus, Token::plus})) { Token token = CurToken(); uint32_t loc = token.GetLocation(); m_dil_lexer.Advance(); @@ -107,7 +108,12 @@ ASTNodeUP DILParser::ParseUnaryExpression() { case Token::amp: return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::AddrOf, std::move(rhs)); - + case Token::minus: + return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Minus, + std::move(rhs)); + case Token::plus: + return std::make_unique<UnaryOpNode>(loc, UnaryOpKind::Plus, + std::move(rhs)); default: llvm_unreachable("invalid token kind"); } diff --git a/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules 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 new file mode 100644 index 0000000000000..d10622738cc6f --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/TestFrameVarDILArithmetic.py @@ -0,0 +1,40 @@ +""" +Test DIL arithmetic. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + + +class TestFrameVarDILArithmetic(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def test_arithmetic(self): + self.build() + lldbutil.run_to_source_breakpoint( + self, "Set a breakpoint here", lldb.SBFileSpec("main.cpp") + ) + + self.runCmd("settings set target.experimental.use-DIL true") + + # Check unary + self.expect_var_path("+0", value="0") + self.expect_var_path("-0", value="0") + self.expect_var_path("+1", value="1") + self.expect_var_path("-1", value="-1") + self.expect_var_path("s", value="10") + self.expect_var_path("+s", value="10") + self.expect_var_path("-s", value="-10") + self.expect_var_path("us", value="1") + self.expect_var_path("-us", value="-1") + self.expect_var_path("+0.0", value="0") + self.expect_var_path("-0.0", value="-0") + self.expect_var_path("-9223372036854775808", value="9223372036854775808") + self.expect_var_path("+p", type="int *") + self.expect( + "frame var -- '-p'", + error=True, + substrs=["invalid argument type 'int *' to unary expression"], + ) 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 new file mode 100644 index 0000000000000..2567453cc293d --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/expr/Arithmetic/main.cpp @@ -0,0 +1,9 @@ +int main(int argc, char **argv) { + short s = 10; + unsigned short us = 1; + + int x = 2; + int &r = x; + int *p = &x; + return 0; // Set a breakpoint here +} >From 424159def9255980463e654a032a628ed30bc0cb Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Thu, 7 Aug 2025 19:42:22 +0500 Subject: [PATCH 2/6] Type promotion --- lldb/source/ValueObject/DILEval.cpp | 261 ++++++++++-------- .../Arithmetic/TestFrameVarDILArithmetic.py | 4 + .../frame/var-dil/expr/Arithmetic/main.cpp | 10 + 3 files changed, 167 insertions(+), 108 deletions(-) diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 595c25085bfed..05ce5b4b8f7af 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -21,71 +21,153 @@ namespace lldb_private::dil { -static CompilerType GetBasicTypeFromCU(std::shared_ptr<StackFrame> ctx, - lldb::BasicType basic_type) { +static llvm::Expected<lldb::TypeSystemSP> +GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) { SymbolContext symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextCompUnit); - auto language = symbol_context.comp_unit->GetLanguage(); + lldb::LanguageType language = symbol_context.comp_unit->GetLanguage(); symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule); - auto type_system = - symbol_context.module_sp->GetTypeSystemForLanguage(language); + return symbol_context.module_sp->GetTypeSystemForLanguage(language); +} +static CompilerType GetBasicType(lldb::TypeSystemSP type_system, + lldb::BasicType basic_type) { if (type_system) - if (auto compiler_type = type_system.get()->GetBasicTypeFromAST(basic_type)) - return compiler_type; + return type_system.get()->GetBasicTypeFromAST(basic_type); return CompilerType(); } -static CompilerType GetIntCompilerTypeForSize(uint32_t size, bool is_signed, - lldb::TypeSystemSP type_system, - std::shared_ptr<StackFrame> ctx) { - lldb::BasicType promote_types[] = { - // lldb::eBasicTypeChar, lldb::eBasicTypeUnsignedChar, - // lldb::eBasicTypeShort, lldb::eBasicTypeUnsignedShort, - lldb::eBasicTypeInt, lldb::eBasicTypeUnsignedInt, - lldb::eBasicTypeLong, lldb::eBasicTypeUnsignedLong, - lldb::eBasicTypeLongLong, lldb::eBasicTypeUnsignedLongLong, - }; - for (auto &basic_type : promote_types) { - uint64_t byte_size = 0; - CompilerType type = GetBasicType(type_system, basic_type); - if (auto temp = type.GetByteSize(ctx.get())) - byte_size = *temp; - if (size < byte_size || - (size == byte_size && - is_signed == (bool)(type.GetTypeInfo() & lldb::eTypeIsSigned))) { - return type; +static llvm::Expected<CompilerType> +DoIntegralPromotion(CompilerType from, lldb::TypeSystemSP type_system, + std::shared_ptr<StackFrame> ctx) { + if (!from.IsInteger() && !from.IsUnscopedEnumerationType()) + return from; + + if (!from.IsPromotableIntegerType()) + return from; + + if (from.IsUnscopedEnumerationType()) + // TODO: fix this by creating CompilerType::GetEnumerationPromotionType() + return DoIntegralPromotion(from.GetEnumerationIntegerType(), type_system, + ctx); + lldb::BasicType builtin_type = + from.GetCanonicalType().GetBasicTypeEnumeration(); + + uint64_t from_size = 0; + if (builtin_type == lldb::eBasicTypeWChar || + builtin_type == lldb::eBasicTypeSignedWChar || + builtin_type == lldb::eBasicTypeUnsignedWChar || + builtin_type == lldb::eBasicTypeChar16 || + builtin_type == lldb::eBasicTypeChar32) { + // Find the type that can hold the entire range of values for our type. + bool is_signed = from.IsSigned(); + llvm::Expected<uint64_t> from_size = from.GetByteSize(ctx.get()); + if (!from_size) + return from_size.takeError(); + + CompilerType promote_types[] = { + GetBasicType(type_system, lldb::eBasicTypeInt), + GetBasicType(type_system, lldb::eBasicTypeUnsignedInt), + GetBasicType(type_system, lldb::eBasicTypeLong), + GetBasicType(type_system, lldb::eBasicTypeUnsignedLong), + GetBasicType(type_system, lldb::eBasicTypeLongLong), + GetBasicType(type_system, lldb::eBasicTypeUnsignedLongLong), + }; + for (CompilerType &type : promote_types) { + llvm::Expected<uint64_t> byte_size = type.GetByteSize(ctx.get()); + if (!byte_size) + return byte_size.takeError(); + if (*from_size < *byte_size || + (*from_size == *byte_size && is_signed == type.IsSigned())) { + return type; + } } + llvm_unreachable("char type should fit into long long"); } - llvm_unreachable("size could not fit into long long"); - return CompilerType(); + // Here we can promote only to "int" or "unsigned int". + CompilerType int_type = GetBasicType(type_system, lldb::eBasicTypeInt); + llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(ctx.get()); + if (!int_byte_size) + return int_byte_size.takeError(); + + // Signed integer types can be safely promoted to "int". + if (from.IsSigned()) { + return int_type; + } + // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold + // their entire value range. + return (from_size == *int_byte_size) + ? GetBasicType(type_system, lldb::eBasicTypeUnsignedInt) + : int_type; } -static llvm::Expected<Scalar> -GetScalarFromValueObject(lldb::ValueObjectSP valobj, +static lldb::ValueObjectSP +ArrayToPointerConversion(lldb::ValueObjectSP valobj, std::shared_ptr<StackFrame> ctx) { - auto type = valobj->GetCompilerType(); - Scalar scalar; - bool resolved = valobj->ResolveValue(scalar); - if (resolved) { - if (scalar.GetType() == scalar.e_int) { - auto apsint = scalar.GetAPSInt(); - auto type_bitsize = type.GetBitSize(ctx.get()); - if (type_bitsize) { - llvm::APSInt adjusted; - if (type.IsSigned()) - adjusted = apsint.sextOrTrunc(*type_bitsize); - else - adjusted = apsint.zextOrTrunc(*type_bitsize); - return Scalar(adjusted); - } - } else - return scalar; + assert(valobj->IsArrayType() && + "an argument to array-to-pointer conversion must be an array"); + + uint64_t addr = valobj->GetLoadAddress(); + ExecutionContext exe_ctx; + ctx->CalculateExecutionContext(exe_ctx); + return ValueObject::CreateValueObjectFromAddress( + "result", addr, exe_ctx, + valobj->GetCompilerType().GetArrayElementType(ctx.get()).GetPointerType(), + /* do_deref */ false); +} + +static llvm::Expected<lldb::ValueObjectSP> +UnaryConversion(lldb::ValueObjectSP valobj, std::shared_ptr<StackFrame> ctx) { + // Perform usual conversions for unary operators. At the moment this includes + // array-to-pointer and the integral promotion for eligible types. + llvm::Expected<lldb::TypeSystemSP> type_system = GetTypeSystemFromCU(ctx); + if (!type_system) + return type_system.takeError(); + CompilerType in_type = valobj->GetCompilerType(); + CompilerType result_type; + if (valobj->IsBitfield()) { + // Promote bitfields. If `int` can represent the bitfield value, it is + // converted to `int`. Otherwise, if `unsigned int` can represent it, it + // is converted to `unsigned int`. Otherwise, it is treated as its + // underlying type. + uint32_t bitfield_size = valobj->GetBitfieldBitSize(); + // Some bitfields have undefined size (e.g. result of ternary operation). + // The AST's `bitfield_size` of those is 0, and no promotion takes place. + if (bitfield_size > 0 && in_type.IsInteger()) { + CompilerType int_type = GetBasicType(*type_system, lldb::eBasicTypeInt); + CompilerType uint_type = + GetBasicType(*type_system, lldb::eBasicTypeUnsignedInt); + llvm::Expected<uint64_t> int_bit_size = int_type.GetBitSize(ctx.get()); + if (!int_bit_size) + return int_bit_size.takeError(); + llvm::Expected<uint64_t> uint_bit_size = uint_type.GetBitSize(ctx.get()); + if (!uint_bit_size) + return int_bit_size.takeError(); + if (bitfield_size < *int_bit_size || + (in_type.IsSigned() && bitfield_size == *int_bit_size)) + valobj = valobj->CastToBasicType(int_type); + else if (bitfield_size <= *uint_bit_size) + valobj = valobj->CastToBasicType(uint_type); + } } - return Scalar(); + + if (in_type.IsArrayType()) + valobj = ArrayToPointerConversion(valobj, ctx); + + if (valobj->GetCompilerType().IsInteger() || + valobj->GetCompilerType().IsUnscopedEnumerationType()) { + llvm::Expected<CompilerType> promoted_type = + DoIntegralPromotion(valobj->GetCompilerType(), *type_system, ctx); + if (!promoted_type) + return promoted_type.takeError(); + if (!promoted_type->CompareTypes(valobj->GetCompilerType())) + return valobj->CastToBasicType(*promoted_type); + } + + return valobj; } static lldb::VariableSP DILFindVariable(ConstString name, @@ -277,7 +359,12 @@ Interpreter::Visit(const UnaryOpNode *node) { return value; } case UnaryOpKind::Minus: { - auto operand_type = operand->GetCompilerType(); + llvm::Expected<lldb::ValueObjectSP> conv_op = + UnaryConversion(operand, m_exe_ctx_scope); + if (!conv_op) + return conv_op; + operand = *conv_op; + CompilerType operand_type = operand->GetCompilerType(); if (!operand_type.IsScalarType()) { std::string errMsg = llvm::formatv("invalid argument type '{0}' to unary expression", @@ -285,58 +372,34 @@ Interpreter::Visit(const UnaryOpNode *node) { return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, node->GetLocation()); } - auto scalar = GetScalarFromValueObject(operand, m_exe_ctx_scope); - if (!scalar) + Scalar scalar; + bool resolved = operand->ResolveValue(scalar); + if (!resolved) break; - bool negated = scalar->UnaryNegate(); - if (scalar->GetType() == Scalar::e_int) { - auto promo_type = GetIntCompilerTypeForSize( - scalar->GetByteSize(), scalar->IsSigned(), - operand_type.GetTypeSystem().GetSharedPointer(), m_exe_ctx_scope); - auto type_bitsize = promo_type.GetBitSize(m_exe_ctx_scope.get()); - - if (type_bitsize && negated) { - scalar->IntegralPromote(*type_bitsize, promo_type.IsSigned()); - return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, - promo_type, "result"); - } - } else - return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, - operand_type, "result"); + bool negated = scalar.UnaryNegate(); + if (negated) + return ValueObject::CreateValueObjectFromScalar( + m_target, scalar, operand->GetCompilerType(), "result"); break; } case UnaryOpKind::Plus: { - auto operand_type = operand->GetCompilerType(); - // Unary plus is allowed for pointers. - if (operand_type.IsPointerType()) - return operand; - if (!operand_type.IsScalarType()) { + llvm::Expected<lldb::ValueObjectSP> conv_op = + UnaryConversion(operand, m_exe_ctx_scope); + if (!conv_op) + return conv_op; + operand = *conv_op; + CompilerType operand_type = operand->GetCompilerType(); + if (!operand_type.IsScalarType() && + // Unary plus is allowed for pointers. + !operand_type.IsPointerType()) { std::string errMsg = llvm::formatv("invalid argument type '{0}' to unary expression", operand_type.GetTypeName()); return llvm::make_error<DILDiagnosticError>(m_expr, errMsg, node->GetLocation()); } - auto scalar = GetScalarFromValueObject(operand, m_exe_ctx_scope); - if (!scalar) - break; - - if (scalar->GetType() == Scalar::e_int) { - auto promo_type = GetIntCompilerTypeForSize( - scalar->GetByteSize(), scalar->IsSigned(), - operand_type.GetTypeSystem().GetSharedPointer(), m_exe_ctx_scope); - auto type_bitsize = promo_type.GetBitSize(m_exe_ctx_scope.get()); - - if (type_bitsize) { - scalar->IntegralPromote(*type_bitsize, promo_type.IsSigned()); - return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, - promo_type, "result"); - } - } else - return ValueObject::CreateValueObjectFromScalar(m_target, *scalar, - operand_type, "result"); - break; + return operand; } } return llvm::make_error<DILDiagnosticError>(m_expr, "invalid unary operation", @@ -626,24 +689,6 @@ Interpreter::Visit(const BitFieldExtractionNode *node) { return child_valobj_sp; } -static llvm::Expected<lldb::TypeSystemSP> -GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) { - SymbolContext symbol_context = - ctx->GetSymbolContext(lldb::eSymbolContextCompUnit); - lldb::LanguageType language = symbol_context.comp_unit->GetLanguage(); - - symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule); - return symbol_context.module_sp->GetTypeSystemForLanguage(language); -} - -static CompilerType GetBasicType(lldb::TypeSystemSP type_system, - lldb::BasicType basic_type) { - if (type_system) - return type_system.get()->GetBasicTypeFromAST(basic_type); - - return CompilerType(); -} - llvm::Expected<CompilerType> Interpreter::PickIntegerType(lldb::TypeSystemSP type_system, std::shared_ptr<ExecutionContextScope> ctx, 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 d10622738cc6f..fc53b656d7591 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 @@ -32,6 +32,10 @@ def test_arithmetic(self): self.expect_var_path("+0.0", value="0") self.expect_var_path("-0.0", value="-0") self.expect_var_path("-9223372036854775808", value="9223372036854775808") + self.expect_var_path("+array", type="int *") + self.expect_var_path("+enum_one", value="1") + self.expect_var_path("-enum_one", value="4294967295") # TODO: fix + self.expect_var_path("+bf.a", value="7") self.expect_var_path("+p", type="int *") self.expect( "frame var -- '-p'", 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 2567453cc293d..125a64d7b7109 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,3 +1,5 @@ +#include <cstdint> + int main(int argc, char **argv) { short s = 10; unsigned short us = 1; @@ -5,5 +7,13 @@ int main(int argc, char **argv) { int x = 2; int &r = x; int *p = &x; + int array[] = {1}; + enum Enum { kZero, kOne } enum_one = kOne; + + struct BitFieldStruct { + uint16_t a : 10; + }; + BitFieldStruct bf = {7}; + return 0; // Set a breakpoint here } >From 05eec8b50f3f6aa93ffaa66ff9810bdcf0eb5546 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Tue, 19 Aug 2025 20:22:51 +0500 Subject: [PATCH 3/6] Move DoIntegralPromotion and IsPromotableIntegerType to TypeSystem --- lldb/include/lldb/Symbol/TypeSystem.h | 7 ++ .../TypeSystem/Clang/TypeSystemClang.cpp | 96 +++++++++++++++++++ .../TypeSystem/Clang/TypeSystemClang.h | 8 ++ lldb/source/Symbol/CompilerType.cpp | 28 +----- lldb/source/Symbol/TypeSystem.cpp | 10 ++ lldb/source/ValueObject/DILEval.cpp | 82 +++------------- .../Arithmetic/TestFrameVarDILArithmetic.py | 2 +- 7 files changed, 137 insertions(+), 96 deletions(-) diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 16a2e0b5a52fb..d74e6a0e05625 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -412,6 +412,13 @@ class TypeSystem : public PluginInterface, GetIntegralTemplateArgument(lldb::opaque_compiler_type_t type, size_t idx, bool expand_pack); + // DIL + + virtual bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type); + + virtual llvm::Expected<CompilerType> + DoIntegralPromotion(CompilerType from, ExecutionContextScope *exe_scope); + // Dumping types #ifndef NDEBUG diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 39aacdb58e694..4d4ca522e052a 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -7320,6 +7320,102 @@ CompilerType TypeSystemClang::GetTypeForFormatters(void *type) { return CompilerType(); } +bool TypeSystemClang::IsPromotableIntegerType( + lldb::opaque_compiler_type_t type) { + // Unscoped enums are always considered as promotable, even if their + // underlying type does not need to be promoted (e.g. "int"). + bool is_signed = false; + bool isUnscopedEnumerationType = + IsEnumerationType(type, is_signed) && !IsScopedEnumerationType(type); + if (isUnscopedEnumerationType) + return true; + + switch (GetBasicTypeEnumeration(type)) { + case lldb::eBasicTypeBool: + case lldb::eBasicTypeChar: + case lldb::eBasicTypeSignedChar: + case lldb::eBasicTypeUnsignedChar: + case lldb::eBasicTypeShort: + case lldb::eBasicTypeUnsignedShort: + case lldb::eBasicTypeWChar: + case lldb::eBasicTypeSignedWChar: + case lldb::eBasicTypeUnsignedWChar: + case lldb::eBasicTypeChar16: + case lldb::eBasicTypeChar32: + return true; + + default: + return false; + } + + llvm_unreachable("All cases handled above."); +} + +llvm::Expected<CompilerType> +TypeSystemClang::DoIntegralPromotion(CompilerType from, + ExecutionContextScope *exe_scope) { + if (!from.IsInteger() && !from.IsUnscopedEnumerationType()) + return from; + + if (!from.IsPromotableIntegerType()) + return from; + + if (from.IsUnscopedEnumerationType()) { + EnumDecl *enum_decl = GetAsEnumDecl(from); + CompilerType promotion_type = GetType(enum_decl->getPromotionType()); + return DoIntegralPromotion(promotion_type, exe_scope); + } + + lldb::BasicType builtin_type = + from.GetCanonicalType().GetBasicTypeEnumeration(); + uint64_t from_size = 0; + if (builtin_type == lldb::eBasicTypeWChar || + builtin_type == lldb::eBasicTypeSignedWChar || + builtin_type == lldb::eBasicTypeUnsignedWChar || + builtin_type == lldb::eBasicTypeChar16 || + builtin_type == lldb::eBasicTypeChar32) { + // Find the type that can hold the entire range of values for our type. + bool is_signed = from.IsSigned(); + llvm::Expected<uint64_t> from_size = from.GetByteSize(exe_scope); + if (!from_size) + return from_size.takeError(); + CompilerType promote_types[] = { + GetBasicTypeFromAST(lldb::eBasicTypeInt), + GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt), + GetBasicTypeFromAST(lldb::eBasicTypeLong), + GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLong), + GetBasicTypeFromAST(lldb::eBasicTypeLongLong), + GetBasicTypeFromAST(lldb::eBasicTypeUnsignedLongLong), + }; + for (CompilerType &type : promote_types) { + llvm::Expected<uint64_t> byte_size = type.GetByteSize(exe_scope); + if (!byte_size) + return byte_size.takeError(); + if (*from_size < *byte_size || + (*from_size == *byte_size && is_signed == type.IsSigned())) { + return type; + } + } + llvm_unreachable("char type should fit into long long"); + } + + // Here we can promote only to "int" or "unsigned int". + CompilerType int_type = GetBasicTypeFromAST(lldb::eBasicTypeInt); + llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(exe_scope); + if (!int_byte_size) + return int_byte_size.takeError(); + + // Signed integer types can be safely promoted to "int". + if (from.IsSigned()) { + return int_type; + } + // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold + // their entire value range. + return (from_size == *int_byte_size) + ? GetBasicTypeFromAST(lldb::eBasicTypeUnsignedInt) + : int_type; +} + clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) { const clang::EnumType *enutype = llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type)); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 709f89590ba3b..0ca1a1e2578b3 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -939,6 +939,14 @@ class TypeSystemClang : public TypeSystem { CompilerType GetTypeForFormatters(void *type) override; + // DIL + + bool IsPromotableIntegerType(lldb::opaque_compiler_type_t type) override; + + llvm::Expected<CompilerType> + DoIntegralPromotion(CompilerType from, + ExecutionContextScope *exe_scope) override; + #define LLDB_INVALID_DECL_LEVEL UINT32_MAX // LLDB_INVALID_DECL_LEVEL is returned by CountDeclLevels if child_decl_ctx // could not be found in decl_ctx. diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 62c0ddf51c012..a22e817f818ce 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -373,30 +373,10 @@ bool CompilerType::IsScalarOrUnscopedEnumerationType() const { } bool CompilerType::IsPromotableIntegerType() const { - // Unscoped enums are always considered as promotable, even if their - // underlying type does not need to be promoted (e.g. "int"). - if (IsUnscopedEnumerationType()) - return true; - - switch (GetBasicTypeEnumeration()) { - case lldb::eBasicTypeBool: - case lldb::eBasicTypeChar: - case lldb::eBasicTypeSignedChar: - case lldb::eBasicTypeUnsignedChar: - case lldb::eBasicTypeShort: - case lldb::eBasicTypeUnsignedShort: - case lldb::eBasicTypeWChar: - case lldb::eBasicTypeSignedWChar: - case lldb::eBasicTypeUnsignedWChar: - case lldb::eBasicTypeChar16: - case lldb::eBasicTypeChar32: - return true; - - default: - return false; - } - - llvm_unreachable("All cases handled above."); + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->IsPromotableIntegerType(m_type); + return false; } bool CompilerType::IsPointerToVoid() const { diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index f7d634ffa2dec..7df049084e6fb 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -123,6 +123,16 @@ CompilerType TypeSystem::GetTypeForFormatters(void *type) { return CompilerType(weak_from_this(), type); } +bool TypeSystem::IsPromotableIntegerType(lldb::opaque_compiler_type_t type) { + return false; +} + +llvm::Expected<CompilerType> +TypeSystem::DoIntegralPromotion(CompilerType from, + ExecutionContextScope *exe_scope) { + return CompilerType(); +} + bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) { return false; } diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index 05ce5b4b8f7af..ff757f34772ef 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -22,12 +22,15 @@ namespace lldb_private::dil { static llvm::Expected<lldb::TypeSystemSP> -GetTypeSystemFromCU(std::shared_ptr<StackFrame> ctx) { +GetTypeSystemFromCU(std::shared_ptr<ExecutionContextScope> ctx) { + auto stack_frame = ctx->CalculateStackFrame(); + if (!stack_frame) + return llvm::createStringError("no stack frame in this context"); SymbolContext symbol_context = - ctx->GetSymbolContext(lldb::eSymbolContextCompUnit); + stack_frame->GetSymbolContext(lldb::eSymbolContextCompUnit); lldb::LanguageType language = symbol_context.comp_unit->GetLanguage(); - symbol_context = ctx->GetSymbolContext(lldb::eSymbolContextModule); + symbol_context = stack_frame->GetSymbolContext(lldb::eSymbolContextModule); return symbol_context.module_sp->GetTypeSystemForLanguage(language); } @@ -39,74 +42,9 @@ static CompilerType GetBasicType(lldb::TypeSystemSP type_system, return CompilerType(); } -static llvm::Expected<CompilerType> -DoIntegralPromotion(CompilerType from, lldb::TypeSystemSP type_system, - std::shared_ptr<StackFrame> ctx) { - if (!from.IsInteger() && !from.IsUnscopedEnumerationType()) - return from; - - if (!from.IsPromotableIntegerType()) - return from; - - if (from.IsUnscopedEnumerationType()) - // TODO: fix this by creating CompilerType::GetEnumerationPromotionType() - return DoIntegralPromotion(from.GetEnumerationIntegerType(), type_system, - ctx); - lldb::BasicType builtin_type = - from.GetCanonicalType().GetBasicTypeEnumeration(); - - uint64_t from_size = 0; - if (builtin_type == lldb::eBasicTypeWChar || - builtin_type == lldb::eBasicTypeSignedWChar || - builtin_type == lldb::eBasicTypeUnsignedWChar || - builtin_type == lldb::eBasicTypeChar16 || - builtin_type == lldb::eBasicTypeChar32) { - // Find the type that can hold the entire range of values for our type. - bool is_signed = from.IsSigned(); - llvm::Expected<uint64_t> from_size = from.GetByteSize(ctx.get()); - if (!from_size) - return from_size.takeError(); - - CompilerType promote_types[] = { - GetBasicType(type_system, lldb::eBasicTypeInt), - GetBasicType(type_system, lldb::eBasicTypeUnsignedInt), - GetBasicType(type_system, lldb::eBasicTypeLong), - GetBasicType(type_system, lldb::eBasicTypeUnsignedLong), - GetBasicType(type_system, lldb::eBasicTypeLongLong), - GetBasicType(type_system, lldb::eBasicTypeUnsignedLongLong), - }; - for (CompilerType &type : promote_types) { - llvm::Expected<uint64_t> byte_size = type.GetByteSize(ctx.get()); - if (!byte_size) - return byte_size.takeError(); - if (*from_size < *byte_size || - (*from_size == *byte_size && is_signed == type.IsSigned())) { - return type; - } - } - llvm_unreachable("char type should fit into long long"); - } - - // Here we can promote only to "int" or "unsigned int". - CompilerType int_type = GetBasicType(type_system, lldb::eBasicTypeInt); - llvm::Expected<uint64_t> int_byte_size = int_type.GetByteSize(ctx.get()); - if (!int_byte_size) - return int_byte_size.takeError(); - - // Signed integer types can be safely promoted to "int". - if (from.IsSigned()) { - return int_type; - } - // Unsigned integer types are promoted to "unsigned int" if "int" cannot hold - // their entire value range. - return (from_size == *int_byte_size) - ? GetBasicType(type_system, lldb::eBasicTypeUnsignedInt) - : int_type; -} - static lldb::ValueObjectSP ArrayToPointerConversion(lldb::ValueObjectSP valobj, - std::shared_ptr<StackFrame> ctx) { + std::shared_ptr<ExecutionContextScope> ctx) { assert(valobj->IsArrayType() && "an argument to array-to-pointer conversion must be an array"); @@ -120,7 +58,8 @@ ArrayToPointerConversion(lldb::ValueObjectSP valobj, } static llvm::Expected<lldb::ValueObjectSP> -UnaryConversion(lldb::ValueObjectSP valobj, std::shared_ptr<StackFrame> ctx) { +UnaryConversion(lldb::ValueObjectSP valobj, + std::shared_ptr<ExecutionContextScope> ctx) { // Perform usual conversions for unary operators. At the moment this includes // array-to-pointer and the integral promotion for eligible types. llvm::Expected<lldb::TypeSystemSP> type_system = GetTypeSystemFromCU(ctx); @@ -160,7 +99,8 @@ UnaryConversion(lldb::ValueObjectSP valobj, std::shared_ptr<StackFrame> ctx) { if (valobj->GetCompilerType().IsInteger() || valobj->GetCompilerType().IsUnscopedEnumerationType()) { llvm::Expected<CompilerType> promoted_type = - DoIntegralPromotion(valobj->GetCompilerType(), *type_system, ctx); + type_system.get()->DoIntegralPromotion(valobj->GetCompilerType(), + ctx.get()); if (!promoted_type) return promoted_type.takeError(); if (!promoted_type->CompareTypes(valobj->GetCompilerType())) 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 fc53b656d7591..c6a97e6f52089 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 @@ -34,7 +34,7 @@ def test_arithmetic(self): self.expect_var_path("-9223372036854775808", value="9223372036854775808") self.expect_var_path("+array", type="int *") self.expect_var_path("+enum_one", value="1") - self.expect_var_path("-enum_one", value="4294967295") # TODO: fix + self.expect_var_path("-enum_one", value="-1") self.expect_var_path("+bf.a", value="7") self.expect_var_path("+p", type="int *") self.expect( >From 86c86fc7accdde1b8914c1351ebb9a0044157469 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Tue, 19 Aug 2025 22:47:24 +0500 Subject: [PATCH 4/6] Adjust bitfield promotion --- lldb/include/lldb/ValueObject/DILEval.h | 2 + lldb/source/ValueObject/DILEval.cpp | 37 +++++++++++-------- .../Arithmetic/TestFrameVarDILArithmetic.py | 6 ++- .../frame/var-dil/expr/Arithmetic/main.cpp | 7 +++- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/lldb/include/lldb/ValueObject/DILEval.h b/lldb/include/lldb/ValueObject/DILEval.h index 5a48c2c989f4d..11f44336cbf55 100644 --- a/lldb/include/lldb/ValueObject/DILEval.h +++ b/lldb/include/lldb/ValueObject/DILEval.h @@ -59,6 +59,8 @@ class Interpreter : Visitor { llvm::Expected<lldb::ValueObjectSP> Visit(const FloatLiteralNode *node) override; + llvm::Expected<lldb::ValueObjectSP> + UnaryConversion(lldb::ValueObjectSP valobj); llvm::Expected<CompilerType> PickIntegerType(lldb::TypeSystemSP type_system, std::shared_ptr<ExecutionContextScope> ctx, diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index ff757f34772ef..c31b90ce83663 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -57,12 +57,12 @@ ArrayToPointerConversion(lldb::ValueObjectSP valobj, /* do_deref */ false); } -static llvm::Expected<lldb::ValueObjectSP> -UnaryConversion(lldb::ValueObjectSP valobj, - std::shared_ptr<ExecutionContextScope> ctx) { +llvm::Expected<lldb::ValueObjectSP> +Interpreter::UnaryConversion(lldb::ValueObjectSP valobj) { // Perform usual conversions for unary operators. At the moment this includes // array-to-pointer and the integral promotion for eligible types. - llvm::Expected<lldb::TypeSystemSP> type_system = GetTypeSystemFromCU(ctx); + llvm::Expected<lldb::TypeSystemSP> type_system = + GetTypeSystemFromCU(m_exe_ctx_scope); if (!type_system) return type_system.takeError(); CompilerType in_type = valobj->GetCompilerType(); @@ -79,28 +79,37 @@ UnaryConversion(lldb::ValueObjectSP valobj, CompilerType int_type = GetBasicType(*type_system, lldb::eBasicTypeInt); CompilerType uint_type = GetBasicType(*type_system, lldb::eBasicTypeUnsignedInt); - llvm::Expected<uint64_t> int_bit_size = int_type.GetBitSize(ctx.get()); + llvm::Expected<uint64_t> int_bit_size = + int_type.GetBitSize(m_exe_ctx_scope.get()); if (!int_bit_size) return int_bit_size.takeError(); - llvm::Expected<uint64_t> uint_bit_size = uint_type.GetBitSize(ctx.get()); + llvm::Expected<uint64_t> uint_bit_size = + uint_type.GetBitSize(m_exe_ctx_scope.get()); if (!uint_bit_size) return int_bit_size.takeError(); if (bitfield_size < *int_bit_size || (in_type.IsSigned() && bitfield_size == *int_bit_size)) - valobj = valobj->CastToBasicType(int_type); - else if (bitfield_size <= *uint_bit_size) - valobj = valobj->CastToBasicType(uint_type); + return valobj->CastToBasicType(int_type); + if (bitfield_size <= *uint_bit_size) + return valobj->CastToBasicType(uint_type); + // Re-create as a const value with the same underlying type + Scalar scalar; + bool resolved = valobj->ResolveValue(scalar); + if (!resolved) + return llvm::createStringError("invalid scalar value"); + return ValueObject::CreateValueObjectFromScalar(m_target, scalar, in_type, + "result"); } } if (in_type.IsArrayType()) - valobj = ArrayToPointerConversion(valobj, ctx); + valobj = ArrayToPointerConversion(valobj, m_exe_ctx_scope); if (valobj->GetCompilerType().IsInteger() || valobj->GetCompilerType().IsUnscopedEnumerationType()) { llvm::Expected<CompilerType> promoted_type = type_system.get()->DoIntegralPromotion(valobj->GetCompilerType(), - ctx.get()); + m_exe_ctx_scope.get()); if (!promoted_type) return promoted_type.takeError(); if (!promoted_type->CompareTypes(valobj->GetCompilerType())) @@ -299,8 +308,7 @@ Interpreter::Visit(const UnaryOpNode *node) { return value; } case UnaryOpKind::Minus: { - llvm::Expected<lldb::ValueObjectSP> conv_op = - UnaryConversion(operand, m_exe_ctx_scope); + llvm::Expected<lldb::ValueObjectSP> conv_op = UnaryConversion(operand); if (!conv_op) return conv_op; operand = *conv_op; @@ -324,8 +332,7 @@ Interpreter::Visit(const UnaryOpNode *node) { break; } case UnaryOpKind::Plus: { - llvm::Expected<lldb::ValueObjectSP> conv_op = - UnaryConversion(operand, m_exe_ctx_scope); + llvm::Expected<lldb::ValueObjectSP> conv_op = UnaryConversion(operand); if (!conv_op) return conv_op; operand = *conv_op; 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 c6a97e6f52089..d2b0ecd75966e 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 @@ -35,7 +35,11 @@ def test_arithmetic(self): self.expect_var_path("+array", type="int *") self.expect_var_path("+enum_one", value="1") self.expect_var_path("-enum_one", value="-1") - self.expect_var_path("+bf.a", value="7") + self.expect_var_path("-bitfield.a", value="-1", type="int") + self.expect_var_path("+bitfield.a", value="1", type="int") + 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") self.expect_var_path("+p", type="int *") self.expect( "frame var -- '-p'", 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 125a64d7b7109..fdeb6cf49ccfd 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 @@ -11,9 +11,12 @@ int main(int argc, char **argv) { enum Enum { kZero, kOne } enum_one = kOne; struct BitFieldStruct { - uint16_t a : 10; + char a : 4; + int b : 32; + unsigned int c : 32; + uint64_t d : 48; }; - BitFieldStruct bf = {7}; + BitFieldStruct bitfield = {1, 2, 3, 4}; return 0; // Set a breakpoint here } >From 80b5f94f4b70dd9dfee584bfa0c42fada5c6ef39 Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Fri, 22 Aug 2025 17:18:33 +0500 Subject: [PATCH 5/6] Expand the test --- .../Arithmetic/TestFrameVarDILArithmetic.py | 19 +++++++++++-------- .../frame/var-dil/expr/Arithmetic/main.cpp | 3 +++ 2 files changed, 14 insertions(+), 8 deletions(-) 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 d2b0ecd75966e..76edc5837cf2b 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 @@ -19,27 +19,30 @@ def test_arithmetic(self): self.runCmd("settings set target.experimental.use-DIL true") - # Check unary + # Check unary results and integral promotion self.expect_var_path("+0", value="0") self.expect_var_path("-0", value="0") self.expect_var_path("+1", value="1") self.expect_var_path("-1", value="-1") - self.expect_var_path("s", value="10") - self.expect_var_path("+s", value="10") - self.expect_var_path("-s", value="-10") - self.expect_var_path("us", value="1") - self.expect_var_path("-us", value="-1") + self.expect_var_path("-9223372036854775808", value="9223372036854775808") + self.expect_var_path("s", value="10", type="short") + self.expect_var_path("+s", value="10", type="int") + self.expect_var_path("-s", value="-10", type="int") + self.expect_var_path("+us", value="1", type="int") + self.expect_var_path("-us", value="-1", type="int") self.expect_var_path("+0.0", value="0") self.expect_var_path("-0.0", value="-0") - self.expect_var_path("-9223372036854775808", value="9223372036854775808") - self.expect_var_path("+array", type="int *") self.expect_var_path("+enum_one", value="1") self.expect_var_path("-enum_one", value="-1") + self.expect_var_path("+wchar", value="1") + self.expect_var_path("+char16", value="2") + self.expect_var_path("+char32", value="3") self.expect_var_path("-bitfield.a", value="-1", type="int") self.expect_var_path("+bitfield.a", value="1", type="int") 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") + self.expect_var_path("+array", type="int *") self.expect_var_path("+p", type="int *") self.expect( "frame var -- '-p'", 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 fdeb6cf49ccfd..5090ce8e34e3d 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 @@ -9,6 +9,9 @@ int main(int argc, char **argv) { int *p = &x; int array[] = {1}; enum Enum { kZero, kOne } enum_one = kOne; + wchar_t wchar = 1; + char16_t char16 = 2; + char32_t char32 = 3; struct BitFieldStruct { char a : 4; >From 72b4fbc46c9e91fea5fb80bc97b045f8af9294ef Mon Sep 17 00:00:00 2001 From: Ilia Kuklin <ikuk...@accesssoftek.com> Date: Thu, 28 Aug 2025 22:05:57 +0500 Subject: [PATCH 6/6] Expand grammar --- lldb/docs/dil-expr-lang.ebnf | 2 +- lldb/source/ValueObject/DILParser.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lldb/docs/dil-expr-lang.ebnf b/lldb/docs/dil-expr-lang.ebnf index 67328939ba420..20804935bf356 100644 --- a/lldb/docs/dil-expr-lang.ebnf +++ b/lldb/docs/dil-expr-lang.ebnf @@ -8,7 +8,7 @@ expression = unary_expression ; unary_expression = postfix_expression | unary_operator expression ; -unary_operator = "*" | "&" ; +unary_operator = "*" | "&" | "+" | "-"; postfix_expression = primary_expression | postfix_expression "[" integer_literal "]" diff --git a/lldb/source/ValueObject/DILParser.cpp b/lldb/source/ValueObject/DILParser.cpp index b88345d18a6d4..b1ba25213c803 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -93,6 +93,8 @@ ASTNodeUP DILParser::ParseExpression() { return ParseUnaryExpression(); } // unary_operator: // "&" // "*" +// "+" +// "-" // ASTNodeUP DILParser::ParseUnaryExpression() { if (CurToken().IsOneOf( _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits