From fde3e045d4dcc5c404cb4216389e18b0e720b8e0 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Thu, 13 Aug 2026 12:55:12 +0800 Subject: [IR] Split LL parsing, assembly writing, and data layout --- backend/lib/MIR/LLVMConstantSyntax.cpp | 2025 -------------------------------- 1 file changed, 2025 deletions(-) delete mode 100644 backend/lib/MIR/LLVMConstantSyntax.cpp (limited to 'backend/lib/MIR/LLVMConstantSyntax.cpp') diff --git a/backend/lib/MIR/LLVMConstantSyntax.cpp b/backend/lib/MIR/LLVMConstantSyntax.cpp deleted file mode 100644 index 4ee231d..0000000 --- a/backend/lib/MIR/LLVMConstantSyntax.cpp +++ /dev/null @@ -1,2025 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "rcc/MIR/LLVMConstantSyntax.h" - -#include "rcc/ADT/APFloat.h" -#include "rcc/ADT/APInt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace rcc::mir { -namespace { - -struct ParsedName final { - std::string Value; - bool Numeric = false; -}; - -[[nodiscard]] bool isSpace(char Character) noexcept { - return Character == ' ' || Character == '\t' || Character == '\r' || Character == '\n'; -} - -[[nodiscard]] bool isIdentifierStart(char Character) noexcept { - return (Character >= 'A' && Character <= 'Z') || (Character >= 'a' && Character <= 'z') || - Character == '-' || Character == '$' || Character == '.' || Character == '_'; -} - -[[nodiscard]] bool isIdentifierBody(char Character) noexcept { - return isIdentifierStart(Character) || (Character >= '0' && Character <= '9'); -} - -[[nodiscard]] bool isHexDigit(char Character) noexcept { - return (Character >= '0' && Character <= '9') || (Character >= 'a' && Character <= 'f') || - (Character >= 'A' && Character <= 'F'); -} - -[[nodiscard]] unsigned hexDigitValue(char Character) noexcept { - if (Character >= '0' && Character <= '9') - return static_cast(Character - '0'); - if (Character >= 'a' && Character <= 'f') - return static_cast(Character - 'a') + 10U; - return static_cast(Character - 'A') + 10U; -} - -[[nodiscard]] std::optional floatingSemantics(std::string_view Name) noexcept { - if (Name == "half") - return FloatSemantics::IEEEHalf; - if (Name == "bfloat") - return FloatSemantics::BFloat; - if (Name == "float") - return FloatSemantics::IEEESingle; - if (Name == "double") - return FloatSemantics::IEEEDouble; - if (Name == "fp128") - return FloatSemantics::IEEEQuad; - if (Name == "ppc_fp128") - return FloatSemantics::PPCDoubleDouble; - if (Name == "x86_fp80") - return FloatSemantics::X87DoubleExtended; - return std::nullopt; -} - -[[nodiscard]] Expected checkedMultiply(std::uint64_t Left, std::uint64_t Right, - std::string_view Description) { - if (Left != 0 && Right > std::numeric_limits::max() / Left) - return makeUnexpected(ErrorCode::Unsupported, std::string(Description) + " is too large"); - return Left * Right; -} - -[[nodiscard]] Expected checkedAdd(std::uint64_t Left, std::uint64_t Right, - std::string_view Description) { - if (Right > std::numeric_limits::max() - Left) - return makeUnexpected(ErrorCode::Unsupported, std::string(Description) + " is too large"); - return Left + Right; -} - -[[nodiscard]] Expected alignTo(std::uint64_t Value, std::uint64_t AlignmentValue) { - if (AlignmentValue == 0 || !std::has_single_bit(AlignmentValue)) - return makeUnexpected(ErrorCode::InvalidArgument, "LLVM type alignment is invalid"); - const std::uint64_t Mask = AlignmentValue - 1U; - if (Value > std::numeric_limits::max() - Mask) - return makeUnexpected(ErrorCode::Unsupported, "LLVM type allocation size is too large"); - return (Value + Mask) & ~Mask; -} - -[[nodiscard]] const GenericConstantType &resolvedType(const GenericConstantType &Type) noexcept { - const GenericConstantType *Resolved = &Type; - std::size_t Depth = 0; - while (Resolved->Kind == GenericConstantTypeKind::Named && Resolved->Elements.size() == 1 && - Depth++ < 1024) { - Resolved = &Resolved->Elements.front(); - } - return *Resolved; -} - -class ConstantParser final { -public: - ConstantParser(std::string_view SourceText, LLVMConstantSyntaxOptions ParserOptions, - std::vector ResolvingTypes = {}) - : Text(SourceText), Options(ParserOptions), ResolvingNamedTypes(std::move(ResolvingTypes)) {} - - [[nodiscard]] Expected parse(); - [[nodiscard]] Expected parseTypeOnly(); - -private: - template [[nodiscard]] Expected fail(std::string_view Message) const { - return makeUnexpected(ErrorCode::ParseError, "LLVM constant at byte " + - std::to_string(Position) + ": " + - std::string(Message)); - } - - void skipSpace() noexcept { - while (Position < Text.size() && isSpace(Text[Position])) - ++Position; - } - - [[nodiscard]] bool atEnd() { - skipSpace(); - return Position == Text.size(); - } - - [[nodiscard]] bool consume(char Character) { - skipSpace(); - if (Position >= Text.size() || Text[Position] != Character) - return false; - ++Position; - return true; - } - - [[nodiscard]] bool consumeWord(std::string_view Word) { - skipSpace(); - if (!Text.substr(Position).starts_with(Word)) - return false; - const std::size_t End = Position + Word.size(); - if (End < Text.size() && isIdentifierBody(Text[End])) - return false; - Position = End; - return true; - } - - [[nodiscard]] std::optional peekWord() { - skipSpace(); - if (Position >= Text.size() || !isIdentifierStart(Text[Position])) - return std::nullopt; - std::size_t End = Position + 1; - while (End < Text.size() && isIdentifierBody(Text[End])) - ++End; - return Text.substr(Position, End - Position); - } - - [[nodiscard]] Expected expect(char Character, std::string_view Description) { - if (!consume(Character)) - return fail("expected " + std::string(Description)); - return {}; - } - - [[nodiscard]] Expected expectWord(std::string_view Word) { - if (!consumeWord(Word)) - return fail("expected '" + std::string(Word) + "'"); - return {}; - } - - [[nodiscard]] Expected parseUnsigned(); - [[nodiscard]] Expected parseName(char Prefix); - [[nodiscard]] Expected> parseByteString(); - [[nodiscard]] Expected parseType(std::size_t Depth = 0); - [[nodiscard]] Expected resolveNamedType(GenericConstantType &Type, std::size_t Depth); - [[nodiscard]] Expected parsePrimaryType(std::size_t Depth); - [[nodiscard]] Expected parseTypedValue(std::size_t Depth); - [[nodiscard]] Expected parseValue(GenericConstantType Type, - std::size_t Depth); - [[nodiscard]] Expected - parseAggregate(GenericConstantType Type, char Open, char Close, bool Packed, std::size_t Depth); - [[nodiscard]] Expected parseFloatingValue(GenericConstantType Type, - std::size_t Depth); - [[nodiscard]] Expected - parseExpression(GenericConstantType Type, std::string_view Opcode, std::size_t Depth); - - [[nodiscard]] Expected accountNode(std::size_t Depth) { - if (Depth > Options.MaximumDepth || ++Nodes > Options.MaximumNodes) - return fail("constant exceeds configured structural limits"); - return {}; - } - - [[nodiscard]] Expected parseValueToken(); - - std::string_view Text; - LLVMConstantSyntaxOptions Options; - std::size_t Position = 0; - std::size_t Nodes = 0; - std::vector ResolvingNamedTypes; -}; - -Expected ConstantParser::parseUnsigned() { - skipSpace(); - const std::size_t Begin = Position; - while (Position < Text.size() && Text[Position] >= '0' && Text[Position] <= '9') - ++Position; - if (Begin == Position) - return fail("expected an unsigned integer"); - std::uint64_t Value = 0; - const auto Parsed = std::from_chars(Text.data() + Begin, Text.data() + Position, Value, 10); - if (Parsed.ec != std::errc{}) - return fail("unsigned integer is out of range"); - return Value; -} - -Expected ConstantParser::parseName(char Prefix) { - skipSpace(); - if (Position >= Text.size() || Text[Position] != Prefix) - return fail(std::string("expected '") + Prefix + "' identifier"); - ++Position; - if (Position >= Text.size()) - return fail("identifier is empty"); - - ParsedName Result; - if (Text[Position] == '"') { - ++Position; - while (Position < Text.size() && Text[Position] != '"') { - if (Text[Position] != '\\') { - if (static_cast(Text[Position]) < 0x20U) - return fail("identifier contains a control character"); - Result.Value.push_back(Text[Position++]); - continue; - } - ++Position; - if (Position + 1 >= Text.size() || !isHexDigit(Text[Position]) || - !isHexDigit(Text[Position + 1])) { - return fail("identifier escape requires two hexadecimal digits"); - } - Result.Value.push_back(static_cast((hexDigitValue(Text[Position]) << 4U) | - hexDigitValue(Text[Position + 1]))); - Position += 2; - } - if (Position >= Text.size()) - return fail("quoted identifier is unterminated"); - ++Position; - return Result; - } - - if (Text[Position] >= '0' && Text[Position] <= '9') { - Result.Numeric = true; - const std::size_t Begin = Position; - while (Position < Text.size() && Text[Position] >= '0' && Text[Position] <= '9') - ++Position; - Result.Value = std::string(Text.substr(Begin, Position - Begin)); - return Result; - } - if (!isIdentifierStart(Text[Position])) - return fail("identifier has an invalid first character"); - const std::size_t Begin = Position++; - while (Position < Text.size() && isIdentifierBody(Text[Position])) - ++Position; - Result.Value = std::string(Text.substr(Begin, Position - Begin)); - return Result; -} - -Expected> ConstantParser::parseByteString() { - skipSpace(); - if (Position >= Text.size() || Text[Position] != '"') - return fail>("expected an LLVM byte string"); - ++Position; - std::vector Bytes; - while (Position < Text.size() && Text[Position] != '"') { - const char Character = Text[Position++]; - if (Character != '\\') { - if (static_cast(Character) < 0x20U) - return fail>("byte string contains a control character"); - Bytes.push_back(static_cast(static_cast(Character))); - continue; - } - if (Position + 1 >= Text.size() || !isHexDigit(Text[Position]) || - !isHexDigit(Text[Position + 1])) { - return fail>("byte-string escape requires two hexadecimal digits"); - } - Bytes.push_back(static_cast((hexDigitValue(Text[Position]) << 4U) | - hexDigitValue(Text[Position + 1]))); - Position += 2; - } - if (Position >= Text.size()) - return fail>("LLVM byte string is unterminated"); - ++Position; - return Bytes; -} - -Expected ConstantParser::parsePrimaryType(std::size_t Depth) { - if (auto Limit = accountNode(Depth); !Limit) - return std::unexpected(Limit.error()); - skipSpace(); - - if (consume('[')) { - auto Count = parseUnsigned(); - if (!Count) - return std::unexpected(Count.error()); - if (auto Separator = expectWord("x"); !Separator) - return std::unexpected(Separator.error()); - auto Element = parseType(Depth + 1); - if (!Element) - return std::unexpected(Element.error()); - if (auto End = expect(']', "']' after array type"); !End) - return std::unexpected(End.error()); - return GenericConstantType::array(*Count, std::move(*Element)); - } - - if (consume('<')) { - if (consume('{')) { - std::vector Elements; - if (!consume('}')) { - while (true) { - auto Element = parseType(Depth + 1); - if (!Element) - return std::unexpected(Element.error()); - Elements.push_back(std::move(*Element)); - if (consume('}')) - break; - if (auto Comma = expect(',', "',' between packed struct members"); !Comma) - return std::unexpected(Comma.error()); - } - } - if (auto End = expect('>', "'>' after packed struct type"); !End) - return std::unexpected(End.error()); - return GenericConstantType::structure(std::move(Elements), true); - } - - const bool Scalable = consumeWord("vscale"); - if (Scalable) { - if (auto Separator = expectWord("x"); !Separator) - return std::unexpected(Separator.error()); - } - auto Count = parseUnsigned(); - if (!Count) - return std::unexpected(Count.error()); - if (auto Separator = expectWord("x"); !Separator) - return std::unexpected(Separator.error()); - auto Element = parseType(Depth + 1); - if (!Element) - return std::unexpected(Element.error()); - if (auto End = expect('>', "'>' after vector type"); !End) - return std::unexpected(End.error()); - return GenericConstantType::vector(*Count, std::move(*Element), Scalable); - } - - if (consume('{')) { - std::vector Elements; - if (!consume('}')) { - while (true) { - auto Element = parseType(Depth + 1); - if (!Element) - return std::unexpected(Element.error()); - Elements.push_back(std::move(*Element)); - if (consume('}')) - break; - if (auto Comma = expect(',', "',' between struct members"); !Comma) - return std::unexpected(Comma.error()); - } - } - return GenericConstantType::structure(std::move(Elements), false); - } - - skipSpace(); - if (Position < Text.size() && Text[Position] == '%') { - auto Name = parseName('%'); - if (!Name) - return std::unexpected(Name.error()); - return GenericConstantType::named(std::move(Name->Value), Name->Numeric); - } - - const auto Word = peekWord(); - if (!Word) - return fail("expected an LLVM IR type"); - Position += Word->size(); - if (*Word == "void") - return GenericConstantType::primitive(GenericConstantTypeKind::Void); - if (*Word == "label") - return GenericConstantType::primitive(GenericConstantTypeKind::Label); - if (*Word == "token") - return GenericConstantType::primitive(GenericConstantTypeKind::Token); - if (*Word == "metadata") - return GenericConstantType::primitive(GenericConstantTypeKind::Metadata); - if (*Word == "byte") - return GenericConstantType::byte(); - if (Word->starts_with('i')) { - std::uint64_t Width = 0; - const auto Parsed = std::from_chars(Word->data() + 1, Word->data() + Word->size(), Width, 10); - if (Word->size() == 1 || Parsed.ec != std::errc{} || - Parsed.ptr != Word->data() + Word->size() || - Width > std::numeric_limits::max()) { - return fail("integer type has an invalid bit width"); - } - return GenericConstantType::integer(static_cast(Width)); - } - if (const auto Semantics = floatingSemantics(*Word)) - return GenericConstantType::floating(*Semantics); - if (*Word == "ptr") { - std::uint32_t AddressSpace = 0; - if (consumeWord("addrspace")) { - if (auto Open = expect('(', "'(' after addrspace"); !Open) - return std::unexpected(Open.error()); - auto ParsedAddressSpace = parseUnsigned(); - if (!ParsedAddressSpace || *ParsedAddressSpace > std::numeric_limits::max()) - return fail("pointer address space is out of range"); - AddressSpace = static_cast(*ParsedAddressSpace); - if (auto Close = expect(')', "')' after address space"); !Close) - return std::unexpected(Close.error()); - } - return GenericConstantType::pointer(AddressSpace); - } - return fail("unsupported LLVM IR type '" + std::string(*Word) + "'"); -} - -Expected ConstantParser::parseType(std::size_t Depth) { - auto Type = parsePrimaryType(Depth); - if (!Type) - return std::unexpected(Type.error()); - - while (true) { - skipSpace(); - if (consume('(')) { - std::vector Parameters; - bool VarArg = false; - if (!consume(')')) { - while (true) { - skipSpace(); - if (Text.substr(Position).starts_with("...")) { - Position += 3; - VarArg = true; - if (auto End = expect(')', "')' after variadic function type"); !End) - return std::unexpected(End.error()); - break; - } - auto Parameter = parseType(Depth + 1); - if (!Parameter) - return std::unexpected(Parameter.error()); - Parameters.push_back(std::move(*Parameter)); - if (consume(')')) - break; - if (auto Comma = expect(',', "',' between function parameters"); !Comma) - return std::unexpected(Comma.error()); - } - } - Type = GenericConstantType::function(std::move(*Type), std::move(Parameters), VarArg); - if (!Type) - return std::unexpected(Type.error()); - continue; - } - - std::uint32_t AddressSpace = 0; - const std::size_t BeforeAddressSpace = Position; - if (consumeWord("addrspace")) { - if (auto Open = expect('(', "'(' after addrspace"); !Open) - return std::unexpected(Open.error()); - auto ParsedAddressSpace = parseUnsigned(); - if (!ParsedAddressSpace || *ParsedAddressSpace > std::numeric_limits::max()) - return fail("pointer address space is out of range"); - AddressSpace = static_cast(*ParsedAddressSpace); - if (auto Close = expect(')', "')' after address space"); !Close) - return std::unexpected(Close.error()); - } - if (consume('*')) { - Type = GenericConstantType::pointer(AddressSpace); - continue; - } - Position = BeforeAddressSpace; - break; - } - if (Type->Kind == GenericConstantTypeKind::Named) { - if (auto Resolved = resolveNamedType(*Type, Depth + 1); !Resolved) - return std::unexpected(Resolved.error()); - } - return Type; -} - -Expected ConstantParser::resolveNamedType(GenericConstantType &Type, std::size_t Depth) { - if (Type.Kind != GenericConstantTypeKind::Named || !Type.Elements.empty()) - return {}; - const auto Definition = - std::ranges::find_if(Options.NamedTypes, [&Type](const LLVMNamedTypeDefinition &Candidate) { - return Candidate.Name == Type.Name && Candidate.NumericName == Type.NumericName; - }); - if (Definition == Options.NamedTypes.end()) - return {}; - if (Depth > Options.MaximumDepth || - std::ranges::find(ResolvingNamedTypes, Type.Name) != ResolvingNamedTypes.end()) { - return fail("named LLVM type definition is recursively unsized"); - } - std::vector Stack = ResolvingNamedTypes; - Stack.push_back(Type.Name); - ConstantParser DefinitionParser(Definition->Definition, Options, std::move(Stack)); - auto Resolved = DefinitionParser.parseTypeOnly(); - if (!Resolved) - return std::unexpected(Resolved.error()); - Type.Elements.push_back(std::move(*Resolved)); - return {}; -} - -Expected ConstantParser::parseValueToken() { - skipSpace(); - const std::size_t Begin = Position; - unsigned ParenthesisDepth = 0; - while (Position < Text.size()) { - const char Character = Text[Position]; - if (Character == '(') { - ++ParenthesisDepth; - ++Position; - continue; - } - if (Character == ')') { - if (ParenthesisDepth == 0) - break; - --ParenthesisDepth; - ++Position; - continue; - } - if (ParenthesisDepth == 0 && (isSpace(Character) || Character == ',' || Character == ']' || - Character == '}' || Character == '>')) { - break; - } - ++Position; - if (Position - Begin > Options.MaximumTokenLength) - return fail("value token exceeds the configured length limit"); - } - if (Begin == Position) - return fail("expected an LLVM constant value"); - return Text.substr(Begin, Position - Begin); -} - -Expected ConstantParser::parseFloatingValue(GenericConstantType Type, - std::size_t Depth) { - const GenericConstantType &EffectiveType = resolvedType(Type); - if (EffectiveType.Kind != GenericConstantTypeKind::Floating) - return fail("floating literal requires a floating-point type"); - auto Token = parseValueToken(); - if (!Token) - return std::unexpected(Token.error()); - auto Bits = APFloat::parse(EffectiveType.Semantics, *Token); - if (!Bits) - return fail(Bits.error().message()); - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::Floating; - Value.FloatingValue = *Bits; - if (auto Limit = accountNode(Depth); !Limit) - return std::unexpected(Limit.error()); - return Value; -} - -Expected ConstantParser::parseAggregate(GenericConstantType Type, char Open, - char Close, bool Packed, - std::size_t Depth) { - if (!consume(Open)) - return fail(std::string("expected '") + Open + "' for aggregate"); - if (Packed && !consume('{')) - return fail("expected '{' in packed struct constant"); - - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::Aggregate; - const char InnerClose = Packed ? '}' : Close; - if (!consume(InnerClose)) { - while (true) { - auto Element = parseTypedValue(Depth + 1); - if (!Element) - return std::unexpected(Element.error()); - Value.Elements.push_back(std::move(*Element)); - if (consume(InnerClose)) - break; - if (auto Comma = expect(',', "',' between aggregate elements"); !Comma) - return std::unexpected(Comma.error()); - } - } - if (Packed) { - if (auto End = expect('>', "'>' after packed struct constant"); !End) - return std::unexpected(End.error()); - } - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; -} - -Expected ConstantParser::parseTypedValue(std::size_t Depth) { - auto Type = parseType(Depth + 1); - if (!Type) - return std::unexpected(Type.error()); - return parseValue(std::move(*Type), Depth + 1); -} - -Expected ConstantParser::parseExpression(GenericConstantType Type, - std::string_view Opcode, - std::size_t Depth) { - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::Expression; - - const auto SetOpcode = [&](GenericConstantExpressionOpcode ParsedOpcode) { - Value.ExpressionOpcode = ParsedOpcode; - }; - if (Opcode == "trunc") - SetOpcode(GenericConstantExpressionOpcode::Trunc); - else if (Opcode == "bitcast") - SetOpcode(GenericConstantExpressionOpcode::BitCast); - else if (Opcode == "addrspacecast") - SetOpcode(GenericConstantExpressionOpcode::AddressSpaceCast); - else if (Opcode == "inttoptr") - SetOpcode(GenericConstantExpressionOpcode::IntToPtr); - else if (Opcode == "ptrtoaddr") - SetOpcode(GenericConstantExpressionOpcode::PtrToAddr); - else if (Opcode == "ptrtoint") - SetOpcode(GenericConstantExpressionOpcode::PtrToInt); - else if (Opcode == "add") - SetOpcode(GenericConstantExpressionOpcode::Add); - else if (Opcode == "sub") - SetOpcode(GenericConstantExpressionOpcode::Sub); - else if (Opcode == "xor") - SetOpcode(GenericConstantExpressionOpcode::Xor); - else if (Opcode == "getelementptr") - SetOpcode(GenericConstantExpressionOpcode::GetElementPtr); - else if (Opcode == "shufflevector") - SetOpcode(GenericConstantExpressionOpcode::ShuffleVector); - else if (Opcode == "insertelement") - SetOpcode(GenericConstantExpressionOpcode::InsertElement); - else if (Opcode == "extractelement") - SetOpcode(GenericConstantExpressionOpcode::ExtractElement); - else if (Opcode == "splat") - SetOpcode(GenericConstantExpressionOpcode::Splat); - else - return fail("unsupported constant expression '" + std::string(Opcode) + - "'"); - - const bool IsCast = Value.ExpressionOpcode == GenericConstantExpressionOpcode::Trunc || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::BitCast || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::AddressSpaceCast || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::IntToPtr || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::PtrToAddr || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::PtrToInt; - const bool IsBinary = Value.ExpressionOpcode == GenericConstantExpressionOpcode::Add || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::Sub || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::Xor; - - if (IsBinary) { - while (true) { - if (consumeWord("nuw")) { - Value.ExpressionFlags.set(GenericConstantExpressionFlag::NoUnsignedWrap); - continue; - } - if (consumeWord("nsw")) { - Value.ExpressionFlags.set(GenericConstantExpressionFlag::NoSignedWrap); - continue; - } - break; - } - } else if (Value.ExpressionOpcode == GenericConstantExpressionOpcode::GetElementPtr) { - while (true) { - if (consumeWord("inbounds")) { - Value.ExpressionFlags.set(GenericConstantExpressionFlag::InBounds); - continue; - } - if (consumeWord("nusw")) { - Value.ExpressionFlags.set(GenericConstantExpressionFlag::NoUnsignedSignedWrap); - continue; - } - if (consumeWord("nuw")) { - Value.ExpressionFlags.set(GenericConstantExpressionFlag::GEPNoUnsignedWrap); - continue; - } - break; - } - if (consumeWord("inrange")) { - if (auto Open = expect('(', "'(' after inrange"); !Open) - return std::unexpected(Open.error()); - auto StartToken = parseValueToken(); - if (!StartToken) - return std::unexpected(StartToken.error()); - auto Start = APInt::parseDecimal(64, *StartToken); - if (!Start) - return fail("invalid inrange start"); - if (auto Comma = expect(',', "',' in inrange interval"); !Comma) - return std::unexpected(Comma.error()); - auto EndToken = parseValueToken(); - if (!EndToken) - return std::unexpected(EndToken.error()); - auto End = APInt::parseDecimal(64, *EndToken); - if (!End) - return fail("invalid inrange end"); - if (auto Close = expect(')', "')' after inrange interval"); !Close) - return std::unexpected(Close.error()); - Value.InRangeStart = std::move(*Start); - Value.InRangeEnd = std::move(*End); - } - } - - if (auto Open = expect('(', "'(' after constant-expression opcode"); !Open) - return std::unexpected(Open.error()); - if (Value.ExpressionOpcode == GenericConstantExpressionOpcode::GetElementPtr) { - auto SourceType = parseType(Depth + 1); - if (!SourceType) - return std::unexpected(SourceType.error()); - Value.SourceElementType = std::move(*SourceType); - if (auto Comma = expect(',', "',' after getelementptr source type"); !Comma) - return std::unexpected(Comma.error()); - } - - auto First = parseTypedValue(Depth + 1); - if (!First) - return std::unexpected(First.error()); - Value.Elements.push_back(std::move(*First)); - if (IsCast) { - if (auto To = expectWord("to"); !To) - return std::unexpected(To.error()); - auto Destination = parseType(Depth + 1); - if (!Destination) - return std::unexpected(Destination.error()); - if (*Destination != Value.Type) - return fail("constant-expression destination type does not match value"); - } else { - while (consume(',')) { - auto Operand = parseTypedValue(Depth + 1); - if (!Operand) - return std::unexpected(Operand.error()); - Value.Elements.push_back(std::move(*Operand)); - } - } - if (auto Close = expect(')', "')' after constant expression"); !Close) - return std::unexpected(Close.error()); - - const std::size_t RequiredOperands = [&]() -> std::size_t { - switch (Value.ExpressionOpcode) { - case GenericConstantExpressionOpcode::Trunc: - case GenericConstantExpressionOpcode::BitCast: - case GenericConstantExpressionOpcode::AddressSpaceCast: - case GenericConstantExpressionOpcode::IntToPtr: - case GenericConstantExpressionOpcode::PtrToAddr: - case GenericConstantExpressionOpcode::PtrToInt: - case GenericConstantExpressionOpcode::Splat: - return 1; - case GenericConstantExpressionOpcode::Add: - case GenericConstantExpressionOpcode::Sub: - case GenericConstantExpressionOpcode::Xor: - case GenericConstantExpressionOpcode::ExtractElement: - return 2; - case GenericConstantExpressionOpcode::ShuffleVector: - case GenericConstantExpressionOpcode::InsertElement: - return 3; - case GenericConstantExpressionOpcode::GetElementPtr: - return 1; - case GenericConstantExpressionOpcode::Invalid: - return 0; - } - return 0; - }(); - if (Value.ExpressionOpcode == GenericConstantExpressionOpcode::GetElementPtr) { - if (Value.Elements.empty() || - resolvedType(Value.Elements.front().Type).Kind != GenericConstantTypeKind::Pointer || - resolvedType(Value.Type).Kind != GenericConstantTypeKind::Pointer) { - return fail("getelementptr constant has no base pointer"); - } - } else if (Value.Elements.size() != RequiredOperands) { - return fail("constant expression has the wrong operand count"); - } - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; -} - -Expected ConstantParser::parseValue(GenericConstantType Type, - std::size_t Depth) { - if (auto Limit = accountNode(Depth); !Limit) - return std::unexpected(Limit.error()); - skipSpace(); - - const auto Marker = [&](GenericConstantKind Kind) -> Expected { - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = Kind; - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; - }; - if (consumeWord("zeroinitializer")) - return Marker(GenericConstantKind::ZeroInitializer); - if (consumeWord("undef")) - return Marker(GenericConstantKind::Undef); - if (consumeWord("poison")) - return Marker(GenericConstantKind::Poison); - if (consumeWord("null")) - return Marker(GenericConstantKind::NullPointer); - - const GenericConstantType &EffectiveType = resolvedType(Type); - - if (consumeWord("c")) { - auto Bytes = parseByteString(); - if (!Bytes) - return std::unexpected(Bytes.error()); - return GenericConstantData::byteString(std::move(Type), std::move(*Bytes)); - } - - if (EffectiveType.Kind == GenericConstantTypeKind::Array) - return parseAggregate(std::move(Type), '[', ']', false, Depth + 1); - if (EffectiveType.Kind == GenericConstantTypeKind::Struct) - return parseAggregate(std::move(Type), EffectiveType.Packed ? '<' : '{', '}', - EffectiveType.Packed, Depth + 1); - if (EffectiveType.Kind == GenericConstantTypeKind::Vector) { - if (consumeWord("splat")) - return parseExpression(std::move(Type), "splat", Depth + 1); - skipSpace(); - if (Position < Text.size() && Text[Position] == '<') - return parseAggregate(std::move(Type), '<', '>', false, Depth + 1); - } - - skipSpace(); - if (Position < Text.size() && Text[Position] == '@') { - auto Name = parseName('@'); - if (!Name) - return std::unexpected(Name.error()); - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::GlobalAddress; - Value.Symbol = std::move(Name->Value); - Value.NumericSymbol = Name->Numeric; - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; - } - - if (consumeWord("blockaddress")) { - if (auto Open = expect('(', "'(' after blockaddress"); !Open) - return std::unexpected(Open.error()); - auto Function = parseName('@'); - if (!Function) - return std::unexpected(Function.error()); - if (auto Comma = expect(',', "',' in blockaddress"); !Comma) - return std::unexpected(Comma.error()); - auto Block = parseName('%'); - if (!Block) - return std::unexpected(Block.error()); - if (auto Close = expect(')', "')' after blockaddress"); !Close) - return std::unexpected(Close.error()); - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::BlockAddress; - Value.Symbol = std::move(Function->Value); - Value.NumericSymbol = Function->Numeric; - Value.Block = std::move(Block->Value); - Value.NumericBlock = Block->Numeric; - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; - } - - for (const auto &[Keyword, Kind] : - {std::pair{std::string_view{"dso_local_equivalent"}, - GenericConstantKind::DSOLocalEquivalent}, - std::pair{std::string_view{"no_cfi"}, GenericConstantKind::NoCFI}}) { - if (!consumeWord(Keyword)) - continue; - auto Name = parseName('@'); - if (!Name) - return std::unexpected(Name.error()); - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = Kind; - Value.Symbol = std::move(Name->Value); - Value.NumericSymbol = Name->Numeric; - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; - } - - if (consumeWord("ptrauth")) { - if (auto Open = expect('(', "'(' after ptrauth"); !Open) - return std::unexpected(Open.error()); - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::PointerAuth; - while (true) { - auto Operand = parseTypedValue(Depth + 1); - if (!Operand) - return std::unexpected(Operand.error()); - Value.Elements.push_back(std::move(*Operand)); - if (consume(')')) - break; - if (auto Comma = expect(',', "',' in ptrauth constant"); !Comma) - return std::unexpected(Comma.error()); - } - auto Verification = Value.verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; - } - - const auto Word = peekWord(); - if (Word) { - constexpr std::array ExpressionNames{ - std::string_view{"trunc"}, - std::string_view{"bitcast"}, - std::string_view{"addrspacecast"}, - std::string_view{"inttoptr"}, - std::string_view{"ptrtoaddr"}, - std::string_view{"ptrtoint"}, - std::string_view{"add"}, - std::string_view{"sub"}, - std::string_view{"xor"}, - std::string_view{"getelementptr"}, - std::string_view{"shufflevector"}, - std::string_view{"insertelement"}, - std::string_view{"extractelement"}, - }; - if (std::ranges::find(ExpressionNames, *Word) != ExpressionNames.end()) { - Position += Word->size(); - return parseExpression(std::move(Type), *Word, Depth + 1); - } - } - - if (EffectiveType.Kind == GenericConstantTypeKind::Floating) - return parseFloatingValue(std::move(Type), Depth + 1); - if (EffectiveType.Kind == GenericConstantTypeKind::Integer || - EffectiveType.Kind == GenericConstantTypeKind::Byte) { - auto Token = parseValueToken(); - if (!Token) - return std::unexpected(Token.error()); - std::string_view Spelling = *Token; - if (Spelling == "true") - Spelling = "1"; - else if (Spelling == "false") - Spelling = "0"; - const std::uint32_t BitWidth = - EffectiveType.Kind == GenericConstantTypeKind::Byte ? 8U : EffectiveType.BitWidth; - const bool IsExplicitHex = Spelling.starts_with("u0x") || Spelling.starts_with("s0x"); - auto Integer = IsExplicitHex ? APInt::parseLLVMHex(BitWidth, Spelling) - : APInt::parseDecimal(BitWidth, Spelling); - if (!Integer) - return fail(Integer.error().message()); - GenericConstantData Value; - Value.Type = std::move(Type); - Value.Kind = GenericConstantKind::Integer; - Value.IntegerValue = std::move(*Integer); - return Value; - } - return fail("constant value is not valid for its LLVM IR type"); -} - -Expected ConstantParser::parse() { - if (Text.empty()) - return fail("constant text is empty"); - auto Value = parseTypedValue(0); - if (!Value) - return Value; - if (!atEnd()) - return fail("unexpected trailing text"); - auto Verification = Value->verify(); - if (!Verification) - return fail(Verification.error().message()); - return Value; -} - -Expected ConstantParser::parseTypeOnly() { - if (Text.empty()) - return fail("type text is empty"); - auto Type = parseType(0); - if (!Type) - return Type; - if (!atEnd()) - return fail("unexpected trailing text after LLVM type"); - auto Verification = Type->verify(); - if (!Verification) - return fail(Verification.error().message()); - return Type; -} - -[[nodiscard]] bool canUseBareName(std::string_view Name) noexcept { - if (Name.empty() || !isIdentifierStart(Name.front())) - return false; - return std::ranges::all_of(Name.substr(1), isIdentifierBody); -} - -[[nodiscard]] std::string printName(char Prefix, std::string_view Name, bool Numeric) { - std::string Result(1, Prefix); - if (Numeric || canUseBareName(Name)) { - Result.append(Name); - return Result; - } - static constexpr std::string_view HexDigits = "0123456789ABCDEF"; - Result.push_back('"'); - for (const char RawCharacter : Name) { - const auto Character = static_cast(RawCharacter); - if (Character >= 0x20U && Character <= 0x7eU && Character != '"' && Character != '\\') { - Result.push_back(static_cast(Character)); - continue; - } - Result.push_back('\\'); - Result.push_back(HexDigits[Character >> 4U]); - Result.push_back(HexDigits[Character & 0xfU]); - } - Result.push_back('"'); - return Result; -} - -[[nodiscard]] Expected printType(const GenericConstantType &Type); - -[[nodiscard]] Expected printTypeList(std::span Types, - std::string_view Open, std::string_view Close) { - std::string Result(Open); - for (std::size_t Index = 0; Index < Types.size(); ++Index) { - if (Index != 0) - Result.append(", "); - auto Element = printType(Types[Index]); - if (!Element) - return std::unexpected(Element.error()); - Result.append(*Element); - } - Result.append(Close); - return Result; -} - -Expected printType(const GenericConstantType &Type) { - auto Verification = Type.verify(); - if (!Verification) - return std::unexpected(Verification.error()); - switch (Type.Kind) { - case GenericConstantTypeKind::Invalid: - break; - case GenericConstantTypeKind::Void: - return std::string("void"); - case GenericConstantTypeKind::Label: - return std::string("label"); - case GenericConstantTypeKind::Token: - return std::string("token"); - case GenericConstantTypeKind::Metadata: - return std::string("metadata"); - case GenericConstantTypeKind::Integer: - return "i" + std::to_string(Type.BitWidth); - case GenericConstantTypeKind::Byte: - return std::string("byte"); - case GenericConstantTypeKind::Floating: - switch (Type.Semantics) { - case FloatSemantics::IEEEHalf: - return std::string("half"); - case FloatSemantics::BFloat: - return std::string("bfloat"); - case FloatSemantics::IEEESingle: - return std::string("float"); - case FloatSemantics::IEEEDouble: - return std::string("double"); - case FloatSemantics::IEEEQuad: - return std::string("fp128"); - case FloatSemantics::PPCDoubleDouble: - return std::string("ppc_fp128"); - case FloatSemantics::X87DoubleExtended: - return std::string("x86_fp80"); - default: - return makeUnexpected(ErrorCode::Unsupported, - "floating semantics has no LLVM IR type spelling"); - } - case GenericConstantTypeKind::Pointer: - if (Type.AddressSpace == 0) - return std::string("ptr"); - return "ptr addrspace(" + std::to_string(Type.AddressSpace) + ")"; - case GenericConstantTypeKind::Array: { - auto Element = printType(Type.Elements.front()); - if (!Element) - return std::unexpected(Element.error()); - return "[" + std::to_string(Type.ElementCount) + " x " + *Element + "]"; - } - case GenericConstantTypeKind::Vector: { - auto Element = printType(Type.Elements.front()); - if (!Element) - return std::unexpected(Element.error()); - std::string Result = "<"; - if (Type.Scalable) - Result.append("vscale x "); - Result.append(std::to_string(Type.ElementCount)); - Result.append(" x "); - Result.append(*Element); - Result.push_back('>'); - return Result; - } - case GenericConstantTypeKind::Struct: - return printTypeList(Type.Elements, Type.Packed ? "<{ " : "{ ", Type.Packed ? " }>" : " }"); - case GenericConstantTypeKind::Function: { - auto Return = printType(Type.Elements.front()); - if (!Return) - return std::unexpected(Return.error()); - std::string Result = *Return + " ("; - for (std::size_t Index = 1; Index < Type.Elements.size(); ++Index) { - if (Index != 1) - Result.append(", "); - auto Parameter = printType(Type.Elements[Index]); - if (!Parameter) - return std::unexpected(Parameter.error()); - Result.append(*Parameter); - } - if (Type.VarArg) { - if (Type.Elements.size() != 1) - Result.append(", "); - Result.append("..."); - } - Result.push_back(')'); - return Result; - } - case GenericConstantTypeKind::Named: - return printName('%', Type.Name, Type.NumericName); - } - return makeUnexpected(ErrorCode::VerificationError, "generic constant type is invalid"); -} - -[[nodiscard]] std::string_view -expressionOpcodeName(GenericConstantExpressionOpcode Opcode) noexcept { - switch (Opcode) { - case GenericConstantExpressionOpcode::Trunc: - return "trunc"; - case GenericConstantExpressionOpcode::BitCast: - return "bitcast"; - case GenericConstantExpressionOpcode::AddressSpaceCast: - return "addrspacecast"; - case GenericConstantExpressionOpcode::IntToPtr: - return "inttoptr"; - case GenericConstantExpressionOpcode::PtrToAddr: - return "ptrtoaddr"; - case GenericConstantExpressionOpcode::PtrToInt: - return "ptrtoint"; - case GenericConstantExpressionOpcode::Add: - return "add"; - case GenericConstantExpressionOpcode::Sub: - return "sub"; - case GenericConstantExpressionOpcode::Xor: - return "xor"; - case GenericConstantExpressionOpcode::GetElementPtr: - return "getelementptr"; - case GenericConstantExpressionOpcode::ShuffleVector: - return "shufflevector"; - case GenericConstantExpressionOpcode::InsertElement: - return "insertelement"; - case GenericConstantExpressionOpcode::ExtractElement: - return "extractelement"; - case GenericConstantExpressionOpcode::Splat: - return "splat"; - case GenericConstantExpressionOpcode::Invalid: - return {}; - } - return {}; -} - -[[nodiscard]] Expected printValue(const GenericConstantData &Value, bool IncludeType); - -[[nodiscard]] Expected appendTypedOperands(std::string &Output, - std::span Operands) { - for (std::size_t Index = 0; Index < Operands.size(); ++Index) { - if (Index != 0) - Output.append(", "); - auto Operand = printValue(Operands[Index], true); - if (!Operand) - return std::unexpected(Operand.error()); - Output.append(*Operand); - } - return {}; -} - -Expected printValue(const GenericConstantData &Value, bool IncludeType) { - auto Verification = Value.verify(); - if (!Verification) - return std::unexpected(Verification.error()); - std::string Result; - if (IncludeType) { - auto Type = printType(Value.Type); - if (!Type) - return std::unexpected(Type.error()); - Result.append(*Type); - Result.push_back(' '); - } - - switch (Value.Kind) { - case GenericConstantKind::Invalid: - break; - case GenericConstantKind::Integer: - if (!Value.IntegerValue) - return makeUnexpected(ErrorCode::VerificationError, - "integer constant is missing its integer payload"); - if (resolvedType(Value.Type).Kind == GenericConstantTypeKind::Integer && - resolvedType(Value.Type).BitWidth == 1) - Result.append(Value.IntegerValue.value().isZero() ? "false" : "true"); - else - Result.append(Value.IntegerValue.value().toUnsignedDecimal()); - return Result; - case GenericConstantKind::Floating: - if (!Value.FloatingValue) - return makeUnexpected(ErrorCode::VerificationError, - "floating constant is missing its floating payload"); - Result.append(Value.FloatingValue->toString()); - return Result; - case GenericConstantKind::NullPointer: - Result.append("null"); - return Result; - case GenericConstantKind::ZeroInitializer: - Result.append("zeroinitializer"); - return Result; - case GenericConstantKind::Undef: - Result.append("undef"); - return Result; - case GenericConstantKind::Poison: - Result.append("poison"); - return Result; - case GenericConstantKind::Aggregate: { - const GenericConstantType &EffectiveType = resolvedType(Value.Type); - const bool Packed = - EffectiveType.Kind == GenericConstantTypeKind::Struct && EffectiveType.Packed; - Result.append(Packed ? "<{ " - : EffectiveType.Kind == GenericConstantTypeKind::Array ? "[ " - : EffectiveType.Kind == GenericConstantTypeKind::Struct ? "{ " - : "< "); - auto Appended = appendTypedOperands(Result, Value.Elements); - if (!Appended) - return std::unexpected(Appended.error()); - Result.append(Packed ? " }>" - : EffectiveType.Kind == GenericConstantTypeKind::Array ? " ]" - : EffectiveType.Kind == GenericConstantTypeKind::Struct ? " }" - : " >"); - return Result; - } - case GenericConstantKind::ByteString: { - static constexpr std::string_view Digits = "0123456789ABCDEF"; - Result.append("c\""); - for (const std::byte Byte : Value.ByteValue) { - const unsigned Character = std::to_integer(Byte); - if (Character >= 0x20U && Character <= 0x7eU && Character != '"' && Character != '\\') { - Result.push_back(static_cast(Character)); - } else { - Result.push_back('\\'); - Result.push_back(Digits[Character >> 4U]); - Result.push_back(Digits[Character & 0xfU]); - } - } - Result.push_back('"'); - return Result; - } - case GenericConstantKind::GlobalAddress: - Result.append(printName('@', Value.Symbol, Value.NumericSymbol)); - return Result; - case GenericConstantKind::BlockAddress: - Result.append("blockaddress("); - Result.append(printName('@', Value.Symbol, Value.NumericSymbol)); - Result.append(", "); - Result.append(printName('%', Value.Block, Value.NumericBlock)); - Result.push_back(')'); - return Result; - case GenericConstantKind::DSOLocalEquivalent: - Result.append("dso_local_equivalent "); - Result.append(printName('@', Value.Symbol, Value.NumericSymbol)); - return Result; - case GenericConstantKind::NoCFI: - Result.append("no_cfi "); - Result.append(printName('@', Value.Symbol, Value.NumericSymbol)); - return Result; - case GenericConstantKind::PointerAuth: - Result.append("ptrauth ("); - if (auto Appended = appendTypedOperands(Result, Value.Elements); !Appended) - return std::unexpected(Appended.error()); - Result.push_back(')'); - return Result; - case GenericConstantKind::Expression: { - const std::string_view Opcode = expressionOpcodeName(Value.ExpressionOpcode); - if (Opcode.empty()) - return makeUnexpected(ErrorCode::VerificationError, - "constant expression has an invalid opcode"); - Result.append(Opcode); - if (Value.ExpressionFlags.has(GenericConstantExpressionFlag::InBounds)) - Result.append(" inbounds"); - if (Value.ExpressionFlags.has(GenericConstantExpressionFlag::NoUnsignedSignedWrap)) - Result.append(" nusw"); - if (Value.ExpressionFlags.has(GenericConstantExpressionFlag::GEPNoUnsignedWrap) || - Value.ExpressionFlags.has(GenericConstantExpressionFlag::NoUnsignedWrap)) - Result.append(" nuw"); - if (Value.ExpressionFlags.has(GenericConstantExpressionFlag::NoSignedWrap)) - Result.append(" nsw"); - if (Value.InRangeStart) { - if (!Value.InRangeEnd) { - return makeUnexpected(ErrorCode::VerificationError, - "constant expression is missing its inrange end"); - } - const auto &InRangeStart = Value.InRangeStart.value(); - const auto &InRangeEnd = Value.InRangeEnd.value(); - Result.append(" inrange("); - Result.append(std::to_string(std::bit_cast(InRangeStart.words()[0]))); - Result.append(", "); - Result.append(std::to_string(std::bit_cast(InRangeEnd.words()[0]))); - Result.push_back(')'); - } - Result.append(" ("); - if (Value.ExpressionOpcode == GenericConstantExpressionOpcode::GetElementPtr) { - if (!Value.SourceElementType) { - return makeUnexpected(ErrorCode::VerificationError, - "getelementptr constant is missing its source element type"); - } - auto SourceType = printType(Value.SourceElementType.value()); - if (!SourceType) - return std::unexpected(SourceType.error()); - Result.append(*SourceType); - Result.append(", "); - } - auto First = printValue(Value.Elements.front(), true); - if (!First) - return std::unexpected(First.error()); - Result.append(*First); - const bool IsCast = - Value.ExpressionOpcode == GenericConstantExpressionOpcode::Trunc || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::BitCast || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::AddressSpaceCast || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::IntToPtr || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::PtrToAddr || - Value.ExpressionOpcode == GenericConstantExpressionOpcode::PtrToInt; - if (IsCast) { - auto Destination = printType(Value.Type); - if (!Destination) - return std::unexpected(Destination.error()); - Result.append(" to "); - Result.append(*Destination); - } else { - for (std::size_t Index = 1; Index < Value.Elements.size(); ++Index) { - Result.append(", "); - auto Operand = printValue(Value.Elements[Index], true); - if (!Operand) - return std::unexpected(Operand.error()); - Result.append(*Operand); - } - } - Result.push_back(')'); - return Result; - } - } - return makeUnexpected(ErrorCode::VerificationError, "generic constant value is invalid"); -} - -struct LayoutAlignment final { - std::uint64_t ABI = 1; - std::uint64_t Preferred = 1; -}; - -struct LayoutAlignmentEntry final { - char Kind = '\0'; - std::uint32_t BitWidth = 0; - LayoutAlignment Alignment; -}; - -struct LayoutPointerEntry final { - std::uint32_t AddressSpace = 0; - std::uint32_t SizeInBits = 0; - std::uint32_t IndexSizeInBits = 0; - LayoutAlignment Alignment; - bool HasExternalState = false; - bool HasUnstableRepresentation = false; - bool NullIsAllOnes = false; - std::string AddressSpaceName; -}; - -constexpr std::uint64_t MaximumDataLayoutSize = (std::uint64_t{1} << 24U) - 1U; -constexpr std::uint64_t MaximumDataLayoutAlignment = (std::uint64_t{1} << 16U) - 1U; - -class DataLayoutInfo final { -public: - [[nodiscard]] static Expected parse(LLVMConstantSyntaxOptions Options); - - [[nodiscard]] bool isExplicit() const noexcept { - return Explicit; - } - - [[nodiscard]] Expected pointer(std::uint32_t AddressSpace) const; - [[nodiscard]] LayoutAlignment integer(std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept; - [[nodiscard]] LayoutAlignment floating(std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept; - [[nodiscard]] LayoutAlignment vector(std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept; - - [[nodiscard]] LayoutAlignment aggregate() const noexcept { - return Aggregate; - } - -private: - [[nodiscard]] static Expected parseUnsignedField(std::string_view Text, - std::string_view Description); - [[nodiscard]] static Expected alignmentBytes(std::string_view Text, bool AllowZero, - std::string_view Description); - [[nodiscard]] static std::vector split(std::string_view Text, char Separator); - - void setAlignment(LayoutAlignmentEntry Entry); - void setPointer(LayoutPointerEntry Entry); - [[nodiscard]] LayoutAlignment natural(std::uint64_t StoreSize) const noexcept; - [[nodiscard]] LayoutAlignment scalarAlignment(char Kind, std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept; - - bool Explicit = false; - std::vector Alignments; - std::vector Pointers; - LayoutAlignment Aggregate{1, 8}; -}; - -Expected DataLayoutInfo::parseUnsignedField(std::string_view Text, - std::string_view Description) { - std::uint64_t Value = 0; - const auto Parsed = std::from_chars(Text.data(), Text.data() + Text.size(), Value, 10); - if (Text.empty() || Parsed.ec != std::errc{} || Parsed.ptr != Text.data() + Text.size()) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM data layout has an invalid " + std::string(Description)); - } - return Value; -} - -Expected DataLayoutInfo::alignmentBytes(std::string_view Text, bool AllowZero, - std::string_view Description) { - auto Bits = parseUnsignedField(Text, Description); - if (!Bits) - return std::unexpected(Bits.error()); - if (*Bits == 0 && AllowZero) - return 1; - if (*Bits > MaximumDataLayoutAlignment || *Bits < 8 || (*Bits % 8U) != 0 || - !std::has_single_bit(*Bits)) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM data layout " + std::string(Description) + - " must be a nonzero power-of-two byte alignment"); - } - return *Bits / 8U; -} - -std::vector DataLayoutInfo::split(std::string_view Text, char Separator) { - std::vector Parts; - while (true) { - const std::size_t Position = Text.find(Separator); - Parts.push_back(Text.substr(0, Position)); - if (Position == std::string_view::npos) - return Parts; - Text.remove_prefix(Position + 1U); - } -} - -void DataLayoutInfo::setAlignment(LayoutAlignmentEntry Entry) { - const auto Existing = - std::ranges::find_if(Alignments, [&Entry](const LayoutAlignmentEntry &Candidate) { - return Candidate.Kind == Entry.Kind && Candidate.BitWidth == Entry.BitWidth; - }); - if (Existing == Alignments.end()) - Alignments.push_back(Entry); - else - *Existing = Entry; -} - -void DataLayoutInfo::setPointer(LayoutPointerEntry Entry) { - const auto Existing = - std::ranges::find_if(Pointers, [&Entry](const LayoutPointerEntry &Candidate) { - return Candidate.AddressSpace == Entry.AddressSpace; - }); - if (Existing == Pointers.end()) - Pointers.push_back(Entry); - else - *Existing = Entry; -} - -Expected DataLayoutInfo::parse(LLVMConstantSyntaxOptions Options) { - DataLayoutInfo Result; - if (Options.DataLayout.empty()) - return Result; - if (Options.DataLayout.size() > Options.MaximumTokenLength) { - return makeUnexpected(ErrorCode::Unsupported, - "LLVM data layout exceeds the configured token length limit"); - } - Result.Explicit = true; - Result.setPointer({.AddressSpace = 0, - .SizeInBits = 64, - .IndexSizeInBits = 64, - .Alignment = {.ABI = 8, .Preferred = 8}, - .HasExternalState = false, - .HasUnstableRepresentation = false, - .NullIsAllOnes = false, - .AddressSpaceName = {}}); - for (const LayoutAlignmentEntry Entry : { - LayoutAlignmentEntry{'i', 1, {1, 1}}, - LayoutAlignmentEntry{'i', 8, {1, 1}}, - LayoutAlignmentEntry{'i', 16, {2, 2}}, - LayoutAlignmentEntry{'i', 32, {4, 4}}, - LayoutAlignmentEntry{'i', 64, {4, 8}}, - LayoutAlignmentEntry{'f', 16, {2, 2}}, - LayoutAlignmentEntry{'f', 32, {4, 4}}, - LayoutAlignmentEntry{'f', 64, {8, 8}}, - LayoutAlignmentEntry{'f', 128, {16, 16}}, - LayoutAlignmentEntry{'v', 64, {8, 8}}, - LayoutAlignmentEntry{'v', 128, {16, 16}}, - }) { - Result.setAlignment(Entry); - } - - for (const std::string_view Component : split(Options.DataLayout, '-')) { - if (Component.empty()) - return makeUnexpected(ErrorCode::ParseError, "LLVM data layout contains an empty component"); - if (Component.front() == 'p') { - const std::size_t Colon = Component.find(':'); - if (Colon == std::string_view::npos) - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer data layout component has no size"); - std::string_view AddressSpaceText = Component.substr(1, Colon - 1U); - bool HasExternalState = false; - bool HasUnstableRepresentation = false; - bool NullIsAllOnes = false; - bool HasExplicitNullValue = false; - while (!AddressSpaceText.empty()) { - const char Flag = AddressSpaceText.front(); - if (Flag == 'e') { - HasExternalState = true; - } else if (Flag == 'u') { - HasUnstableRepresentation = true; - } else if (Flag == 'z' || Flag == 'o') { - if (HasExplicitNullValue) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer data layout has conflicting null-pointer flags"); - } - HasExplicitNullValue = true; - NullIsAllOnes = Flag == 'o'; - } else { - break; - } - AddressSpaceText.remove_prefix(1); - } - - std::uint64_t AddressSpace = 0; - std::string AddressSpaceName; - if (!AddressSpaceText.empty()) { - std::size_t NumberLength = 0; - while (NumberLength < AddressSpaceText.size() && AddressSpaceText[NumberLength] >= '0' && - AddressSpaceText[NumberLength] <= '9') { - ++NumberLength; - } - if (NumberLength != 0) { - auto Parsed = - parseUnsignedField(AddressSpaceText.substr(0, NumberLength), "pointer address space"); - if (!Parsed) - return std::unexpected(Parsed.error()); - AddressSpace = *Parsed; - AddressSpaceText.remove_prefix(NumberLength); - } - if (!AddressSpaceText.empty()) { - if (AddressSpaceText.size() <= 2 || AddressSpaceText.front() != '(' || - AddressSpaceText.back() != ')') { - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer address space or name is invalid"); - } - AddressSpaceName = std::string(AddressSpaceText.substr(1, AddressSpaceText.size() - 2)); - if (AddressSpaceName.size() == 1 && - (AddressSpaceName.front() == 'P' || AddressSpaceName.front() == 'G' || - AddressSpaceName.front() == 'A')) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer address space uses a reserved name"); - } - } - } - if (AddressSpace == 0 && (HasExternalState || HasUnstableRepresentation)) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM address space zero cannot be unstable or external"); - } - if (!AddressSpaceName.empty() && - std::ranges::any_of(Result.Pointers, - [&AddressSpaceName](const LayoutPointerEntry &Entry) { - return Entry.AddressSpaceName == AddressSpaceName; - })) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer address-space name is duplicated"); - } - const auto Fields = split(Component.substr(Colon + 1U), ':'); - if (Fields.size() < 2 || Fields.size() > 4 || AddressSpace > MaximumDataLayoutSize) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer data layout component has invalid fields"); - } - auto Size = parseUnsignedField(Fields[0], "pointer size"); - auto ABI = alignmentBytes(Fields[1], false, "pointer ABI alignment"); - auto Preferred = Fields.size() >= 3 - ? alignmentBytes(Fields[2], false, "pointer preferred alignment") - : ABI; - if (!Size || !ABI || !Preferred || *Size == 0 || *Size > MaximumDataLayoutSize || - *Preferred < *ABI) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM pointer data layout component is invalid"); - } - std::uint64_t IndexSize = *Size; - if (Fields.size() == 4) { - auto ParsedIndexSize = parseUnsignedField(Fields[3], "pointer index size"); - if (!ParsedIndexSize || *ParsedIndexSize == 0 || *ParsedIndexSize > MaximumDataLayoutSize || - *ParsedIndexSize > *Size) { - return makeUnexpected(ErrorCode::ParseError, "LLVM pointer index size is invalid"); - } - IndexSize = *ParsedIndexSize; - } - Result.setPointer({.AddressSpace = static_cast(AddressSpace), - .SizeInBits = static_cast(*Size), - .IndexSizeInBits = static_cast(IndexSize), - .Alignment = {.ABI = *ABI, .Preferred = *Preferred}, - .HasExternalState = HasExternalState, - .HasUnstableRepresentation = HasUnstableRepresentation, - .NullIsAllOnes = NullIsAllOnes, - .AddressSpaceName = std::move(AddressSpaceName)}); - continue; - } - - if (Component == "ve") - continue; - - if (Component.front() == 'i' || Component.front() == 'f' || Component.front() == 'v') { - const std::size_t Colon = Component.find(':'); - if (Colon == std::string_view::npos) - return makeUnexpected(ErrorCode::ParseError, - "LLVM scalar data layout component has no alignment"); - auto Width = parseUnsignedField(Component.substr(1, Colon - 1U), "type alignment bit width"); - const auto Fields = split(Component.substr(Colon + 1U), ':'); - if (!Width || *Width == 0 || *Width > MaximumDataLayoutSize || Fields.empty() || - Fields.size() > 2) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM scalar data layout component has invalid fields"); - } - auto ABI = alignmentBytes(Fields[0], false, "type ABI alignment"); - auto Preferred = - Fields.size() == 2 ? alignmentBytes(Fields[1], false, "type preferred alignment") : ABI; - if (!ABI || !Preferred || *Preferred < *ABI) - return makeUnexpected(ErrorCode::ParseError, - "LLVM scalar data layout alignment is invalid"); - Result.setAlignment( - {Component.front(), static_cast(*Width), {*ABI, *Preferred}}); - continue; - } - - if (Component.starts_with('a')) { - const auto Fields = split(Component.substr(1), ':'); - if (Fields.size() < 2 || Fields.size() > 3 || (!Fields[0].empty() && Fields[0] != "0")) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM aggregate data layout component has invalid fields"); - } - auto ABI = alignmentBytes(Fields[1], true, "aggregate ABI alignment"); - auto Preferred = Fields.size() == 3 - ? alignmentBytes(Fields[2], false, "aggregate preferred alignment") - : ABI; - if (!ABI || !Preferred || *Preferred < *ABI) - return makeUnexpected(ErrorCode::ParseError, - "LLVM aggregate data layout alignment is invalid"); - Result.Aggregate = {.ABI = *ABI, .Preferred = *Preferred}; - continue; - } - - if (Component == "e" || Component == "E" || Component == "s" || Component == "ve") - continue; - - if (Component.starts_with("ni:")) { - const auto AddressSpaces = split(Component.substr(3), ':'); - if (AddressSpaces.empty()) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM non-integral address-space component is empty"); - } - for (const std::string_view AddressSpace : AddressSpaces) { - auto Parsed = parseUnsignedField(AddressSpace, "non-integral address space"); - if (!Parsed || *Parsed == 0 || *Parsed > MaximumDataLayoutSize) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM non-integral address space is invalid"); - } - } - continue; - } - - if (Component.starts_with("m:")) { - const std::string_view Mode = Component.substr(2); - if (Mode.size() != 1 || (Mode.front() != 'e' && Mode.front() != 'l' && Mode.front() != 'o' && - Mode.front() != 'm' && Mode.front() != 'w' && Mode.front() != 'x' && - Mode.front() != 'a')) { - return makeUnexpected(ErrorCode::ParseError, "LLVM mangling mode is invalid"); - } - continue; - } - - if (Component.starts_with('n')) { - const auto Widths = split(Component.substr(1), ':'); - if (Widths.empty()) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM native integer-width component is empty"); - } - for (const std::string_view Width : Widths) { - auto Parsed = parseUnsignedField(Width, "native integer bit width"); - if (!Parsed || *Parsed == 0 || *Parsed > MaximumDataLayoutSize) { - return makeUnexpected(ErrorCode::ParseError, "LLVM native integer bit width is invalid"); - } - } - continue; - } - - if (Component.starts_with('S')) { - auto AlignmentValue = alignmentBytes(Component.substr(1), false, "stack natural alignment"); - if (!AlignmentValue) - return std::unexpected(AlignmentValue.error()); - continue; - } - - if (Component.starts_with('F')) { - const std::string_view Rest = Component.substr(1); - if (Rest.size() < 2 || (Rest.front() != 'i' && Rest.front() != 'n')) { - return makeUnexpected(ErrorCode::ParseError, - "LLVM function-pointer alignment component is invalid"); - } - auto AlignmentValue = alignmentBytes(Rest.substr(1), false, "function-pointer ABI alignment"); - if (!AlignmentValue) - return std::unexpected(AlignmentValue.error()); - continue; - } - - if (Component.starts_with('P') || Component.starts_with('G') || Component.starts_with('A')) { - auto AddressSpace = parseUnsignedField(Component.substr(1), "default address space"); - if (!AddressSpace || *AddressSpace > MaximumDataLayoutSize) { - return makeUnexpected(ErrorCode::ParseError, "LLVM default address space is invalid"); - } - continue; - } - - return makeUnexpected(ErrorCode::ParseError, "unsupported LLVM data layout component '" + - std::string(Component) + "'"); - } - return Result; -} - -LayoutAlignment DataLayoutInfo::natural(std::uint64_t StoreSize) const noexcept { - if (StoreSize == 0) - return {1, 1}; - constexpr std::uint64_t MaximumPowerOfTwo = std::uint64_t{1} << 63U; - const std::uint64_t LimitedSize = - std::min(StoreSize, Explicit ? MaximumPowerOfTwo : 16U); - const std::uint64_t Alignment = std::bit_ceil(LimitedSize); - return {Alignment, Alignment}; -} - -LayoutAlignment DataLayoutInfo::scalarAlignment(char Kind, std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept { - if (!Explicit) - return natural(StoreSize); - const LayoutAlignmentEntry *Selected = nullptr; - for (const LayoutAlignmentEntry &Entry : Alignments) { - if (Entry.Kind != Kind) - continue; - if (Kind == 'i') { - const bool BetterMatch = - Selected == nullptr || - (Entry.BitWidth >= BitWidth && Entry.BitWidth < Selected->BitWidth) || - (Selected->BitWidth < BitWidth && Entry.BitWidth > Selected->BitWidth); - if (BetterMatch) - Selected = &Entry; - } else if (Entry.BitWidth == BitWidth) { - Selected = &Entry; - break; - } - } - return Selected == nullptr ? natural(StoreSize) : Selected->Alignment; -} - -LayoutAlignment DataLayoutInfo::integer(std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept { - return scalarAlignment('i', BitWidth, StoreSize); -} - -LayoutAlignment DataLayoutInfo::floating(std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept { - return scalarAlignment('f', BitWidth, StoreSize); -} - -LayoutAlignment DataLayoutInfo::vector(std::uint32_t BitWidth, - std::uint64_t StoreSize) const noexcept { - return scalarAlignment('v', BitWidth, StoreSize); -} - -Expected DataLayoutInfo::pointer(std::uint32_t AddressSpace) const { - if (!Explicit) { - return makeUnexpected(ErrorCode::InvalidArgument, - "pointer size is required to lay out pointer constants"); - } - auto Entry = std::ranges::find_if(Pointers, [AddressSpace](const LayoutPointerEntry &Candidate) { - return Candidate.AddressSpace == AddressSpace; - }); - if (Entry == Pointers.end()) { - Entry = std::ranges::find_if( - Pointers, [](const LayoutPointerEntry &Candidate) { return Candidate.AddressSpace == 0; }); - } - if (Entry == Pointers.end()) - return makeUnexpected(ErrorCode::InvalidArgument, "LLVM data layout has no pointer layout"); - return *Entry; -} - -struct TypeLayout final { - std::uint64_t StoreSize = 0; - std::uint64_t AllocationSize = 0; - std::uint64_t ABIAlignment = 1; - std::uint64_t PreferredAlignment = 1; -}; - -[[nodiscard]] Expected layoutType(const GenericConstantType &Type, - LLVMConstantSyntaxOptions Options, - const DataLayoutInfo &Layout, - std::vector &NamedTypeStack, - std::size_t Depth) { - if (Depth > Options.MaximumDepth) - return makeUnexpected(ErrorCode::Unsupported, "LLVM type exceeds the layout depth limit"); - auto Verification = Type.verify(); - if (!Verification) - return std::unexpected(Verification.error()); - - const auto ScalarLayout = [&Layout](std::uint64_t StoreSize, - LayoutAlignment TypeAlignment) -> Expected { - std::uint64_t AllocationSize = StoreSize; - if (Layout.isExplicit()) { - auto Aligned = alignTo(StoreSize, TypeAlignment.ABI); - if (!Aligned) - return std::unexpected(Aligned.error()); - AllocationSize = *Aligned; - } - return TypeLayout{StoreSize, AllocationSize, TypeAlignment.ABI, TypeAlignment.Preferred}; - }; - - switch (Type.Kind) { - case GenericConstantTypeKind::Integer: - case GenericConstantTypeKind::Byte: { - const std::uint32_t Bits = Type.Kind == GenericConstantTypeKind::Byte ? 8U : Type.BitWidth; - const std::uint64_t StoreSize = (static_cast(Bits) + 7U) / 8U; - return ScalarLayout(StoreSize, Layout.integer(Bits, StoreSize)); - } - case GenericConstantTypeKind::Floating: { - const std::uint32_t Bits = getFloatSemanticsBitWidth(Type.Semantics).value_or(0); - const std::uint64_t StoreSize = (static_cast(Bits) + 7U) / 8U; - return ScalarLayout(StoreSize, Layout.floating(Bits, StoreSize)); - } - case GenericConstantTypeKind::Pointer: { - auto Pointer = Layout.pointer(Type.AddressSpace); - if (!Pointer) - return std::unexpected(Pointer.error()); - const std::uint64_t StoreSize = (static_cast(Pointer->SizeInBits) + 7U) / 8U; - return ScalarLayout(StoreSize, Pointer->Alignment); - } - case GenericConstantTypeKind::Array: { - auto Element = layoutType(Type.Elements.front(), Options, Layout, NamedTypeStack, Depth + 1); - if (!Element) - return std::unexpected(Element.error()); - auto Stride = alignTo(Element->AllocationSize, Element->ABIAlignment); - if (!Stride) - return std::unexpected(Stride.error()); - auto Size = checkedMultiply(*Stride, Type.ElementCount, "LLVM array allocation size"); - if (!Size) - return std::unexpected(Size.error()); - return TypeLayout{*Size, *Size, Element->ABIAlignment, Element->PreferredAlignment}; - } - case GenericConstantTypeKind::Vector: { - if (Type.Scalable) - return makeUnexpected(ErrorCode::Unsupported, - "scalable vector has no fixed constant-pool size"); - const GenericConstantType &ElementType = resolvedType(Type.Elements.front()); - std::uint64_t ElementBits = 0; - if (ElementType.Kind == GenericConstantTypeKind::Integer) - ElementBits = ElementType.BitWidth; - else if (ElementType.Kind == GenericConstantTypeKind::Byte) - ElementBits = 8; - else if (ElementType.Kind == GenericConstantTypeKind::Floating) - ElementBits = getFloatSemanticsBitWidth(ElementType.Semantics).value_or(0); - else if (ElementType.Kind == GenericConstantTypeKind::Pointer) { - auto Pointer = Layout.pointer(ElementType.AddressSpace); - if (!Pointer) - return std::unexpected(Pointer.error()); - ElementBits = Pointer->SizeInBits; - } else { - return makeUnexpected(ErrorCode::Unsupported, - "LLVM vector element type has no fixed bit size"); - } - auto TotalBits = checkedMultiply(ElementBits, Type.ElementCount, "LLVM vector bit size"); - if (!TotalBits || *TotalBits > std::numeric_limits::max() - 7U) - return makeUnexpected(ErrorCode::Unsupported, "LLVM vector bit size is too large"); - const std::uint64_t StoreSize = (*TotalBits + 7U) / 8U; - return ScalarLayout(StoreSize, - Layout.vector(static_cast(std::min( - *TotalBits, std::numeric_limits::max())), - StoreSize)); - } - case GenericConstantTypeKind::Struct: { - if (Type.Packed) { - std::uint64_t Size = 0; - for (const GenericConstantType &MemberType : Type.Elements) { - auto Member = layoutType(MemberType, Options, Layout, NamedTypeStack, Depth + 1); - if (!Member) - return std::unexpected(Member.error()); - auto Next = checkedAdd(Size, Member->AllocationSize, "LLVM packed struct allocation size"); - if (!Next) - return std::unexpected(Next.error()); - Size = *Next; - } - return TypeLayout{Size, Size, 1, std::max(Layout.aggregate().Preferred, 1)}; - } - std::uint64_t Offset = 0; - std::uint64_t ABIAlignment = std::max(Layout.aggregate().ABI, 1); - for (const GenericConstantType &MemberType : Type.Elements) { - auto Member = layoutType(MemberType, Options, Layout, NamedTypeStack, Depth + 1); - if (!Member) - return std::unexpected(Member.error()); - auto AlignedOffset = alignTo(Offset, Member->ABIAlignment); - if (!AlignedOffset) - return std::unexpected(AlignedOffset.error()); - auto Next = checkedAdd(*AlignedOffset, Member->AllocationSize, "LLVM struct allocation size"); - if (!Next) - return std::unexpected(Next.error()); - Offset = *Next; - ABIAlignment = std::max(ABIAlignment, Member->ABIAlignment); - } - auto Size = alignTo(Offset, ABIAlignment); - if (!Size) - return std::unexpected(Size.error()); - return TypeLayout{*Size, *Size, ABIAlignment, - std::max(Layout.aggregate().Preferred, ABIAlignment)}; - } - case GenericConstantTypeKind::Named: { - if (std::ranges::find(NamedTypeStack, Type.Name) != NamedTypeStack.end()) { - return makeUnexpected(ErrorCode::Unsupported, - "named LLVM type definition is recursively unsized"); - } - NamedTypeStack.push_back(Type.Name); - Expected Result = - makeUnexpected(ErrorCode::Unsupported, "named LLVM type has no embedded type definition"); - if (Type.Elements.size() == 1) { - Result = layoutType(Type.Elements.front(), Options, Layout, NamedTypeStack, Depth + 1); - } else { - const auto Definition = std::ranges::find_if( - Options.NamedTypes, [&Type](const LLVMNamedTypeDefinition &Candidate) { - return Candidate.Name == Type.Name && Candidate.NumericName == Type.NumericName; - }); - if (Definition != Options.NamedTypes.end()) { - auto Resolved = parseLLVMType(Definition->Definition, Options); - if (!Resolved) - Result = std::unexpected(Resolved.error()); - else - Result = layoutType(*Resolved, Options, Layout, NamedTypeStack, Depth + 1); - } - } - NamedTypeStack.pop_back(); - return Result; - } - case GenericConstantTypeKind::Invalid: - case GenericConstantTypeKind::Void: - case GenericConstantTypeKind::Label: - case GenericConstantTypeKind::Token: - case GenericConstantTypeKind::Metadata: - case GenericConstantTypeKind::Function: - return makeUnexpected(ErrorCode::Unsupported, - "LLVM type is not sized for a machine constant pool"); - } - return makeUnexpected(ErrorCode::InternalError, "LLVM constant type layout is unhandled"); -} - -[[nodiscard]] Expected layoutType(const GenericConstantType &Type, - LLVMConstantSyntaxOptions Options) { - auto Layout = DataLayoutInfo::parse(Options); - if (!Layout) - return std::unexpected(Layout.error()); - std::vector NamedTypeStack; - return layoutType(Type, Options, *Layout, NamedTypeStack, 0); -} - -} // namespace - -Expected parseLLVMConstant(std::string_view Text, - LLVMConstantSyntaxOptions Options) { - if (Options.MaximumDepth == 0 || Options.MaximumNodes == 0 || Options.MaximumTokenLength == 0) { - return makeUnexpected(ErrorCode::InvalidArgument, - "LLVM constant parser limits must be nonzero"); - } - return ConstantParser(Text, Options).parse(); -} - -Expected parseLLVMType(std::string_view Text, - LLVMConstantSyntaxOptions Options) { - if (Options.MaximumDepth == 0 || Options.MaximumNodes == 0 || Options.MaximumTokenLength == 0) { - return makeUnexpected(ErrorCode::InvalidArgument, "LLVM type parser limits must be nonzero"); - } - return ConstantParser(Text, Options).parseTypeOnly(); -} - -Expected printLLVMConstant(const GenericConstantData &Constant) { - return printValue(Constant, true); -} - -Expected llvmConstantStorageSize(const GenericConstantType &Type, - LLVMConstantSyntaxOptions Options) { - auto Layout = layoutType(Type, Options); - if (!Layout) - return std::unexpected(Layout.error()); - return Layout->AllocationSize; -} - -Expected llvmConstantPreferredAlignment(const GenericConstantType &Type, - LLVMConstantSyntaxOptions Options) { - auto Layout = layoutType(Type, Options); - if (!Layout) - return std::unexpected(Layout.error()); - return Alignment::create(Layout->PreferredAlignment); -} - -Expected llvmPointerSizeInBits(std::uint32_t AddressSpace, - LLVMConstantSyntaxOptions Options) { - auto Layout = DataLayoutInfo::parse(Options); - if (!Layout) - return std::unexpected(Layout.error()); - auto Pointer = Layout->pointer(AddressSpace); - if (!Pointer) - return std::unexpected(Pointer.error()); - return Pointer->SizeInBits; -} - -} // namespace rcc::mir -- cgit v1.2.3