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/include/rcc/IR/Constants.h | 177 ++++++++++++++++++++++++++++++++++++ backend/include/rcc/IR/DataLayout.h | 82 +++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 backend/include/rcc/IR/Constants.h create mode 100644 backend/include/rcc/IR/DataLayout.h (limited to 'backend/include/rcc/IR') diff --git a/backend/include/rcc/IR/Constants.h b/backend/include/rcc/IR/Constants.h new file mode 100644 index 0000000..9f894f2 --- /dev/null +++ b/backend/include/rcc/IR/Constants.h @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_IR_CONSTANTS_H +#define RCC_IR_CONSTANTS_H + +#include "rcc/ADT/APFloat.h" +#include "rcc/ADT/APInt.h" +#include "rcc/Support/Error.h" + +#include +#include +#include +#include +#include + +namespace rcc { + +enum class GenericConstantTypeKind : std::uint8_t { + Invalid, + Void, + Label, + Token, + Metadata, + Integer, + Byte, + Floating, + Pointer, + Array, + Vector, + Struct, + Function, + Named, +}; + +struct GenericConstantType final { + GenericConstantTypeKind Kind = GenericConstantTypeKind::Invalid; + std::uint32_t BitWidth = 0; + FloatSemantics Semantics = FloatSemantics::IEEEHalf; + std::uint32_t AddressSpace = 0; + std::uint64_t ElementCount = 0; + bool Scalable = false; + bool Packed = false; + bool VarArg = false; + bool NumericName = false; + std::string Name; + std::vector Elements; + + [[nodiscard]] static Expected integer(std::uint32_t BitWidth); + [[nodiscard]] static GenericConstantType primitive(GenericConstantTypeKind Kind) noexcept; + [[nodiscard]] static GenericConstantType byte() noexcept; + [[nodiscard]] static Expected floating(FloatSemantics Semantics); + [[nodiscard]] static GenericConstantType pointer(std::uint32_t AddressSpace = 0) noexcept; + [[nodiscard]] static Expected array(std::uint64_t ElementCount, + GenericConstantType Element); + [[nodiscard]] static Expected + vector(std::uint64_t ElementCount, GenericConstantType Element, bool Scalable = false); + [[nodiscard]] static Expected + structure(std::vector Elements, bool Packed = false); + [[nodiscard]] static Expected + function(GenericConstantType Return, std::vector Parameters, + bool VarArg = false); + [[nodiscard]] static Expected named(std::string Name, + bool NumericName = false); + + [[nodiscard]] const GenericConstantType &resolved() const noexcept; + [[nodiscard]] Expected verify() const; + + friend bool operator==(const GenericConstantType &Left, + const GenericConstantType &Right) = default; +}; + +enum class GenericConstantKind : std::uint8_t { + Invalid, + Integer, + Floating, + NullPointer, + ZeroInitializer, + Undef, + Poison, + Aggregate, + ByteString, + GlobalAddress, + BlockAddress, + DSOLocalEquivalent, + NoCFI, + PointerAuth, + Expression, +}; + +enum class GenericConstantExpressionOpcode : std::uint8_t { + Invalid, + Trunc, + BitCast, + AddressSpaceCast, + IntToPtr, + PtrToAddr, + PtrToInt, + Add, + Sub, + Xor, + GetElementPtr, + ShuffleVector, + InsertElement, + ExtractElement, + Splat, +}; + +enum class GenericConstantExpressionFlag : std::uint8_t { + NoUnsignedWrap, + NoSignedWrap, + InBounds, + NoUnsignedSignedWrap, + GEPNoUnsignedWrap, + Count, +}; + +class GenericConstantExpressionFlags final { +public: + constexpr GenericConstantExpressionFlags() noexcept = default; + + [[nodiscard]] constexpr bool has(GenericConstantExpressionFlag Flag) const noexcept { + const auto Index = static_cast(Flag); + if (Index >= static_cast(GenericConstantExpressionFlag::Count)) + return false; + return (Mask & (std::uint8_t{1} << Index)) != 0; + } + + constexpr void set(GenericConstantExpressionFlag Flag) noexcept { + const auto Index = static_cast(Flag); + if (Index < static_cast(GenericConstantExpressionFlag::Count)) + Mask |= std::uint8_t{1} << Index; + } + + [[nodiscard]] constexpr std::uint8_t rawValue() const noexcept { + return Mask; + } + + friend constexpr bool operator==(GenericConstantExpressionFlags Left, + GenericConstantExpressionFlags Right) noexcept = default; + +private: + std::uint8_t Mask = 0; +}; + +struct GenericConstantData final { + GenericConstantType Type; + GenericConstantKind Kind = GenericConstantKind::Invalid; + std::optional IntegerValue; + std::optional FloatingValue; + std::vector ByteValue; + std::vector Elements; + std::string Symbol; + std::string Block; + bool NumericSymbol = false; + bool NumericBlock = false; + GenericConstantExpressionOpcode ExpressionOpcode = GenericConstantExpressionOpcode::Invalid; + GenericConstantExpressionFlags ExpressionFlags; + std::optional SourceElementType; + std::optional InRangeStart; + std::optional InRangeEnd; + + [[nodiscard]] static Expected integer(APInt Value); + [[nodiscard]] static Expected floating(APFloat Value); + [[nodiscard]] static Expected byteString(GenericConstantType Type, + std::vector Bytes); + + [[nodiscard]] Expected toLLVMString() const; + [[nodiscard]] Expected verify() const; + [[nodiscard]] bool referencesSymbol() const noexcept; + + friend bool operator==(const GenericConstantData &Left, + const GenericConstantData &Right) = default; +}; + +} // namespace rcc + +#endif // RCC_IR_CONSTANTS_H diff --git a/backend/include/rcc/IR/DataLayout.h b/backend/include/rcc/IR/DataLayout.h new file mode 100644 index 0000000..0ca3f07 --- /dev/null +++ b/backend/include/rcc/IR/DataLayout.h @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_IR_DATALAYOUT_H +#define RCC_IR_DATALAYOUT_H + +#include "rcc/IR/Constants.h" +#include "rcc/Support/Error.h" + +#include +#include +#include +#include +#include + +namespace rcc { + +class DataLayout final { +public: + [[nodiscard]] static Expected parse(std::string_view LayoutString); + + [[nodiscard]] Expected getTypeAllocSize(const GenericConstantType &Type) const; + [[nodiscard]] Expected getABITypeAlign(const GenericConstantType &Type) const; + [[nodiscard]] Expected getPrefTypeAlign(const GenericConstantType &Type) const; + [[nodiscard]] Expected getPointerSizeInBits(std::uint32_t AddressSpace = 0) const; + +private: + struct AlignmentSpec final { + std::uint64_t ABI = 1; + std::uint64_t Preferred = 1; + }; + + struct PrimitiveSpec final { + char Kind = '\0'; + std::uint32_t BitWidth = 0; + AlignmentSpec Alignment; + }; + + struct PointerSpec final { + std::uint32_t AddressSpace = 0; + std::uint32_t SizeInBits = 0; + AlignmentSpec Alignment; + std::string AddressSpaceName; + }; + + struct TypeLayout final { + std::uint64_t StoreSize = 0; + std::uint64_t AllocationSize = 0; + std::uint64_t ABIAlignment = 1; + std::uint64_t PreferredAlignment = 1; + }; + + [[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 setPrimitiveSpec(PrimitiveSpec Entry); + void setPointerSpec(PointerSpec Entry); + [[nodiscard]] AlignmentSpec naturalAlignment(std::uint64_t StoreSize) const noexcept; + [[nodiscard]] AlignmentSpec scalarAlignment(char Kind, std::uint32_t BitWidth, + std::uint64_t StoreSize) const noexcept; + [[nodiscard]] AlignmentSpec integerAlignment(std::uint32_t BitWidth, + std::uint64_t StoreSize) const noexcept; + [[nodiscard]] AlignmentSpec floatingAlignment(std::uint32_t BitWidth, + std::uint64_t StoreSize) const noexcept; + [[nodiscard]] AlignmentSpec vectorAlignment(std::uint32_t BitWidth, + std::uint64_t StoreSize) const noexcept; + [[nodiscard]] Expected getPointerSpec(std::uint32_t AddressSpace) const; + [[nodiscard]] Expected getTypeLayout(const GenericConstantType &Type, + std::vector &NamedTypeStack, + std::size_t Depth) const; + + bool Explicit = false; + std::vector PrimitiveSpecs; + std::vector PointerSpecs; + AlignmentSpec AggregateAlignment{1, 8}; +}; + +} // namespace rcc + +#endif // RCC_IR_DATALAYOUT_H -- cgit v1.2.3