// SPDX-License-Identifier: GPL-3.0-or-later #ifndef RCC_CODEGEN_MACHINEIRTYPES_H #define RCC_CODEGEN_MACHINEIRTYPES_H #include "rcc/Support/Error.h" #include #include #include #include #include #include #include #include #include namespace rcc { template class MachineIndex final { public: constexpr MachineIndex() noexcept = default; [[nodiscard]] static constexpr MachineIndex fromValue(ValueT Value) noexcept { return MachineIndex(Value); } [[nodiscard]] constexpr ValueT value() const noexcept { return Value; } friend constexpr bool operator==(MachineIndex Left, MachineIndex Right) noexcept = default; friend constexpr auto operator<=>(MachineIndex Left, MachineIndex Right) noexcept = default; private: explicit constexpr MachineIndex(ValueT Value) noexcept : Value(Value) {} ValueT Value = 0; }; namespace detail { struct FrameIndexTag; struct ConstantPoolIndexTag; struct JumpTableIndexTag; struct TargetIndexTag; struct CFIInstructionIndexTag; struct IntrinsicIDTag; struct SubRegIndexTag; struct RegisterUnitIDTag; struct RegisterBankIDTag; struct RegisterClassIDTag; struct SchedulingClassIDTag; struct ProcessorResourceIDTag; struct RegisterPressureSetIDTag; struct ImmediatePredicateIDTag; struct NamedOperandIDTag; struct TargetOperandTypeIDTag; struct EncodingCategoryIDTag; struct AssemblyFormatIDTag; struct SyncScopeIDTag; struct MemoryAliasSourceIDTag; struct OriginIDTag; struct TargetConstantTypeIDTag; struct TargetFunctionStateTypeIDTag; struct TargetRelocationKindIDTag; struct CallingConventionIDTag; } // namespace detail using FrameIndex = MachineIndex; using ConstantPoolIndex = MachineIndex; using JumpTableIndex = MachineIndex; using TargetIndex = MachineIndex; using CFIInstructionIndex = MachineIndex; using IntrinsicID = MachineIndex; enum class GenericIntrinsic : std::uint32_t { VACopy = 1, }; [[nodiscard]] constexpr IntrinsicID intrinsicID(GenericIntrinsic Intrinsic) noexcept { return IntrinsicID::fromValue(static_cast(Intrinsic)); } using SubRegIndex = MachineIndex; using RegisterUnitID = MachineIndex; using RegisterBankID = MachineIndex; using RegisterClassID = MachineIndex; using SchedulingClassID = MachineIndex; using ProcessorResourceID = MachineIndex; using RegisterPressureSetID = MachineIndex; using ImmediatePredicateID = MachineIndex; using NamedOperandID = MachineIndex; using TargetOperandTypeID = MachineIndex; using EncodingCategoryID = MachineIndex; using AssemblyFormatID = MachineIndex; using SyncScopeID = MachineIndex; using MemoryAliasSourceID = MachineIndex; using OriginID = MachineIndex; using TargetConstantTypeID = MachineIndex; using TargetFunctionStateTypeID = MachineIndex; using TargetRelocationKindID = MachineIndex; using CallingConventionID = MachineIndex; class Alignment final { public: constexpr Alignment() noexcept = default; [[nodiscard]] static Expected create(std::uint64_t Bytes); [[nodiscard]] constexpr std::uint64_t bytes() const noexcept { return Bytes; } friend constexpr bool operator==(Alignment Left, Alignment Right) noexcept = default; private: explicit constexpr Alignment(std::uint64_t Bytes) noexcept : Bytes(Bytes) {} std::uint64_t Bytes = 1; }; class Opcode final { public: constexpr Opcode() noexcept = default; [[nodiscard]] static constexpr Opcode fromValue(std::uint32_t Value) noexcept { return Opcode(Value); } [[nodiscard]] constexpr bool isValid() const noexcept { return Value != 0; } [[nodiscard]] constexpr std::uint32_t value() const noexcept { return Value; } friend constexpr bool operator==(Opcode Left, Opcode Right) noexcept = default; private: explicit constexpr Opcode(std::uint32_t Value) noexcept : Value(Value) {} std::uint32_t Value = 0; }; class LaneMask final { public: constexpr LaneMask() noexcept = default; [[nodiscard]] static constexpr LaneMask fromRaw(std::uint64_t RawValue) noexcept { return LaneMask(RawValue); } [[nodiscard]] static constexpr LaneMask all() noexcept { return LaneMask(~std::uint64_t{0}); } [[nodiscard]] constexpr bool empty() const noexcept { return RawValue == 0; } [[nodiscard]] constexpr bool intersects(LaneMask Other) const noexcept { return (RawValue & Other.RawValue) != 0; } [[nodiscard]] constexpr bool contains(LaneMask Other) const noexcept { return (RawValue & Other.RawValue) == Other.RawValue; } [[nodiscard]] constexpr std::uint64_t rawValue() const noexcept { return RawValue; } [[nodiscard]] constexpr LaneMask operator~() const noexcept { return LaneMask(~RawValue); } constexpr LaneMask &operator|=(LaneMask Other) noexcept { RawValue |= Other.RawValue; return *this; } constexpr LaneMask &operator&=(LaneMask Other) noexcept { RawValue &= Other.RawValue; return *this; } friend constexpr bool operator==(LaneMask Left, LaneMask Right) noexcept = default; friend constexpr LaneMask operator|(LaneMask Left, LaneMask Right) noexcept { return LaneMask(Left.RawValue | Right.RawValue); } friend constexpr LaneMask operator&(LaneMask Left, LaneMask Right) noexcept { return LaneMask(Left.RawValue & Right.RawValue); } private: explicit constexpr LaneMask(std::uint64_t RawValue) noexcept : RawValue(RawValue) {} std::uint64_t RawValue = 0; }; class BranchProbability final { public: constexpr BranchProbability() noexcept = default; [[nodiscard]] static constexpr BranchProbability zero() noexcept { return BranchProbability(0); } [[nodiscard]] static constexpr BranchProbability one() noexcept { return BranchProbability(MaxRawValue); } [[nodiscard]] static constexpr BranchProbability fromRaw(std::uint32_t RawValue) noexcept { return BranchProbability(RawValue); } [[nodiscard]] static Expected fromFraction(std::uint32_t Numerator, std::uint32_t Denominator); static void normalizeProbabilities(std::span Probabilities) noexcept; [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { return RawValue; } [[nodiscard]] constexpr BranchProbability saturatingAdd(BranchProbability Other) const noexcept { if (MaxRawValue - RawValue < Other.RawValue) return one(); return BranchProbability(RawValue + Other.RawValue); } [[nodiscard]] constexpr BranchProbability complement() const noexcept { return BranchProbability(MaxRawValue - RawValue); } friend constexpr bool operator==(BranchProbability Left, BranchProbability Right) noexcept = default; friend constexpr auto operator<=>(BranchProbability Left, BranchProbability Right) noexcept = default; private: static constexpr std::uint32_t MaxRawValue = std::uint32_t{1} << 31U; explicit constexpr BranchProbability(std::uint32_t RawValue) noexcept : RawValue(RawValue) {} std::uint32_t RawValue = 0; }; enum class MachineInstrFlag : std::uint8_t { NoSignedWrap, NoUnsignedWrap, Exact, NoFPExcept, FastMathAllowReassoc, FastMathNoNaNs, FastMathNoInfs, FastMathNoSignedZeros, FastMathAllowReciprocal, FastMathAllowContract, FastMathApproxFunc, FrameSetup, FrameDestroy, BundledWithPred, BundledWithSucc, NoMerge, Unpredictable, NoConvergent, NonNeg, Disjoint, NoUSWrap, SameSign, InBounds, Count, }; class MachineInstrFlags final { public: constexpr MachineInstrFlags() noexcept = default; MachineInstrFlags(std::initializer_list Flags) noexcept; [[nodiscard]] constexpr bool has(MachineInstrFlag Flag) const noexcept { const auto Index = static_cast(Flag); if (Index >= static_cast(MachineInstrFlag::Count)) return false; return (Mask & (std::uint32_t{1} << Index)) != 0; } constexpr void set(MachineInstrFlag Flag) noexcept { const auto Index = static_cast(Flag); if (Index < static_cast(MachineInstrFlag::Count)) Mask |= std::uint32_t{1} << Index; } constexpr void clear(MachineInstrFlag Flag) noexcept { const auto Index = static_cast(Flag); if (Index < static_cast(MachineInstrFlag::Count)) Mask &= ~(std::uint32_t{1} << Index); } [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { return Mask; } friend constexpr bool operator==(MachineInstrFlags Left, MachineInstrFlags Right) noexcept = default; private: std::uint32_t Mask = 0; }; struct SourceLocation final { std::string File; std::uint32_t Line = 0; std::uint32_t Column = 0; std::uint32_t Discriminator = 0; [[nodiscard]] bool isValid() const noexcept { return !File.empty() && Line != 0; } friend bool operator==(const SourceLocation &Left, const SourceLocation &Right) = default; }; static_assert(sizeof(Opcode) == sizeof(std::uint32_t)); static_assert(sizeof(Alignment) == sizeof(std::uint64_t)); static_assert(sizeof(FrameIndex) == sizeof(std::uint32_t)); static_assert(sizeof(CallingConventionID) == sizeof(std::uint32_t)); static_assert(sizeof(MemoryAliasSourceID) == sizeof(std::uint64_t)); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copyable_v); static_assert(std::is_trivially_copyable_v); } // namespace rcc template struct std::hash> { [[nodiscard]] std::size_t operator()(rcc::MachineIndex Index) const noexcept { return std::hash{}(Index.value()); } }; template <> struct std::hash { [[nodiscard]] std::size_t operator()(rcc::Opcode Value) const noexcept { return std::hash{}(Value.value()); } }; #endif // RCC_CODEGEN_MACHINEIRTYPES_H