diff options
| author | Mingming Liu <mingmingl@google.com> | 2025-09-10 15:25:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-10 15:25:31 -0700 |
| commit | 1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch) | |
| tree | 57f4b1f313c8cf74eed8819870f39c36ea263c68 /lldb/source/ValueObject | |
| parent | 898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff) | |
| parent | b8cefcb601ddaa18482555c4ff363c01a270c2fe (diff) | |
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'lldb/source/ValueObject')
| -rw-r--r-- | lldb/source/ValueObject/DILAST.cpp | 9 | ||||
| -rw-r--r-- | lldb/source/ValueObject/DILEval.cpp | 254 | ||||
| -rw-r--r-- | lldb/source/ValueObject/DILLexer.cpp | 57 | ||||
| -rw-r--r-- | lldb/source/ValueObject/DILParser.cpp | 67 |
4 files changed, 345 insertions, 42 deletions
diff --git a/lldb/source/ValueObject/DILAST.cpp b/lldb/source/ValueObject/DILAST.cpp index b1cd824c2299..70564663a62c 100644 --- a/lldb/source/ValueObject/DILAST.cpp +++ b/lldb/source/ValueObject/DILAST.cpp @@ -37,4 +37,13 @@ BitFieldExtractionNode::Accept(Visitor *v) const { return v->Visit(this); } +llvm::Expected<lldb::ValueObjectSP> +IntegerLiteralNode::Accept(Visitor *v) const { + return v->Visit(this); +} + +llvm::Expected<lldb::ValueObjectSP> FloatLiteralNode::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 6f28434c646c..c6cf41ee9e9e 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "lldb/ValueObject/DILEval.h" +#include "lldb/Core/Module.h" #include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/TypeSystem.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/RegisterContext.h" #include "lldb/ValueObject/DILAST.h" @@ -330,40 +332,135 @@ Interpreter::Visit(const ArraySubscriptNode *node) { return lhs_or_err; lldb::ValueObjectSP base = *lhs_or_err; - // Check to see if 'base' has a synthetic value; if so, try using that. + StreamString var_expr_path_strm; uint64_t child_idx = node->GetIndex(); - if (lldb::ValueObjectSP synthetic = base->GetSyntheticValue()) { - llvm::Expected<uint32_t> num_children = - synthetic->GetNumChildren(child_idx + 1); - if (!num_children) - return llvm::make_error<DILDiagnosticError>( - m_expr, toString(num_children.takeError()), node->GetLocation()); - if (child_idx >= *num_children) { - std::string message = llvm::formatv( - "array index {0} is not valid for \"({1}) {2}\"", child_idx, + lldb::ValueObjectSP child_valobj_sp; + + bool is_incomplete_array = false; + CompilerType base_type = base->GetCompilerType().GetNonReferenceType(); + base->GetExpressionPath(var_expr_path_strm); + + if (base_type.IsPointerType()) { + bool is_objc_pointer = true; + + if (base->GetCompilerType().GetMinimumLanguage() != lldb::eLanguageTypeObjC) + is_objc_pointer = false; + else if (!base->GetCompilerType().IsPointerType()) + is_objc_pointer = false; + + if (!m_use_synthetic && is_objc_pointer) { + std::string err_msg = llvm::formatv( + "\"({0}) {1}\" is an Objective-C pointer, and cannot be subscripted", base->GetTypeName().AsCString("<invalid type>"), - base->GetName().AsCString()); - return llvm::make_error<DILDiagnosticError>(m_expr, message, + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), node->GetLocation()); } - if (lldb::ValueObjectSP child_valobj_sp = - synthetic->GetChildAtIndex(child_idx)) + if (is_objc_pointer) { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (!synthetic || synthetic == base) { + std::string err_msg = + llvm::formatv("\"({0}) {1}\" is not an array type", + base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation()); + } + if (static_cast<uint32_t>(child_idx) >= + synthetic->GetNumChildrenIgnoringErrors()) { + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation()); + } + child_valobj_sp = synthetic->GetChildAtIndex(child_idx); + if (!child_valobj_sp) { + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation()); + } + if (m_use_dynamic != lldb::eNoDynamicValues) { + if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic)) + child_valobj_sp = std::move(dynamic_sp); + } return child_valobj_sp; - } + } - auto base_type = base->GetCompilerType().GetNonReferenceType(); - if (!base_type.IsPointerType() && !base_type.IsArrayType()) - return llvm::make_error<DILDiagnosticError>( - m_expr, "subscripted value is not an array or pointer", - node->GetLocation()); - if (base_type.IsPointerToVoid()) - return llvm::make_error<DILDiagnosticError>( - m_expr, "subscript of pointer to incomplete type 'void'", - node->GetLocation()); + child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); + if (!child_valobj_sp) { + std::string err_msg = llvm::formatv( + "failed to use pointer as array for index {0} for " + "\"({1}) {2}\"", + child_idx, base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + if (base_type.IsPointerToVoid()) + err_msg = "subscript of pointer to incomplete type 'void'"; + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation()); + } + } else if (base_type.IsArrayType(nullptr, nullptr, &is_incomplete_array)) { + child_valobj_sp = base->GetChildAtIndex(child_idx); + if (!child_valobj_sp && (is_incomplete_array || m_use_synthetic)) + child_valobj_sp = base->GetSyntheticArrayMember(child_idx, true); + if (!child_valobj_sp) { + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation()); + } + } else if (base_type.IsScalarType()) { + child_valobj_sp = + base->GetSyntheticBitFieldChild(child_idx, child_idx, true); + if (!child_valobj_sp) { + std::string err_msg = llvm::formatv( + "bitfield range {0}-{1} is not valid for \"({2}) {3}\"", child_idx, + child_idx, base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation(), 1); + } + } else { + lldb::ValueObjectSP synthetic = base->GetSyntheticValue(); + if (!m_use_synthetic || !synthetic || synthetic == base) { + std::string err_msg = + llvm::formatv("\"{0}\" is not an array type", + base->GetTypeName().AsCString("<invalid type>")); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation(), 1); + } + if (static_cast<uint32_t>(child_idx) >= + synthetic->GetNumChildrenIgnoringErrors(child_idx + 1)) { + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation(), 1); + } + child_valobj_sp = synthetic->GetChildAtIndex(child_idx); + if (!child_valobj_sp) { + std::string err_msg = llvm::formatv( + "array index {0} is not valid for \"({1}) {2}\"", child_idx, + base->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetData()); + return llvm::make_error<DILDiagnosticError>(m_expr, std::move(err_msg), + node->GetLocation(), 1); + } + } - if (base_type.IsArrayType()) { - if (lldb::ValueObjectSP child_valobj_sp = base->GetChildAtIndex(child_idx)) - return child_valobj_sp; + if (child_valobj_sp) { + if (m_use_dynamic != lldb::eNoDynamicValues) { + if (auto dynamic_sp = child_valobj_sp->GetDynamicValue(m_use_dynamic)) + child_valobj_sp = std::move(dynamic_sp); + } + return child_valobj_sp; } int64_t signed_child_idx = node->GetIndex(); @@ -402,4 +499,107 @@ 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, + const IntegerLiteralNode *literal) { + // Binary, Octal, Hexadecimal and literals with a U suffix are allowed to be + // an unsigned integer. + bool unsigned_is_allowed = literal->IsUnsigned() || literal->GetRadix() != 10; + llvm::APInt apint = literal->GetValue(); + + llvm::SmallVector<std::pair<lldb::BasicType, lldb::BasicType>, 3> candidates; + if (literal->GetTypeSuffix() <= IntegerTypeSuffix::None) + candidates.emplace_back(lldb::eBasicTypeInt, + unsigned_is_allowed ? lldb::eBasicTypeUnsignedInt + : lldb::eBasicTypeInvalid); + if (literal->GetTypeSuffix() <= IntegerTypeSuffix::Long) + candidates.emplace_back(lldb::eBasicTypeLong, + unsigned_is_allowed ? lldb::eBasicTypeUnsignedLong + : lldb::eBasicTypeInvalid); + candidates.emplace_back(lldb::eBasicTypeLongLong, + lldb::eBasicTypeUnsignedLongLong); + for (auto [signed_, unsigned_] : candidates) { + CompilerType signed_type = type_system->GetBasicTypeFromAST(signed_); + if (!signed_type) + continue; + llvm::Expected<uint64_t> size = signed_type.GetBitSize(ctx.get()); + if (!size) + return size.takeError(); + if (!literal->IsUnsigned() && apint.isIntN(*size - 1)) + return signed_type; + if (unsigned_ != lldb::eBasicTypeInvalid && apint.isIntN(*size)) + return type_system->GetBasicTypeFromAST(unsigned_); + } + + return llvm::make_error<DILDiagnosticError>( + m_expr, + "integer literal is too large to be represented in any integer type", + literal->GetLocation()); +} + +llvm::Expected<lldb::ValueObjectSP> +Interpreter::Visit(const IntegerLiteralNode *node) { + llvm::Expected<lldb::TypeSystemSP> type_system = + GetTypeSystemFromCU(m_exe_ctx_scope); + if (!type_system) + return type_system.takeError(); + + llvm::Expected<CompilerType> type = + PickIntegerType(*type_system, m_exe_ctx_scope, node); + if (!type) + return type.takeError(); + + Scalar scalar = node->GetValue(); + // APInt from StringRef::getAsInteger comes with just enough bitwidth to + // hold the value. This adjusts APInt bitwidth to match the compiler type. + llvm::Expected<uint64_t> type_bitsize = + type->GetBitSize(m_exe_ctx_scope.get()); + if (!type_bitsize) + return type_bitsize.takeError(); + scalar.TruncOrExtendTo(*type_bitsize, false); + return ValueObject::CreateValueObjectFromScalar(m_target, scalar, *type, + "result"); +} + +llvm::Expected<lldb::ValueObjectSP> +Interpreter::Visit(const FloatLiteralNode *node) { + llvm::Expected<lldb::TypeSystemSP> type_system = + GetTypeSystemFromCU(m_exe_ctx_scope); + if (!type_system) + return type_system.takeError(); + + bool isFloat = + &node->GetValue().getSemantics() == &llvm::APFloat::IEEEsingle(); + lldb::BasicType basic_type = + isFloat ? lldb::eBasicTypeFloat : lldb::eBasicTypeDouble; + CompilerType type = GetBasicType(*type_system, basic_type); + + if (!type) + return llvm::make_error<DILDiagnosticError>( + m_expr, "unable to create a const literal", node->GetLocation()); + + Scalar scalar = node->GetValue(); + return ValueObject::CreateValueObjectFromScalar(m_target, scalar, type, + "result"); +} + } // namespace lldb_private::dil diff --git a/lldb/source/ValueObject/DILLexer.cpp b/lldb/source/ValueObject/DILLexer.cpp index eaefaf484bc1..0b2288a9d923 100644 --- a/lldb/source/ValueObject/DILLexer.cpp +++ b/lldb/source/ValueObject/DILLexer.cpp @@ -28,18 +28,23 @@ llvm::StringRef Token::GetTokenName(Kind kind) { return "coloncolon"; case Kind::eof: return "eof"; + case Kind::float_constant: + return "float_constant"; case Kind::identifier: return "identifier"; + case Kind::integer_constant: + return "integer_constant"; case Kind::l_paren: return "l_paren"; case Kind::l_square: return "l_square"; case Kind::minus: return "minus"; - case Kind::numeric_constant: - return "numeric_constant"; case Kind::period: return "period"; + return "l_square"; + case Kind::plus: + return "plus"; case Kind::r_paren: return "r_paren"; case Kind::r_square: @@ -70,13 +75,32 @@ static std::optional<llvm::StringRef> IsWord(llvm::StringRef expr, return candidate; } -static bool IsNumberBodyChar(char ch) { return IsDigit(ch) || IsLetter(ch); } +static bool IsNumberBodyChar(char ch) { + return IsDigit(ch) || IsLetter(ch) || ch == '.'; +} -static std::optional<llvm::StringRef> IsNumber(llvm::StringRef expr, - llvm::StringRef &remainder) { - if (IsDigit(remainder[0])) { - llvm::StringRef number = remainder.take_while(IsNumberBodyChar); - remainder = remainder.drop_front(number.size()); +static std::optional<llvm::StringRef> IsNumber(llvm::StringRef &remainder, + bool &isFloat) { + llvm::StringRef tail = remainder; + llvm::StringRef body = tail.take_while(IsNumberBodyChar); + size_t dots = body.count('.'); + if (dots > 1 || dots == body.size()) + return std::nullopt; + if (IsDigit(body.front()) || (body[0] == '.' && IsDigit(body[1]))) { + isFloat = dots == 1; + tail = tail.drop_front(body.size()); + bool isHex = body.contains_insensitive('x'); + bool hasExp = !isHex && body.contains_insensitive('e'); + bool hasHexExp = isHex && body.contains_insensitive('p'); + if (hasExp || hasHexExp) { + isFloat = true; // This marks numbers like 0x1p1 and 1e1 as float + if (body.ends_with_insensitive("e") || body.ends_with_insensitive("p")) + if (tail.consume_front("+") || tail.consume_front("-")) + tail = tail.drop_while(IsNumberBodyChar); + } + size_t number_length = remainder.size() - tail.size(); + llvm::StringRef number = remainder.take_front(number_length); + remainder = remainder.drop_front(number_length); return number; } return std::nullopt; @@ -106,18 +130,21 @@ llvm::Expected<Token> DILLexer::Lex(llvm::StringRef expr, return Token(Token::eof, "", (uint32_t)expr.size()); uint32_t position = cur_pos - expr.begin(); - std::optional<llvm::StringRef> maybe_number = IsNumber(expr, remainder); - if (maybe_number) - return Token(Token::numeric_constant, maybe_number->str(), position); + bool isFloat = false; + std::optional<llvm::StringRef> maybe_number = IsNumber(remainder, isFloat); + if (maybe_number) { + auto kind = isFloat ? Token::float_constant : Token::integer_constant; + return Token(kind, maybe_number->str(), position); + } std::optional<llvm::StringRef> maybe_word = IsWord(expr, remainder); if (maybe_word) return Token(Token::identifier, maybe_word->str(), position); constexpr std::pair<Token::Kind, const char *> operators[] = { - {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"}, - {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"}, - {Token::period, "."}, {Token::r_paren, ")"}, {Token::r_square, "]"}, - {Token::star, "*"}, + {Token::amp, "&"}, {Token::arrow, "->"}, {Token::coloncolon, "::"}, + {Token::l_paren, "("}, {Token::l_square, "["}, {Token::minus, "-"}, + {Token::period, "."}, {Token::plus, "+"}, {Token::r_paren, ")"}, + {Token::r_square, "]"}, {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 eac41fab9076..8c4f7fdb25be 100644 --- a/lldb/source/ValueObject/DILParser.cpp +++ b/lldb/source/ValueObject/DILParser.cpp @@ -179,10 +179,13 @@ ASTNodeUP DILParser::ParsePostfixExpression() { // Parse a primary_expression. // // primary_expression: +// numeric_literal // id_expression // "(" expression ")" // ASTNodeUP DILParser::ParsePrimaryExpression() { + if (CurToken().IsOneOf({Token::integer_constant, Token::float_constant})) + return ParseNumericLiteral(); if (CurToken().IsOneOf( {Token::coloncolon, Token::identifier, Token::l_paren})) { // Save the source location for the diagnostics message. @@ -346,6 +349,7 @@ void DILParser::BailOut(const std::string &error, uint32_t loc, m_dil_lexer.ResetTokenIdx(m_dil_lexer.NumLexedTokens() - 1); } +// FIXME: Remove this once subscript operator uses ScalarLiteralNode. // Parse a integer_literal. // // integer_literal: @@ -370,6 +374,69 @@ std::optional<int64_t> DILParser::ParseIntegerConstant() { return std::nullopt; } +// Parse a numeric_literal. +// +// numeric_literal: +// ? Token::integer_constant ? +// ? Token::floating_constant ? +// +ASTNodeUP DILParser::ParseNumericLiteral() { + ASTNodeUP numeric_constant; + if (CurToken().Is(Token::integer_constant)) + numeric_constant = ParseIntegerLiteral(); + else + numeric_constant = ParseFloatingPointLiteral(); + if (!numeric_constant) { + BailOut(llvm::formatv("Failed to parse token as numeric-constant: {0}", + CurToken()), + CurToken().GetLocation(), CurToken().GetSpelling().length()); + return std::make_unique<ErrorNode>(); + } + m_dil_lexer.Advance(); + return numeric_constant; +} + +ASTNodeUP DILParser::ParseIntegerLiteral() { + Token token = CurToken(); + auto spelling = token.GetSpelling(); + llvm::StringRef spelling_ref = spelling; + + auto radix = llvm::getAutoSenseRadix(spelling_ref); + IntegerTypeSuffix type = IntegerTypeSuffix::None; + bool is_unsigned = false; + if (spelling_ref.consume_back_insensitive("u")) + is_unsigned = true; + if (spelling_ref.consume_back_insensitive("ll")) + type = IntegerTypeSuffix::LongLong; + else if (spelling_ref.consume_back_insensitive("l")) + type = IntegerTypeSuffix::Long; + // Suffix 'u' can be only specified only once, before or after 'l' + if (!is_unsigned && spelling_ref.consume_back_insensitive("u")) + is_unsigned = true; + + llvm::APInt raw_value; + if (!spelling_ref.getAsInteger(radix, raw_value)) + return std::make_unique<IntegerLiteralNode>(token.GetLocation(), raw_value, + radix, is_unsigned, type); + return nullptr; +} + +ASTNodeUP DILParser::ParseFloatingPointLiteral() { + Token token = CurToken(); + auto spelling = token.GetSpelling(); + llvm::StringRef spelling_ref = spelling; + + llvm::APFloat raw_float(llvm::APFloat::IEEEdouble()); + if (spelling_ref.consume_back_insensitive("f")) + raw_float = llvm::APFloat(llvm::APFloat::IEEEsingle()); + + auto StatusOrErr = raw_float.convertFromString( + spelling_ref, llvm::APFloat::rmNearestTiesToEven); + if (!errorToBool(StatusOrErr.takeError())) + return std::make_unique<FloatLiteralNode>(token.GetLocation(), raw_float); + return nullptr; +} + void DILParser::Expect(Token::Kind kind) { if (CurToken().IsNot(kind)) { BailOut(llvm::formatv("expected {0}, got: {1}", kind, CurToken()), |
