diff options
Diffstat (limited to 'backend')
54 files changed, 994 insertions, 1196 deletions
diff --git a/backend/include/rcc/CodeGen/InstructionDescriptor.h b/backend/include/rcc/CodeGen/InstructionDescriptor.h index 15d2162..ddc42e8 100644 --- a/backend/include/rcc/CodeGen/InstructionDescriptor.h +++ b/backend/include/rcc/CodeGen/InstructionDescriptor.h @@ -67,24 +67,24 @@ private: std::uint32_t Mask = 0; }; -class LLTKindSet final { +class LowLevelTypeKindSet final { public: - static_assert(static_cast<std::uint32_t>(LLT::Kind::VectorPointer) < 16); + static_assert(static_cast<std::uint32_t>(LowLevelType::Kind::VectorPointer) < 16); - constexpr LLTKindSet() noexcept = default; + constexpr LowLevelTypeKindSet() noexcept = default; - LLTKindSet(std::initializer_list<LLT::Kind> Kinds) noexcept; + LowLevelTypeKindSet(std::initializer_list<LowLevelType::Kind> Kinds) noexcept; [[nodiscard]] constexpr bool empty() const noexcept { return Mask == 0; } - [[nodiscard]] constexpr bool contains(LLT::Kind Kind) const noexcept { + [[nodiscard]] constexpr bool contains(LowLevelType::Kind Kind) const noexcept { const auto Index = static_cast<std::uint32_t>(Kind); return Index < 16 && (Mask & (std::uint16_t{1} << Index)) != 0; } - constexpr void add(LLT::Kind Kind) noexcept { + constexpr void add(LowLevelType::Kind Kind) noexcept { const auto Index = static_cast<std::uint32_t>(Kind); if (Index < 16) Mask |= std::uint16_t{1} << Index; @@ -94,7 +94,8 @@ public: return Mask; } - friend constexpr bool operator==(LLTKindSet Left, LLTKindSet Right) noexcept = default; + friend constexpr bool operator==(LowLevelTypeKindSet Left, + LowLevelTypeKindSet Right) noexcept = default; private: std::uint16_t Mask = 0; @@ -117,7 +118,7 @@ enum class MemoryOperandRole : std::uint8_t { }; struct OperandTypeConstraint final { - LLTKindSet Kinds; + LowLevelTypeKindSet Kinds; std::optional<std::uint16_t> EqualityGroup; }; @@ -141,6 +142,7 @@ enum class InstructionFlag : std::uint8_t { NotDuplicable, Convergent, UnmodeledSideEffects, + MayRaiseFPException, Phi, FakeUse, Generic, diff --git a/backend/include/rcc/CodeGen/LowLevelType.h b/backend/include/rcc/CodeGen/LowLevelType.h index e6ff174..d35d30d 100644 --- a/backend/include/rcc/CodeGen/LowLevelType.h +++ b/backend/include/rcc/CodeGen/LowLevelType.h @@ -3,7 +3,6 @@ #ifndef RCC_CODEGEN_LOWLEVELTYPE_H #define RCC_CODEGEN_LOWLEVELTYPE_H -#include "rcc/ADT/APFloat.h" #include "rcc/Support/Error.h" #include <cstddef> @@ -16,18 +15,14 @@ namespace rcc { -class LLT final { +class LowLevelType final { public: enum class Kind : std::uint8_t { Invalid, Token, - AnyScalar, - Integer, - Float, + CategoryNeutralScalar, Pointer, - VectorAny, - VectorInteger, - VectorFloat, + Vector, VectorPointer, }; @@ -35,20 +30,19 @@ public: static constexpr std::uint32_t MaxElementCount = (std::uint32_t{1} << 16) - 1; static constexpr std::uint32_t MaxAddressSpace = (std::uint32_t{1} << 24) - 1; - constexpr LLT() noexcept = default; + constexpr LowLevelType() noexcept = default; - [[nodiscard]] static constexpr LLT token() noexcept { - return LLT(encode(Kind::Token, 0, 0, 0, false)); + [[nodiscard]] static constexpr LowLevelType token() noexcept { + return LowLevelType(encode(Kind::Token, 0, 0, 0, false)); } - [[nodiscard]] static Expected<LLT> makeAnyScalar(std::uint64_t BitWidth); - [[nodiscard]] static Expected<LLT> makeInteger(std::uint64_t BitWidth); - [[nodiscard]] static Expected<LLT> makeFloat(FloatSemantics Semantics); - [[nodiscard]] static Expected<LLT> makePointer(std::uint64_t AddressSpace, - std::uint64_t BitWidth); - [[nodiscard]] static Expected<LLT> makeFixedVector(std::uint64_t ElementCount, LLT ElementType); - [[nodiscard]] static Expected<LLT> makeScalableVector(std::uint64_t MinimumElementCount, - LLT ElementType); + [[nodiscard]] static Expected<LowLevelType> makeCategoryNeutralScalar(std::uint64_t BitWidth); + [[nodiscard]] static Expected<LowLevelType> makePointer(std::uint64_t AddressSpace, + std::uint64_t BitWidth); + [[nodiscard]] static Expected<LowLevelType> makeFixedVector(std::uint64_t ElementCount, + LowLevelType ElementType); + [[nodiscard]] static Expected<LowLevelType> makeScalableVector(std::uint64_t MinimumElementCount, + LowLevelType ElementType); [[nodiscard]] constexpr Kind kind() const noexcept { return static_cast<Kind>((RawValue >> KindShift) & KindMask); @@ -62,53 +56,28 @@ public: return kind() == Kind::Token; } - [[nodiscard]] constexpr bool isAnyScalar() const noexcept { - return kind() == Kind::AnyScalar; - } - - [[nodiscard]] constexpr bool isInteger() const noexcept { - return kind() == Kind::Integer; - } - - [[nodiscard]] constexpr bool isFloat() const noexcept { - return kind() == Kind::Float; + [[nodiscard]] constexpr bool isCategoryNeutralScalar() const noexcept { + return kind() == Kind::CategoryNeutralScalar; } [[nodiscard]] constexpr bool isPointer() const noexcept { return kind() == Kind::Pointer; } - [[nodiscard]] constexpr bool isAnyVector() const noexcept { - return kind() == Kind::VectorAny; - } - - [[nodiscard]] constexpr bool isIntegerVector() const noexcept { - return kind() == Kind::VectorInteger; - } - - [[nodiscard]] constexpr bool isFloatVector() const noexcept { - return kind() == Kind::VectorFloat; + [[nodiscard]] constexpr bool isVectorValue() const noexcept { + return kind() == Kind::Vector; } [[nodiscard]] constexpr bool isPointerVector() const noexcept { return kind() == Kind::VectorPointer; } - [[nodiscard]] constexpr bool isIntegerOrIntegerVector() const noexcept { - return isInteger() || isIntegerVector(); - } - - [[nodiscard]] constexpr bool isFloatOrFloatVector() const noexcept { - return isFloat() || isFloatVector(); - } - [[nodiscard]] constexpr bool isPointerOrPointerVector() const noexcept { return isPointer() || isPointerVector(); } [[nodiscard]] constexpr bool isVector() const noexcept { - return kind() == Kind::VectorAny || kind() == Kind::VectorInteger || - kind() == Kind::VectorFloat || kind() == Kind::VectorPointer; + return kind() == Kind::Vector || kind() == Kind::VectorPointer; } [[nodiscard]] constexpr bool isScalableVector() const noexcept { @@ -116,7 +85,7 @@ public: } [[nodiscard]] constexpr bool isScalarValue() const noexcept { - return isAnyScalar() || isInteger() || isFloat() || isPointer(); + return isCategoryNeutralScalar() || isPointer(); } [[nodiscard]] constexpr std::uint32_t scalarBitWidth() const noexcept { @@ -130,8 +99,7 @@ public: } [[nodiscard]] std::optional<std::uint32_t> addressSpace() const noexcept; - [[nodiscard]] std::optional<FloatSemantics> floatSemantics() const noexcept; - [[nodiscard]] std::optional<LLT> scalarElementType() const noexcept; + [[nodiscard]] std::optional<LowLevelType> scalarElementType() const noexcept; [[nodiscard]] constexpr std::uint64_t rawValue() const noexcept { return RawValue; @@ -139,7 +107,7 @@ public: [[nodiscard]] std::string toString() const; - friend constexpr bool operator==(LLT Left, LLT Right) noexcept = default; + friend constexpr bool operator==(LowLevelType Left, LowLevelType Right) noexcept = default; private: static constexpr unsigned BitWidthShift = 0; @@ -153,7 +121,7 @@ private: static constexpr std::uint64_t AuxiliaryMask = (std::uint64_t{1} << 24) - 1; static constexpr std::uint64_t KindMask = (std::uint64_t{1} << 4) - 1; - explicit constexpr LLT(std::uint64_t RawValue) noexcept : RawValue(RawValue) {} + explicit constexpr LowLevelType(std::uint64_t RawValue) noexcept : RawValue(RawValue) {} [[nodiscard]] static constexpr std::uint64_t encode(Kind TypeKind, std::uint32_t BitWidth, std::uint32_t ElementCount, @@ -166,9 +134,8 @@ private: (static_cast<std::uint64_t>(BitWidth) << BitWidthShift); } - [[nodiscard]] static Expected<LLT> makeScalar(Kind TypeKind, std::uint64_t BitWidth); - [[nodiscard]] static Expected<LLT> makeVector(std::uint64_t ElementCount, bool IsScalable, - LLT ElementType); + [[nodiscard]] static Expected<LowLevelType> makeVector(std::uint64_t ElementCount, + bool IsScalable, LowLevelType ElementType); [[nodiscard]] constexpr std::uint32_t auxiliaryValue() const noexcept { return static_cast<std::uint32_t>((RawValue >> AuxiliaryShift) & AuxiliaryMask); @@ -177,13 +144,13 @@ private: std::uint64_t RawValue = 0; }; -static_assert(sizeof(LLT) == sizeof(std::uint64_t)); -static_assert(std::is_trivially_copyable_v<LLT>); +static_assert(sizeof(LowLevelType) == sizeof(std::uint64_t)); +static_assert(std::is_trivially_copyable_v<LowLevelType>); } // namespace rcc -template <> struct std::hash<rcc::LLT> { - [[nodiscard]] std::size_t operator()(rcc::LLT Type) const noexcept { +template <> struct std::hash<rcc::LowLevelType> { + [[nodiscard]] std::size_t operator()(rcc::LowLevelType Type) const noexcept { return std::hash<std::uint64_t>{}(Type.rawValue()); } }; diff --git a/backend/include/rcc/CodeGen/MachineMemOperand.h b/backend/include/rcc/CodeGen/MachineMemOperand.h index d236fd3..0ddd1b5 100644 --- a/backend/include/rcc/CodeGen/MachineMemOperand.h +++ b/backend/include/rcc/CodeGen/MachineMemOperand.h @@ -197,7 +197,7 @@ struct MachineMemOperandDesc final { AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic; SyncScopeID SyncScope; MemorySize Size; - std::optional<LLT> MemoryType; + std::optional<LowLevelType> MemoryType; Alignment Align; std::optional<Alignment> BaseAlign; std::uint32_t AddressSpace = 0; diff --git a/backend/include/rcc/CodeGen/MachineRegisterInfo.h b/backend/include/rcc/CodeGen/MachineRegisterInfo.h index 524ee77..e0538d3 100644 --- a/backend/include/rcc/CodeGen/MachineRegisterInfo.h +++ b/backend/include/rcc/CodeGen/MachineRegisterInfo.h @@ -81,7 +81,7 @@ private: struct VirtualRegisterInfo final { std::optional<std::string> Name; - std::optional<LLT> Type; + std::optional<LowLevelType> Type; std::optional<RegisterBankID> Bank; std::optional<RegisterClassID> RegClass; std::vector<PhysicalRegister> AllocationHints; @@ -107,7 +107,7 @@ public: ~MachineRegisterInfo(); [[nodiscard]] Expected<Register> createVirtualRegister(); - [[nodiscard]] Expected<Register> createVirtualRegister(LLT Type); + [[nodiscard]] Expected<Register> createVirtualRegister(LowLevelType Type); [[nodiscard]] Expected<void> eraseVirtualRegister(Register Reg); [[nodiscard]] bool isKnownVirtualRegister(Register Reg) const noexcept; @@ -119,7 +119,7 @@ public: [[nodiscard]] Expected<std::reference_wrapper<const VirtualRegisterInfo>> virtualRegisterInfo(Register Reg) const; - [[nodiscard]] Expected<void> setType(Register Reg, LLT Type); + [[nodiscard]] Expected<void> setType(Register Reg, LowLevelType Type); [[nodiscard]] Expected<void> clearType(Register Reg); [[nodiscard]] Expected<void> setRegisterBank(Register Reg, RegisterBankID Bank); [[nodiscard]] Expected<void> clearRegisterBank(Register Reg); diff --git a/backend/include/rcc/CodeGen/TargetCallLowering.h b/backend/include/rcc/CodeGen/TargetCallLowering.h index 9d9b98b..21b5407 100644 --- a/backend/include/rcc/CodeGen/TargetCallLowering.h +++ b/backend/include/rcc/CodeGen/TargetCallLowering.h @@ -33,6 +33,14 @@ enum class ABIExtensionKind : std::uint8_t { Count, }; +enum class ABIValueCategory : std::uint8_t { + Invalid, + Integer, + FloatingPoint, + Pointer, + Count, +}; + enum class ABIValueFlag : std::uint8_t { ByVal, StructReturn, @@ -71,7 +79,8 @@ private: struct ABIValue final { Register Value; - LLT Type; + LowLevelType Type; + ABIValueCategory Category = ABIValueCategory::Invalid; std::uint32_t OriginalValue = 0; std::uint16_t FragmentIndex = 0; std::uint16_t FragmentCount = 1; @@ -222,8 +231,8 @@ struct CCAssignment final { std::uint32_t OriginalValueIndex = 0; std::uint16_t FragmentIndex = 0; std::uint16_t FragmentCount = 1; - LLT ValueType; - LLT LocationType; + LowLevelType ValueType; + LowLevelType LocationType; CCLocationKind LocationKind = CCLocationKind::Register; std::optional<PhysicalRegister> LocationRegister; std::optional<std::uint64_t> StackOffsetBytes; @@ -279,7 +288,7 @@ struct VarArgLoweringState final { struct ByValCopyAssignment final { std::size_t ArgumentAssignmentIndex = 0; Register Source; - LLT PointerType; + LowLevelType PointerType; std::uint64_t StackOffsetBytes = 0; std::uint64_t SizeBytes = 0; Alignment Align; diff --git a/backend/lib/CodeGen/GenericOpcodes.cpp b/backend/lib/CodeGen/GenericOpcodes.cpp index 0cfd83f..f3ff5f1 100644 --- a/backend/lib/CodeGen/GenericOpcodes.cpp +++ b/backend/lib/CodeGen/GenericOpcodes.cpp @@ -33,52 +33,50 @@ using GO = GenericOpcode; [[nodiscard]] Expected<void> verifyGenericInstructionSemantics(const MachineInstr &Instruction, const MachineRegisterInfo &RegInfo); -[[nodiscard]] LLTKindSet anyValueKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::Float, - LLT::Kind::Pointer, LLT::Kind::VectorAny, LLT::Kind::VectorInteger, - LLT::Kind::VectorFloat, LLT::Kind::VectorPointer}; +[[nodiscard]] LowLevelTypeKindSet anyValueKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar, LowLevelType::Kind::Pointer, + LowLevelType::Kind::Vector, LowLevelType::Kind::VectorPointer}; } -[[nodiscard]] LLTKindSet integerKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::VectorAny, LLT::Kind::VectorInteger}; +[[nodiscard]] LowLevelTypeKindSet integerKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar, LowLevelType::Kind::Vector}; } -[[nodiscard]] LLTKindSet integerOrPointerKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::Pointer, - LLT::Kind::VectorAny, LLT::Kind::VectorInteger, LLT::Kind::VectorPointer}; +[[nodiscard]] LowLevelTypeKindSet integerOrPointerKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar, LowLevelType::Kind::Pointer, + LowLevelType::Kind::Vector, LowLevelType::Kind::VectorPointer}; } -[[nodiscard]] LLTKindSet scalarIntegerKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Integer}; +[[nodiscard]] LowLevelTypeKindSet scalarIntegerKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar}; } -[[nodiscard]] LLTKindSet scalarIntegerOrPointerKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::Pointer}; +[[nodiscard]] LowLevelTypeKindSet scalarIntegerOrPointerKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar, LowLevelType::Kind::Pointer}; } -[[nodiscard]] LLTKindSet scalarValueKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Integer, LLT::Kind::Float, LLT::Kind::Pointer}; +[[nodiscard]] LowLevelTypeKindSet scalarValueKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar, LowLevelType::Kind::Pointer}; } -[[nodiscard]] LLTKindSet floatingKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Float, LLT::Kind::VectorAny, LLT::Kind::VectorFloat}; +[[nodiscard]] LowLevelTypeKindSet floatingKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar, LowLevelType::Kind::Vector}; } -[[nodiscard]] LLTKindSet scalarFloatingKinds() { - return {LLT::Kind::AnyScalar, LLT::Kind::Float}; +[[nodiscard]] LowLevelTypeKindSet scalarFloatingKinds() { + return {LowLevelType::Kind::CategoryNeutralScalar}; } -[[nodiscard]] LLTKindSet pointerKinds() { - return {LLT::Kind::Pointer, LLT::Kind::VectorPointer}; +[[nodiscard]] LowLevelTypeKindSet pointerKinds() { + return {LowLevelType::Kind::Pointer, LowLevelType::Kind::VectorPointer}; } -[[nodiscard]] LLTKindSet scalarPointerKinds() { - return {LLT::Kind::Pointer}; +[[nodiscard]] LowLevelTypeKindSet scalarPointerKinds() { + return {LowLevelType::Kind::Pointer}; } -[[nodiscard]] LLTKindSet vectorKinds() { - return {LLT::Kind::VectorAny, LLT::Kind::VectorInteger, LLT::Kind::VectorFloat, - LLT::Kind::VectorPointer}; +[[nodiscard]] LowLevelTypeKindSet vectorKinds() { + return {LowLevelType::Kind::Vector, LowLevelType::Kind::VectorPointer}; } [[nodiscard]] OperandKindSet allOperandKinds() { @@ -106,7 +104,7 @@ using GO = GenericOpcode; MachineOperand::Kind::LaneMask}; } -[[nodiscard]] OperandDescriptor typedRegister(RegisterOperandRole Role, LLTKindSet Kinds, +[[nodiscard]] OperandDescriptor typedRegister(RegisterOperandRole Role, LowLevelTypeKindSet Kinds, std::uint16_t Group) { OperandDescriptor Result; Result.Kinds = {MachineOperand::Kind::Register}; @@ -263,22 +261,22 @@ private: return *Value; } -[[nodiscard]] std::uint64_t minimumBitWidth(LLT Type) noexcept { +[[nodiscard]] std::uint64_t minimumBitWidth(LowLevelType Type) noexcept { const std::uint64_t Elements = Type.isVector() ? Type.minimumElementCount() : 1; return Elements * Type.scalarBitWidth(); } -[[nodiscard]] std::uint64_t minimumStoreBytes(LLT Type) noexcept { +[[nodiscard]] std::uint64_t minimumStoreBytes(LowLevelType Type) noexcept { return (minimumBitWidth(Type) + 7) / 8; } -[[nodiscard]] LLT scalarElementType(LLT Type) noexcept { +[[nodiscard]] LowLevelType scalarElementType(LowLevelType Type) noexcept { if (const auto Element = Type.scalarElementType()) return *Element; return Type; } -[[nodiscard]] bool hasSameShape(LLT Left, LLT Right) noexcept { +[[nodiscard]] bool hasSameShape(LowLevelType Left, LowLevelType Right) noexcept { if (Left.isVector() != Right.isVector()) return false; if (!Left.isVector()) @@ -287,18 +285,18 @@ private: Left.minimumElementCount() == Right.minimumElementCount(); } -[[nodiscard]] Expected<void> requireSameShape(LLT Left, LLT Right, std::string_view Message) { +[[nodiscard]] Expected<void> requireSameShape(LowLevelType Left, LowLevelType Right, + std::string_view Message) { if (!hasSameShape(Left, Right)) return semanticError(Message); return {}; } -[[nodiscard]] Expected<void> requireI1WithShape(LLT Condition, LLT Value, +[[nodiscard]] Expected<void> requireI1WithShape(LowLevelType Condition, LowLevelType Value, bool AllowScalarCondition) { - const bool IsScalarInteger = Condition.isAnyScalar() || Condition.isInteger(); - const bool IsVectorInteger = Condition.isAnyVector() || Condition.isIntegerVector(); - if ((!IsScalarInteger && !IsVectorInteger) || Condition.scalarBitWidth() == 0) - return semanticError("generic condition or status result must use an integer LLT"); + if ((!Condition.isCategoryNeutralScalar() && !Condition.isVectorValue()) || + Condition.scalarBitWidth() == 0) + return semanticError("generic condition or status result must use an integer LowLevelType"); if (AllowScalarCondition && !Condition.isVector()) return {}; return requireSameShape(Condition, Value, @@ -308,7 +306,7 @@ private: [[nodiscard]] Expected<void> verifyGenericExplicitOperands(Opcode InstructionOpcode, std::span<const MachineOperand> Operands, const MachineRegisterInfo &RegInfo) { - std::vector<std::optional<LLT>> Types(Operands.size()); + std::vector<std::optional<LowLevelType>> Types(Operands.size()); bool SawNonDefinition = false; for (std::size_t Index = 0; Index < Operands.size(); ++Index) { const MachineOperand &Operand = Operands[Index]; @@ -334,18 +332,18 @@ private: auto Info = RegInfo.virtualRegisterInfo(*Reg); if (!Info) return std::unexpected(Info.error()); - const std::optional<LLT> &Type = Info->get().Type; + const std::optional<LowLevelType> &Type = Info->get().Type; if (!Type) - return semanticError("generic virtual register is missing its LLT"); + return semanticError("generic virtual register is missing its LowLevelType"); Types[Index] = Type.value(); } - const auto TypeAt = [&Types](std::size_t Index) -> LLT { return *Types[Index]; }; + const auto TypeAt = [&Types](std::size_t Index) -> LowLevelType { return *Types[Index]; }; const GO Generic = static_cast<GO>(InstructionOpcode.value()); const auto VerifyWidthChange = [&](bool IsExtension) -> Expected<void> { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); if (auto Shape = requireSameShape(Dst, Src, "generic width conversion must preserve vector shape"); !Shape) { @@ -389,7 +387,7 @@ private: case GO::G_CONSTANT: { if (const auto *Payload = Operands[1].getIf<IntegerImmediateOperand>(); Payload != nullptr && Payload->Value.bitWidth() != TypeAt(0).scalarBitWidth()) { - return semanticError("G_CONSTANT integer width must match its destination LLT"); + return semanticError("G_CONSTANT integer width must match its destination LowLevelType"); } return {}; } @@ -397,17 +395,14 @@ private: const auto *Payload = Operands[1].getIf<FloatingImmediateOperand>(); if (Payload == nullptr) return semanticError("G_FCONSTANT requires a floating-point immediate"); - const LLT DestinationType = TypeAt(0); - const std::optional<FloatSemantics> DestinationSemantics = DestinationType.floatSemantics(); - if ((DestinationSemantics && Payload->Bits.semantics() != *DestinationSemantics) || - (!DestinationSemantics && Payload->Bits.bitWidth() != DestinationType.scalarBitWidth())) { - return semanticError("G_FCONSTANT semantics must match its destination LLT"); - } + const LowLevelType DestinationType = TypeAt(0); + if (Payload->Bits.bitWidth() != DestinationType.scalarBitWidth()) + return semanticError("G_FCONSTANT width must match its destination LowLevelType"); return {}; } case GO::G_BITCAST: { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); if (Dst.isPointerOrPointerVector() != Src.isPointerOrPointerVector()) return semanticError("G_BITCAST cannot cross the pointer/non-pointer boundary"); if (minimumBitWidth(Dst) != minimumBitWidth(Src) || @@ -415,7 +410,7 @@ private: return semanticError("G_BITCAST source and destination sizes must match"); } if (Dst == Src) - return semanticError("G_BITCAST must change the LLT"); + return semanticError("G_BITCAST must change the LowLevelType"); return {}; } case GO::G_INTTOPTR: @@ -423,8 +418,8 @@ private: return requireSameShape(TypeAt(0), TypeAt(1), "pointer/integer conversion must preserve vector shape"); case GO::G_ADDRSPACE_CAST: { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); if (auto Shape = requireSameShape(Dst, Src, "G_ADDRSPACE_CAST must preserve vector shape"); !Shape) { return Shape; @@ -527,8 +522,8 @@ private: } case GO::G_UNMERGE_VALUES: { const std::size_t DestinationCount = Operands.size() - 1; - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(DestinationCount); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(DestinationCount); if (minimumBitWidth(Src) != minimumBitWidth(Dst) * DestinationCount) return semanticError("G_UNMERGE_VALUES destination widths do not cover the source"); if (Dst.isVector() && (!Src.isVector() || Dst.isScalableVector() != Src.isScalableVector() || @@ -559,22 +554,23 @@ private: } case GO::G_BUILD_VECTOR: case GO::G_BUILD_VECTOR_TRUNC: { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); if (!Dst.isVector() || Dst.isScalableVector() || Src.isVector()) return semanticError("G_BUILD_VECTOR requires a fixed vector result and scalar sources"); if (Dst.minimumElementCount() != Operands.size() - 1) return semanticError("G_BUILD_VECTOR source count must equal the result lane count"); - const LLT Element = scalarElementType(Dst); + const LowLevelType Element = scalarElementType(Dst); if (Generic == GO::G_BUILD_VECTOR && Element != Src) - return semanticError("G_BUILD_VECTOR source LLT must equal the result element LLT"); + return semanticError( + "G_BUILD_VECTOR source LowLevelType must equal the result element LowLevelType"); if (Generic == GO::G_BUILD_VECTOR_TRUNC && Src.scalarBitWidth() <= Element.scalarBitWidth()) return semanticError("G_BUILD_VECTOR_TRUNC sources must be wider than result elements"); return {}; } case GO::G_CONCAT_VECTORS: { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); if (!Dst.isVector() || !Src.isVector() || Dst.isScalableVector() != Src.isScalableVector() || scalarElementType(Dst) != scalarElementType(Src) || Dst.minimumElementCount() != Src.minimumElementCount() * (Operands.size() - 1)) { @@ -604,8 +600,8 @@ private: case GO::G_INSERT_SUBVECTOR: case GO::G_EXTRACT_SUBVECTOR: { const bool IsInsert = Generic == GO::G_INSERT_SUBVECTOR; - const LLT Outer = TypeAt(IsInsert ? 0 : 1); - const LLT Inner = TypeAt(IsInsert ? 2 : 0); + const LowLevelType Outer = TypeAt(IsInsert ? 0 : 1); + const LowLevelType Inner = TypeAt(IsInsert ? 2 : 0); const auto Index = plainImmediate(Operands[IsInsert ? 3 : 2]); if (!Outer.isVector() || !Inner.isVector() || scalarElementType(Outer) != scalarElementType(Inner) || !Index || *Index < 0) { @@ -626,8 +622,8 @@ private: return {}; } case GO::G_SHUFFLE_VECTOR: { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); const auto *Mask = Operands[3].getIf<ShuffleMaskOperand>(); if (!Dst.isVector() || !Src.isVector() || Dst.isScalableVector() || Src.isScalableVector() || scalarElementType(Dst) != scalarElementType(Src) || Mask == nullptr || @@ -644,8 +640,8 @@ private: return {}; } case GO::G_SPLAT_VECTOR: { - const LLT Dst = TypeAt(0); - const LLT Src = TypeAt(1); + const LowLevelType Dst = TypeAt(0); + const LowLevelType Src = TypeAt(1); if (!Dst.isScalableVector() || Src.isVector() || scalarElementType(Dst).scalarBitWidth() > Src.scalarBitWidth()) { return semanticError("G_SPLAT_VECTOR requires a scalable result with no wider elements"); @@ -653,7 +649,7 @@ private: return {}; } case GO::G_STEP_VECTOR: { - const LLT Dst = TypeAt(0); + const LowLevelType Dst = TypeAt(0); const auto *Step = Operands[1].getIf<IntegerImmediateOperand>(); if (!Dst.isScalableVector() || Step == nullptr || Step->Value.isZero() || Step->Value.isNegative() || Step->Value.bitWidth() != Dst.scalarBitWidth()) { @@ -662,15 +658,15 @@ private: return {}; } case GO::G_INSERT_VECTOR_ELT: { - const LLT Vector = TypeAt(0); + const LowLevelType Vector = TypeAt(0); if (scalarElementType(Vector) != TypeAt(2) || TypeAt(3).isVector()) - return semanticError("G_INSERT_VECTOR_ELT element or index LLT is incompatible"); + return semanticError("G_INSERT_VECTOR_ELT element or index LowLevelType is incompatible"); return {}; } case GO::G_EXTRACT_VECTOR_ELT: { - const LLT Vector = TypeAt(1); + const LowLevelType Vector = TypeAt(1); if (scalarElementType(Vector) != TypeAt(0) || TypeAt(2).isVector()) - return semanticError("G_EXTRACT_VECTOR_ELT result or index LLT is incompatible"); + return semanticError("G_EXTRACT_VECTOR_ELT result or index LowLevelType is incompatible"); return {}; } case GO::G_VECTOR_COMPRESS: @@ -699,7 +695,7 @@ private: case GO::G_VECREDUCE_UMIN: if (TypeAt(0).isVector() || !TypeAt(1).isVector() || scalarElementType(TypeAt(1)) != TypeAt(0)) { - return semanticError("vector reduction result must equal the source element LLT"); + return semanticError("vector reduction result must equal the source element LowLevelType"); } return {}; case GO::G_SBFX: @@ -807,7 +803,7 @@ private: const auto MemoryOperands = Instruction.memOperands(); const GO Generic = static_cast<GO>(Instruction.opcode().value()); - const auto TypeAt = [&](std::size_t Index) -> Expected<LLT> { + const auto TypeAt = [&](std::size_t Index) -> Expected<LowLevelType> { if (Index >= Operands.size()) return makeUnexpected(ErrorCode::InternalError, "generic semantic verifier operand index is out of range"); @@ -820,7 +816,7 @@ private: return std::unexpected(Info.error()); if (!Info->get().Type) return makeUnexpected(ErrorCode::InternalError, - "generic semantic verifier found a register without an LLT"); + "generic semantic verifier found a register without an LowLevelType"); return *Info->get().Type; }; @@ -830,7 +826,8 @@ private: if (!Type) return std::unexpected(Type.error()); if (!Type->isPointer() || Type->addressSpace() != Memory.description().AddressSpace) - return semanticError("generic memory address LLT and MMO address space do not match"); + return semanticError( + "generic memory address LowLevelType and MMO address space do not match"); return {}; }; @@ -839,7 +836,7 @@ private: NoLarger, StrictlySmaller, }; - const auto VerifySize = [&](LLT ValueType, const MachineMemOperand &Memory, + const auto VerifySize = [&](LowLevelType ValueType, const MachineMemOperand &Memory, SizeRelation Relation) -> Expected<void> { const MemorySize Size = Memory.description().Size; if (!Size.isKnown()) @@ -853,7 +850,8 @@ private: : (Relation == SizeRelation::NoLarger ? MemoryBytes <= ValueBytes : MemoryBytes < ValueBytes); if (!Valid) - return semanticError("generic memory access size is incompatible with its value LLT"); + return semanticError( + "generic memory access size is incompatible with its value LowLevelType"); return {}; }; @@ -1121,17 +1119,17 @@ void configureCoreOpcodes(DescriptorRegistry &Registry) { } void configureGenericOpcodes(DescriptorRegistry &Registry) { - const LLTKindSet AnyTypes = anyValueKinds(); - const LLTKindSet IntTypes = integerKinds(); - const LLTKindSet IntegerOrPointers = integerOrPointerKinds(); - const LLTKindSet ScalarValues = scalarValueKinds(); - const LLTKindSet ScalarInts = scalarIntegerKinds(); - const LLTKindSet ScalarIntegerOrPointers = scalarIntegerOrPointerKinds(); - const LLTKindSet FloatTypes = floatingKinds(); - const LLTKindSet ScalarFloats = scalarFloatingKinds(); - const LLTKindSet PointerTypes = pointerKinds(); - const LLTKindSet ScalarPointers = scalarPointerKinds(); - const LLTKindSet VectorTypes = vectorKinds(); + const LowLevelTypeKindSet AnyTypes = anyValueKinds(); + const LowLevelTypeKindSet IntTypes = integerKinds(); + const LowLevelTypeKindSet IntegerOrPointers = integerOrPointerKinds(); + const LowLevelTypeKindSet ScalarValues = scalarValueKinds(); + const LowLevelTypeKindSet ScalarInts = scalarIntegerKinds(); + const LowLevelTypeKindSet ScalarIntegerOrPointers = scalarIntegerOrPointerKinds(); + const LowLevelTypeKindSet FloatTypes = floatingKinds(); + const LowLevelTypeKindSet ScalarFloats = scalarFloatingKinds(); + const LowLevelTypeKindSet PointerTypes = pointerKinds(); + const LowLevelTypeKindSet ScalarPointers = scalarPointerKinds(); + const LowLevelTypeKindSet VectorTypes = vectorKinds(); const auto AnyDef0 = typedRegister(RegisterOperandRole::Def, AnyTypes, 0); const auto AnyUse0 = typedRegister(RegisterOperandRole::Use, AnyTypes, 0); @@ -1414,16 +1412,17 @@ void configureGenericOpcodes(DescriptorRegistry &Registry) { Registry.configure({GO::G_STRICT_FADD, GO::G_STRICT_FSUB, GO::G_STRICT_FMUL, GO::G_STRICT_FDIV, GO::G_STRICT_FREM}, - {FloatDef0, FloatUse0, FloatUse0}, 1, {InstructionFlag::HasSideEffects}); + {FloatDef0, FloatUse0, FloatUse0}, 1, + {InstructionFlag::HasSideEffects, InstructionFlag::MayRaiseFPException}); Registry.configure({GO::G_STRICT_FMA}, {FloatDef0, FloatUse0, FloatUse0, FloatUse0}, 1, - {InstructionFlag::HasSideEffects}); + {InstructionFlag::HasSideEffects, InstructionFlag::MayRaiseFPException}); Registry.configure({GO::G_STRICT_FSQRT}, {FloatDef0, FloatUse0}, 1, - {InstructionFlag::HasSideEffects}); + {InstructionFlag::HasSideEffects, InstructionFlag::MayRaiseFPException}); Registry.configure({GO::G_STRICT_FLDEXP}, {FloatDef0, FloatUse0, IntUse1}, 1, - {InstructionFlag::HasSideEffects}); + {InstructionFlag::HasSideEffects, InstructionFlag::MayRaiseFPException}); Registry.configure({GO::G_STRICT_FCMP, GO::G_STRICT_FCMPS}, {IntDef0, kind(MachineOperand::Kind::Predicate), FloatUse1, FloatUse1}, 1, - {InstructionFlag::HasSideEffects}); + {InstructionFlag::HasSideEffects, InstructionFlag::MayRaiseFPException}); Registry.configure({GO::G_READ_REGISTER}, {AnyDef0, kind(MachineOperand::Kind::Metadata)}, 1, {InstructionFlag::HasSideEffects, InstructionFlag::Convergent}); Registry.configure({GO::G_WRITE_REGISTER}, {kind(MachineOperand::Kind::Metadata), AnyUse0}, 0, diff --git a/backend/lib/CodeGen/InstructionDescriptor.cpp b/backend/lib/CodeGen/InstructionDescriptor.cpp index 2c99939..d164cde 100644 --- a/backend/lib/CodeGen/InstructionDescriptor.cpp +++ b/backend/lib/CodeGen/InstructionDescriptor.cpp @@ -80,7 +80,7 @@ namespace { } if (Operand.TypeConstraint) { if (!isRegisterOnly(Operand.Kinds) || Operand.TypeConstraint->Kinds.empty() || - Operand.TypeConstraint->Kinds.contains(LLT::Kind::Invalid)) { + Operand.TypeConstraint->Kinds.contains(LowLevelType::Kind::Invalid)) { return makeUnexpected(ErrorCode::InvalidArgument, "typed operand descriptor requires a nonempty register type set"); } @@ -307,8 +307,8 @@ OperandKindSet::OperandKindSet(std::initializer_list<MachineOperand::Kind> Kinds add(Kind); } -LLTKindSet::LLTKindSet(std::initializer_list<LLT::Kind> Kinds) noexcept { - for (const LLT::Kind Kind : Kinds) +LowLevelTypeKindSet::LowLevelTypeKindSet(std::initializer_list<LowLevelType::Kind> Kinds) noexcept { + for (const LowLevelType::Kind Kind : Kinds) add(Kind); } @@ -386,7 +386,7 @@ Expected<void> InstructionSet::validateExplicitOperands(const InstructionDescrip return std::unexpected(Shape.error()); bool SawUse = false; - std::unordered_map<std::uint16_t, LLT> EqualityGroups; + std::unordered_map<std::uint16_t, LowLevelType> EqualityGroups; for (std::size_t Index = 0; Index < Operands.size(); ++Index) { const MachineOperand &Operand = Operands[Index]; if (Operand.isImplicit()) { @@ -423,22 +423,24 @@ Expected<void> InstructionSet::validateExplicitOperands(const InstructionDescrip auto Info = RegInfo.virtualRegisterInfo(*Reg); if (!Info) return std::unexpected(Info.error()); - const std::optional<LLT> &RegisterType = Info->get().Type; + const std::optional<LowLevelType> &RegisterType = Info->get().Type; if (!RegisterType) { return makeUnexpected(ErrorCode::VerificationError, - "typed instruction operand virtual register has no LLT"); + "typed instruction operand virtual register has no LowLevelType"); } - const LLT Type = RegisterType.value(); + const LowLevelType Type = RegisterType.value(); if (!OperandDesc.TypeConstraint->Kinds.contains(Type.kind())) { - return makeUnexpected(ErrorCode::VerificationError, - "instruction operand LLT kind is not permitted by its descriptor"); + return makeUnexpected( + ErrorCode::VerificationError, + "instruction operand LowLevelType kind is not permitted by its descriptor"); } if (OperandDesc.TypeConstraint->EqualityGroup) { const auto [Position, Inserted] = EqualityGroups.emplace(*OperandDesc.TypeConstraint->EqualityGroup, Type); if (!Inserted && Position->second != Type) { - return makeUnexpected(ErrorCode::VerificationError, - "instruction operands in one LLT group have different types"); + return makeUnexpected( + ErrorCode::VerificationError, + "instruction operands in one LowLevelType group have different types"); } } } diff --git a/backend/lib/CodeGen/LowLevelType.cpp b/backend/lib/CodeGen/LowLevelType.cpp index b50ea6b..50ee0e6 100644 --- a/backend/lib/CodeGen/LowLevelType.cpp +++ b/backend/lib/CodeGen/LowLevelType.cpp @@ -8,130 +8,99 @@ namespace rcc { namespace { -[[nodiscard]] LLT::Kind getVectorKind(LLT ElementType) noexcept { +[[nodiscard]] LowLevelType::Kind getVectorKind(LowLevelType ElementType) noexcept { switch (ElementType.kind()) { - case LLT::Kind::AnyScalar: - return LLT::Kind::VectorAny; - case LLT::Kind::Integer: - return LLT::Kind::VectorInteger; - case LLT::Kind::Float: - return LLT::Kind::VectorFloat; - case LLT::Kind::Pointer: - return LLT::Kind::VectorPointer; - case LLT::Kind::Invalid: - case LLT::Kind::Token: - case LLT::Kind::VectorAny: - case LLT::Kind::VectorInteger: - case LLT::Kind::VectorFloat: - case LLT::Kind::VectorPointer: - return LLT::Kind::Invalid; + case LowLevelType::Kind::CategoryNeutralScalar: + return LowLevelType::Kind::Vector; + case LowLevelType::Kind::Pointer: + return LowLevelType::Kind::VectorPointer; + case LowLevelType::Kind::Invalid: + case LowLevelType::Kind::Token: + case LowLevelType::Kind::Vector: + case LowLevelType::Kind::VectorPointer: + return LowLevelType::Kind::Invalid; } - return LLT::Kind::Invalid; + return LowLevelType::Kind::Invalid; } } // namespace -Expected<LLT> LLT::makeScalar(Kind TypeKind, std::uint64_t BitWidth) { +Expected<LowLevelType> LowLevelType::makeCategoryNeutralScalar(std::uint64_t BitWidth) { if (BitWidth == 0 || BitWidth > MaxBitWidth) { return makeUnexpected(ErrorCode::InvalidArgument, - "LLT bit width must be in the range [1, 65535]"); + "LowLevelType bit width must be in the range [1, 65535]"); } - return LLT(encode(TypeKind, static_cast<std::uint32_t>(BitWidth), 0, 0, false)); + return LowLevelType( + encode(Kind::CategoryNeutralScalar, static_cast<std::uint32_t>(BitWidth), 0, 0, false)); } -Expected<LLT> LLT::makeAnyScalar(std::uint64_t BitWidth) { - return makeScalar(Kind::AnyScalar, BitWidth); -} - -Expected<LLT> LLT::makeInteger(std::uint64_t BitWidth) { - return makeScalar(Kind::Integer, BitWidth); -} - -Expected<LLT> LLT::makeFloat(FloatSemantics Semantics) { - const auto BitWidth = getFloatSemanticsBitWidth(Semantics); - if (!BitWidth) { - return makeUnexpected(ErrorCode::InvalidArgument, "unknown floating-point semantics"); - } - - return LLT(encode(Kind::Float, *BitWidth, 0, static_cast<std::uint32_t>(Semantics), false)); -} - -Expected<LLT> LLT::makePointer(std::uint64_t AddressSpace, std::uint64_t BitWidth) { +Expected<LowLevelType> LowLevelType::makePointer(std::uint64_t AddressSpace, + std::uint64_t BitWidth) { if (BitWidth == 0 || BitWidth > MaxBitWidth) { return makeUnexpected(ErrorCode::InvalidArgument, - "LLT pointer bit width must be in the range [1, 65535]"); + "LowLevelType pointer bit width must be in the range [1, 65535]"); } if (AddressSpace > MaxAddressSpace) { - return makeUnexpected(ErrorCode::InvalidArgument, "LLT address space must fit in 24 bits"); + return makeUnexpected(ErrorCode::InvalidArgument, + "LowLevelType address space must fit in 24 bits"); } - return LLT(encode(Kind::Pointer, static_cast<std::uint32_t>(BitWidth), 0, - static_cast<std::uint32_t>(AddressSpace), false)); + return LowLevelType(encode(Kind::Pointer, static_cast<std::uint32_t>(BitWidth), 0, + static_cast<std::uint32_t>(AddressSpace), false)); } -Expected<LLT> LLT::makeFixedVector(std::uint64_t ElementCount, LLT ElementType) { +Expected<LowLevelType> LowLevelType::makeFixedVector(std::uint64_t ElementCount, + LowLevelType ElementType) { return makeVector(ElementCount, false, ElementType); } -Expected<LLT> LLT::makeScalableVector(std::uint64_t MinimumElementCount, LLT ElementType) { +Expected<LowLevelType> LowLevelType::makeScalableVector(std::uint64_t MinimumElementCount, + LowLevelType ElementType) { return makeVector(MinimumElementCount, true, ElementType); } -Expected<LLT> LLT::makeVector(std::uint64_t ElementCount, bool IsScalable, LLT ElementType) { +Expected<LowLevelType> LowLevelType::makeVector(std::uint64_t ElementCount, bool IsScalable, + LowLevelType ElementType) { if (ElementCount == 0 || ElementCount > MaxElementCount) { return makeUnexpected(ErrorCode::InvalidArgument, - "LLT vector element count must be in the range [1, 65535]"); + "LowLevelType vector element count must be in the range [1, 65535]"); } if (!IsScalable && ElementCount == 1) { return makeUnexpected(ErrorCode::InvalidArgument, - "a fixed LLT vector must contain at least two elements"); + "a fixed LowLevelType vector must contain at least two elements"); } const Kind VectorKind = getVectorKind(ElementType); if (VectorKind == Kind::Invalid) { return makeUnexpected(ErrorCode::InvalidArgument, - "LLT vector elements must be non-vector value types"); + "LowLevelType vector elements must be non-vector value types"); } std::uint32_t Auxiliary = 0; if (ElementType.isPointer()) Auxiliary = *ElementType.addressSpace(); - else if (ElementType.isFloat()) - Auxiliary = static_cast<std::uint32_t>(*ElementType.floatSemantics()); - return LLT(encode(VectorKind, ElementType.scalarBitWidth(), - static_cast<std::uint32_t>(ElementCount), Auxiliary, IsScalable)); + return LowLevelType(encode(VectorKind, ElementType.scalarBitWidth(), + static_cast<std::uint32_t>(ElementCount), Auxiliary, IsScalable)); } -std::optional<std::uint32_t> LLT::addressSpace() const noexcept { +std::optional<std::uint32_t> LowLevelType::addressSpace() const noexcept { if (!isPointerOrPointerVector()) return std::nullopt; return auxiliaryValue(); } -std::optional<FloatSemantics> LLT::floatSemantics() const noexcept { - if (!isFloatOrFloatVector()) - return std::nullopt; - return static_cast<FloatSemantics>(auxiliaryValue()); -} - -std::optional<LLT> LLT::scalarElementType() const noexcept { +std::optional<LowLevelType> LowLevelType::scalarElementType() const noexcept { switch (kind()) { - case Kind::VectorAny: - return LLT(encode(Kind::AnyScalar, scalarBitWidth(), 0, 0, false)); - case Kind::VectorInteger: - return LLT(encode(Kind::Integer, scalarBitWidth(), 0, 0, false)); - case Kind::VectorFloat: - return LLT(encode(Kind::Float, scalarBitWidth(), 0, auxiliaryValue(), false)); + case Kind::Vector: + return LowLevelType(encode(Kind::CategoryNeutralScalar, scalarBitWidth(), 0, 0, false)); case Kind::VectorPointer: - return LLT(encode(Kind::Pointer, scalarBitWidth(), 0, auxiliaryValue(), false)); + return LowLevelType(encode(Kind::Pointer, scalarBitWidth(), 0, auxiliaryValue(), false)); case Kind::Invalid: case Kind::Token: - case Kind::AnyScalar: - case Kind::Integer: - case Kind::Float: + case Kind::CategoryNeutralScalar: case Kind::Pointer: return std::nullopt; } @@ -139,7 +108,7 @@ std::optional<LLT> LLT::scalarElementType() const noexcept { return std::nullopt; } -std::string LLT::toString() const { +std::string LowLevelType::toString() const { if (!isValid()) return "LLT_invalid"; if (isToken()) @@ -147,19 +116,10 @@ std::string LLT::toString() const { std::string ScalarSpelling; switch (kind()) { - case Kind::AnyScalar: - case Kind::VectorAny: + case Kind::CategoryNeutralScalar: + case Kind::Vector: ScalarSpelling = "s" + std::to_string(scalarBitWidth()); break; - case Kind::Integer: - case Kind::VectorInteger: - ScalarSpelling = "i" + std::to_string(scalarBitWidth()); - break; - case Kind::Float: - case Kind::VectorFloat: - ScalarSpelling = - std::string(getFloatSemanticsSpelling(static_cast<FloatSemantics>(auxiliaryValue()))); - break; case Kind::Pointer: case Kind::VectorPointer: ScalarSpelling = diff --git a/backend/lib/CodeGen/MIRParser/MIParser.cpp b/backend/lib/CodeGen/MIRParser/MIParser.cpp index 5932111..b21e713 100644 --- a/backend/lib/CodeGen/MIRParser/MIParser.cpp +++ b/backend/lib/CodeGen/MIRParser/MIParser.cpp @@ -159,7 +159,7 @@ namespace { return APInt::create(BitWidth, Words); } -[[nodiscard]] std::optional<std::uint64_t> minimumTypeSizeInBits(LLT Type) noexcept { +[[nodiscard]] std::optional<std::uint64_t> minimumTypeSizeInBits(LowLevelType Type) noexcept { if (!Type.isValid() || Type.isToken()) return std::nullopt; const std::uint64_t ScalarSize = Type.scalarBitWidth(); @@ -377,8 +377,8 @@ private: [[nodiscard]] bool parseSigned64(const MIToken &Token, std::int64_t &Value); [[nodiscard]] bool parseOptionalOffset(std::int64_t &Offset); [[nodiscard]] bool parseAlignment(Alignment &Result); - [[nodiscard]] bool parseLowLevelType(LLT &Result); - [[nodiscard]] bool parseScalarLowLevelType(const MIToken &Token, LLT &Result); + [[nodiscard]] bool parseLowLevelType(LowLevelType &Result); + [[nodiscard]] bool parseScalarLowLevelType(const MIToken &Token, LowLevelType &Result); [[nodiscard]] bool parseFirstPass(); [[nodiscard]] bool parseSecondPass(); @@ -553,30 +553,20 @@ bool MIParser::Impl::parseAlignment(Alignment &Result) { return false; } -bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LLT &Result) { +bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LowLevelType &Result) { if (TypeToken.kind() != MITokenKind::Identifier) return fail(TypeToken, "expected a scalar low-level type"); std::string_view Spelling = TypeToken.stringValue(); - enum class ScalarKind : std::uint8_t { - Any, - Integer, - Float, - BFloat, - Pointer, - }; - ScalarKind Kind = ScalarKind::Any; + enum class ScalarKind : std::uint8_t { CategoryNeutral, Pointer }; + ScalarKind Kind = ScalarKind::CategoryNeutral; std::string_view Digits; if (Spelling.starts_with("bf")) { - Kind = ScalarKind::BFloat; Digits = Spelling.substr(2); } else if (Spelling.starts_with('s')) { - Kind = ScalarKind::Any; Digits = Spelling.substr(1); } else if (Spelling.starts_with('i')) { - Kind = ScalarKind::Integer; Digits = Spelling.substr(1); } else if (Spelling.starts_with('f')) { - Kind = ScalarKind::Float; Digits = Spelling.substr(1); } else if (Spelling.starts_with('p')) { Kind = ScalarKind::Pointer; @@ -589,43 +579,20 @@ bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LLT &Resu if (!parseUnsignedDigits(Digits, Value)) return fail(TypeToken, "expected integers after 's'/'i'/'f'/'bf'/'p' type identifier"); - Expected<LLT> Created = makeUnexpected(ErrorCode::ParseError, "invalid low-level type"); + Expected<LowLevelType> Created = makeUnexpected(ErrorCode::ParseError, "invalid low-level type"); switch (Kind) { - case ScalarKind::Any: + case ScalarKind::CategoryNeutral: if (Value == 0) { - Result = LLT::token(); + Result = LowLevelType::token(); return false; } - Created = LLT::makeAnyScalar(Value); - break; - case ScalarKind::Integer: - Created = LLT::makeInteger(Value); - break; - case ScalarKind::Float: { - std::optional<FloatSemantics> Semantics; - if (Value == 16) - Semantics = FloatSemantics::IEEEHalf; - else if (Value == 32) - Semantics = FloatSemantics::IEEESingle; - else if (Value == 64) - Semantics = FloatSemantics::IEEEDouble; - else if (Value == 128) - Semantics = FloatSemantics::IEEEQuad; - if (!Semantics) - return fail(TypeToken, "unsupported IEEE floating low-level type width"); - Created = LLT::makeFloat(*Semantics); - break; - } - case ScalarKind::BFloat: - if (Value != 16) - return fail(TypeToken, "bfloat low-level type must have width 16"); - Created = LLT::makeFloat(FloatSemantics::BFloat); + Created = LowLevelType::makeCategoryNeutralScalar(Value); break; case ScalarKind::Pointer: if (!Context.PointerSizeInBits) return fail(TypeToken, "pointer low-level type requires an explicit pointer size"); if (auto PointerSize = Context.PointerSizeInBits(static_cast<std::uint32_t>(Value))) - Created = LLT::makePointer(Value, *PointerSize); + Created = LowLevelType::makePointer(Value, *PointerSize); else return importError(TypeToken, PointerSize.error()); break; @@ -636,7 +603,7 @@ bool MIParser::Impl::parseScalarLowLevelType(const MIToken &TypeToken, LLT &Resu return false; } -bool MIParser::Impl::parseLowLevelType(LLT &Result) { +bool MIParser::Impl::parseLowLevelType(LowLevelType &Result) { const MIToken Begin = token(); const auto HasScalarPrefix = [](std::string_view Spelling) { return Spelling.starts_with('s') || Spelling.starts_with('i') || Spelling.starts_with('f') || @@ -685,7 +652,7 @@ bool MIParser::Impl::parseLowLevelType(LLT &Result) { if (!at(MITokenKind::Identifier) || !HasScalarPrefix(token().stringValue())) return VectorError(); - LLT ElementType; + LowLevelType ElementType; if (parseScalarLowLevelType(token(), ElementType)) return true; if (ElementType.isToken()) @@ -694,8 +661,9 @@ bool MIParser::Impl::parseLowLevelType(LLT &Result) { if (!consume(MITokenKind::Greater)) return VectorError(); - Expected<LLT> Created = Scalable ? LLT::makeScalableVector(ElementCount, ElementType) - : LLT::makeFixedVector(ElementCount, ElementType); + Expected<LowLevelType> Created = Scalable + ? LowLevelType::makeScalableVector(ElementCount, ElementType) + : LowLevelType::makeFixedVector(ElementCount, ElementType); if (!Created) return importError(Begin, Created.error()); Result = *Created; @@ -1078,7 +1046,7 @@ bool MIParser::Impl::parseRegisterOperand(bool IsDef, ParsedOperand &Result) { } else { if (!Reg.isVirtual()) return fail("low-level type is only valid on a virtual register"); - LLT Type; + LowLevelType Type; if (parseLowLevelType(Type)) return true; if (expect(MITokenKind::RightParen, "')' after the low-level type")) @@ -1883,7 +1851,7 @@ bool MIParser::Impl::parseMemoryOperand(const MachineMemOperand *&Result, } else if (atKeyword("unknown-size")) { advance(); } else if (consume(MITokenKind::LeftParen)) { - LLT Type; + LowLevelType Type; if (parseLowLevelType(Type)) return true; if (expect(MITokenKind::RightParen, "')' after the memory low-level type")) @@ -1945,7 +1913,7 @@ bool MIParser::Impl::parseMemoryOperand(const MachineMemOperand *&Result, } else if (atKeyword("addrspace")) { advance(); if (!at(MITokenKind::IntegerLiteral) || parseUnsigned32(token(), Description.AddressSpace) || - Description.AddressSpace > LLT::MaxAddressSpace) { + Description.AddressSpace > LowLevelType::MaxAddressSpace) { return fail("invalid machine memory operand address space"); } advance(); diff --git a/backend/lib/CodeGen/MIRPrinter.cpp b/backend/lib/CodeGen/MIRPrinter.cpp index d2cc8eb..1ba8ac1 100644 --- a/backend/lib/CodeGen/MIRPrinter.cpp +++ b/backend/lib/CodeGen/MIRPrinter.cpp @@ -1647,13 +1647,11 @@ namespace { return {}; } -[[nodiscard]] Expected<std::string> llvmMIRScalarLowLevelType(LLT Type) { +[[nodiscard]] Expected<std::string> llvmMIRScalarLowLevelType(LowLevelType Type) { if (Type.isToken()) return "s0"; - if (Type.isAnyScalar()) + if (Type.isCategoryNeutralScalar()) return "s" + std::to_string(Type.scalarBitWidth()); - if (Type.isInteger()) - return "i" + std::to_string(Type.scalarBitWidth()); if (Type.isPointer()) { const auto AddressSpace = Type.addressSpace(); if (!AddressSpace) { @@ -1662,49 +1660,11 @@ namespace { } return "p" + std::to_string(*AddressSpace); } - if (!Type.isFloat()) { - return makeUnexpected(ErrorCode::VerificationError, - "invalid scalar low-level type cannot be printed as LLVM MIR"); - } - - const auto Semantics = Type.floatSemantics(); - if (!Semantics) { - return makeUnexpected(ErrorCode::VerificationError, - "floating low-level type has no floating-point semantics"); - } - switch (*Semantics) { - case FloatSemantics::IEEEHalf: - return "f16"; - case FloatSemantics::BFloat: - return "bf16"; - case FloatSemantics::IEEESingle: - return "f32"; - case FloatSemantics::IEEEDouble: - return "f64"; - case FloatSemantics::IEEEQuad: - return "f128"; - case FloatSemantics::PPCDoubleDouble: - case FloatSemantics::Float8E5M2: - case FloatSemantics::Float8E5M2FNUZ: - case FloatSemantics::Float8E4M3: - case FloatSemantics::Float8E4M3FN: - case FloatSemantics::Float8E4M3FNUZ: - case FloatSemantics::Float8E4M3B11FNUZ: - case FloatSemantics::Float8E3M4: - case FloatSemantics::FloatTF32: - case FloatSemantics::Float8E8M0FNU: - case FloatSemantics::Float6E3M2FN: - case FloatSemantics::Float6E2M3FN: - case FloatSemantics::Float4E2M1FN: - case FloatSemantics::X87DoubleExtended: - case FloatSemantics::Count: - return makeUnexpected(ErrorCode::Unsupported, - "fixed LLVM MIR cannot spell this floating low-level type"); - } - return makeUnexpected(ErrorCode::InternalError, "floating low-level type is unhandled"); + return makeUnexpected(ErrorCode::VerificationError, + "invalid scalar low-level type cannot be printed as LLVM MIR"); } -[[nodiscard]] Expected<std::string> llvmMIRLowLevelType(LLT Type) { +[[nodiscard]] Expected<std::string> llvmMIRLowLevelType(LowLevelType Type) { if (!Type.isValid()) { return makeUnexpected(ErrorCode::VerificationError, "invalid low-level type cannot be printed as LLVM MIR"); diff --git a/backend/lib/CodeGen/MachineCSE.cpp b/backend/lib/CodeGen/MachineCSE.cpp index 52a1484..30129bc 100644 --- a/backend/lib/CodeGen/MachineCSE.cpp +++ b/backend/lib/CodeGen/MachineCSE.cpp @@ -149,24 +149,7 @@ template <typename ValueT> return true; } -[[nodiscard]] bool hasFloatingRegister(const MachineInstr &Instruction, - const MachineRegisterInfo &Registers) { - for (const MachineOperand &Operand : Instruction.operands()) { - const Register *Reg = Operand.getIf<Register>(); - if (Reg == nullptr || !Reg->isVirtual()) - continue; - auto Info = Registers.virtualRegisterInfo(*Reg); - if (Info) { - const auto &Type = Info->get().Type; - if (Type && Type->isFloat()) - return true; - } - } - return false; -} - [[nodiscard]] Expected<bool> isCandidate(const MachineInstr &Instruction, - const MachineFunction &Function, const TargetDescription &Target) { const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction.opcode()); if (Descriptor == nullptr) { @@ -187,8 +170,8 @@ template <typename ValueT> return false; if (!Flags.has(InstructionFlag::MayLoad) && !Instruction.memOperands().empty()) return false; - if (!Instruction.flags().has(MachineInstrFlag::NoFPExcept) && - hasFloatingRegister(Instruction, Function.registerInfo())) { + if (Flags.has(InstructionFlag::MayRaiseFPException) && + !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) { return false; } @@ -351,7 +334,7 @@ MachineCSEPass::runImplementation(MachineFunction &Function, const TargetDescrip Block = Block->next()) { for (MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr;) { MachineInstr *Next = Instruction->next(); - auto Candidate = isCandidate(*Instruction, Function, Target); + auto Candidate = isCandidate(*Instruction, Target); if (!Candidate) return std::unexpected(Candidate.error()); if (!*Candidate) { diff --git a/backend/lib/CodeGen/MachineLICM.cpp b/backend/lib/CodeGen/MachineLICM.cpp index 8a34d3b..627e59f 100644 --- a/backend/lib/CodeGen/MachineLICM.cpp +++ b/backend/lib/CodeGen/MachineLICM.cpp @@ -113,6 +113,9 @@ namespace { hasProtectedAttachment(Instruction) || !Instruction.memOperands().empty()) { return false; } + if (Flags.has(InstructionFlag::MayRaiseFPException) && + !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) + return false; bool HasDefinition = false; for (const MachineOperand &Operand : Instruction.operands()) { @@ -141,14 +144,6 @@ namespace { auto Info = Function.registerInfo().virtualRegisterInfo(*Reg); if (!Info) return std::unexpected(Info.error()); - const auto &Type = Info->get().Type; - if (Type && Type->isFloat() && !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) { - return false; - } - } - if (Stage == MachineCodeMotionStage::PostRegisterAllocation && - !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) { - return false; } return HasDefinition; } diff --git a/backend/lib/CodeGen/MachineMemOperand.cpp b/backend/lib/CodeGen/MachineMemOperand.cpp index cb90e61..0ae6941 100644 --- a/backend/lib/CodeGen/MachineMemOperand.cpp +++ b/backend/lib/CodeGen/MachineMemOperand.cpp @@ -257,7 +257,7 @@ Expected<MachineMemOperand> MachineMemOperand::create(MachineMemOperandDesc Desc return makeUnexpected(ErrorCode::InvalidArgument, "machine memory operand must describe a load or store"); } - if (Description.AddressSpace > LLT::MaxAddressSpace) { + if (Description.AddressSpace > LowLevelType::MaxAddressSpace) { return makeUnexpected(ErrorCode::InvalidArgument, "machine memory operand address space must fit in 24 bits"); } diff --git a/backend/lib/CodeGen/MachineRegisterInfo.cpp b/backend/lib/CodeGen/MachineRegisterInfo.cpp index ccd7d89..a88bfb0 100644 --- a/backend/lib/CodeGen/MachineRegisterInfo.cpp +++ b/backend/lib/CodeGen/MachineRegisterInfo.cpp @@ -68,9 +68,10 @@ Expected<Register> MachineRegisterInfo::createVirtualRegister() { return *Reg; } -Expected<Register> MachineRegisterInfo::createVirtualRegister(LLT Type) { +Expected<Register> MachineRegisterInfo::createVirtualRegister(LowLevelType Type) { if (!Type.isValid()) { - return makeUnexpected(ErrorCode::InvalidArgument, "virtual register type must be a valid LLT"); + return makeUnexpected(ErrorCode::InvalidArgument, + "virtual register type must be a valid LowLevelType"); } auto Reg = createVirtualRegister(); @@ -124,9 +125,10 @@ MachineRegisterInfo::virtualRegisterInfo(Register Reg) const { return std::cref(VirtualRegisters[*Index]); } -Expected<void> MachineRegisterInfo::setType(Register Reg, LLT Type) { +Expected<void> MachineRegisterInfo::setType(Register Reg, LowLevelType Type) { if (!Type.isValid()) { - return makeUnexpected(ErrorCode::InvalidArgument, "virtual register type must be a valid LLT"); + return makeUnexpected(ErrorCode::InvalidArgument, + "virtual register type must be a valid LowLevelType"); } auto Info = virtualRegisterInfo(Reg); if (!Info) diff --git a/backend/lib/CodeGen/MachineSink.cpp b/backend/lib/CodeGen/MachineSink.cpp index 7c540e0..95f902d 100644 --- a/backend/lib/CodeGen/MachineSink.cpp +++ b/backend/lib/CodeGen/MachineSink.cpp @@ -90,6 +90,9 @@ namespace { hasProtectedAttachment(Instruction) || !Instruction.memOperands().empty()) { return false; } + if (Flags.has(InstructionFlag::MayRaiseFPException) && + !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) + return false; bool HasDefinition = false; for (const MachineOperand &Operand : Instruction.operands()) { @@ -118,14 +121,6 @@ namespace { auto Info = Function.registerInfo().virtualRegisterInfo(*Reg); if (!Info) return std::unexpected(Info.error()); - const auto &Type = Info->get().Type; - if (Type && Type->isFloat() && !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) { - return false; - } - } - if (Stage == MachineCodeMotionStage::PostRegisterAllocation && - !Instruction.flags().has(MachineInstrFlag::NoFPExcept)) { - return false; } return HasDefinition; } diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index 725a288..14ce8ef 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -849,7 +849,7 @@ private: MissingVirtualBank |= !Info.Bank; MissingVirtualClass |= !Info.RegClass; if (Info.Type && !Info.Type->isValid()) - return fail("virtual register has an invalid LLT"); + return fail("virtual register has an invalid LowLevelType"); std::unordered_set<PhysicalRegister> Hints; for (const PhysicalRegister Hint : Info.AllocationHints) { @@ -924,7 +924,7 @@ private: Has(MachineFunctionProperty::Legalized) || Has(MachineFunctionProperty::RegBankSelected); if (NeedsTypes && MissingVirtualType) - return fail("typed pipeline stage has a virtual register without LLT"); + return fail("typed pipeline stage has a virtual register without LowLevelType"); if (Options.Mode == MachineVerifierMode::PreLegalizer) { if (!Has(MachineFunctionProperty::IsSSA) || !Has(MachineFunctionProperty::TracksLiveness)) { diff --git a/backend/lib/CodeGen/TargetDescription.cpp b/backend/lib/CodeGen/TargetDescription.cpp index e8c7d79..b9569be 100644 --- a/backend/lib/CodeGen/TargetDescription.cpp +++ b/backend/lib/CodeGen/TargetDescription.cpp @@ -30,7 +30,7 @@ namespace { return Descriptor.Operands.back(); } -[[nodiscard]] std::uint64_t minimumTypeSizeInBits(LLT Type) noexcept { +[[nodiscard]] std::uint64_t minimumTypeSizeInBits(LowLevelType Type) noexcept { if (Type.isToken()) return 0; const std::uint64_t ScalarSize = Type.scalarBitWidth(); diff --git a/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp b/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp index b4d513a..b0c22fc 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVCallLowering.cpp @@ -54,25 +54,22 @@ constexpr std::uint32_t AllowedDirectCallFlags = return Value + Increment; } -[[nodiscard]] std::uint64_t valueSizeBytes(LLT Type) noexcept { +[[nodiscard]] std::uint64_t valueSizeBytes(LowLevelType Type) noexcept { return (static_cast<std::uint64_t>(Type.scalarBitWidth()) + 7U) / 8U; } -[[nodiscard]] bool isSupportedFloat(LLT Type) noexcept { - if (!Type.isFloat()) - return false; - const auto Semantics = Type.floatSemantics(); - return Semantics && - (*Semantics == FloatSemantics::IEEESingle || *Semantics == FloatSemantics::IEEEDouble); +[[nodiscard]] bool isSupportedFloat(const ABIValue &Value) noexcept { + return Value.Category == ABIValueCategory::FloatingPoint && + (Value.Type.scalarBitWidth() == 32 || Value.Type.scalarBitWidth() == 64); } [[nodiscard]] Expected<PhysicalRegister> floatingRegisterView(PhysicalRegister DoubleView, - LLT Type) { - if (!isSupportedFloat(Type)) { + const ABIValue &Value) { + if (!isSupportedFloat(Value)) { return makeUnexpected(ErrorCode::InvalidArgument, "RISC-V floating-register view requires f32 or f64"); } - if (Type.scalarBitWidth() == 64) + if (Value.Type.scalarBitWidth() == 64) return DoubleView; constexpr std::uint32_t FirstDouble = static_cast<std::uint32_t>(PhysicalRegisterID::F0_D); @@ -87,7 +84,7 @@ constexpr std::uint32_t AllowedDirectCallFlags = } [[nodiscard]] bool requiresIntegerTransport(const ABIValue &Value) noexcept { - return !isSupportedFloat(Value.Type) || Value.Flags.has(ABIValueFlag::ByVal) || + return !isSupportedFloat(Value) || Value.Flags.has(ABIValueFlag::ByVal) || Value.Flags.has(ABIValueFlag::StructReturn) || Value.Flags.has(ABIValueFlag::Indirect); } @@ -101,14 +98,21 @@ constexpr std::uint32_t AllowedDirectCallFlags = ErrorCode::Unsupported, "RISC-V ABI accepts explicitly classified integer, pointer, f32, and f64 scalar fragments"); } - if (Value.Type.isFloat() && !isSupportedFloat(Value.Type)) { + if (Value.Category == ABIValueCategory::Invalid || Value.Category >= ABIValueCategory::Count) { + return makeUnexpected(ErrorCode::InvalidArgument, "RISC-V ABI value category is invalid"); + } + if (Value.Category == ABIValueCategory::FloatingPoint && !isSupportedFloat(Value)) { return makeUnexpected(ErrorCode::Unsupported, "RISC-V LP64 ABIs only support f32 and f64 floating fragments"); } + if ((Value.Category == ABIValueCategory::Pointer) != Value.Type.isPointer()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "RISC-V ABI pointer category must match its pointer LowLevelType"); + } if (Value.Type.isPointer() && Value.Type.scalarBitWidth() != 64) { return makeUnexpected(ErrorCode::Unsupported, "RISC-V LP64 ABIs require 64-bit pointers"); } - if ((Value.Type.isInteger() || Value.Type.isAnyScalar()) && Value.Type.scalarBitWidth() < 64) { + if (Value.Category == ABIValueCategory::Integer && Value.Type.scalarBitWidth() < 64) { if (Value.Extension == ABIExtensionKind::None) { return makeUnexpected(ErrorCode::InvalidArgument, "narrow RISC-V ABI integers require an explicit extension kind"); @@ -226,10 +230,9 @@ struct AssignmentState final { bool VariadicStackOnly = false; }; -[[nodiscard]] Expected<CCAssignment> registerAssignment(const ABIValue &Value, - std::size_t ValueIndex, - PhysicalRegister Location, LLT LocationType, - bool IsVariadic, bool IsBitcast) { +[[nodiscard]] Expected<CCAssignment> +registerAssignment(const ABIValue &Value, std::size_t ValueIndex, PhysicalRegister Location, + LowLevelType LocationType, bool IsVariadic, bool IsBitcast) { auto Align = alignment(std::min<std::uint64_t>(Value.OriginalAlignment.bytes(), ABIStackAlignmentBytes)); if (!Align) @@ -254,8 +257,8 @@ struct AssignmentState final { } [[nodiscard]] Expected<CCAssignment> stackAssignment(const ABIValue &Value, std::size_t ValueIndex, - std::uint64_t StackOffset, LLT LocationType, - bool IsVariadic, + std::uint64_t StackOffset, + LowLevelType LocationType, bool IsVariadic, std::uint64_t StackAlignment) { auto Align = alignment(StackAlignment); if (!Align) @@ -282,7 +285,7 @@ struct AssignmentState final { [[nodiscard]] Expected<ArgumentAssignmentResult> assignArguments(std::span<const ABIValue> Values, std::size_t FixedArgumentCount, bool IsVariadic, const CallingConventionInfo &Convention) { - auto I64 = LLT::makeInteger(64); + auto I64 = LowLevelType::makeCategoryNeutralScalar(64); auto StackAlign = alignment(Convention.StackArgumentAlignmentBytes); if (!I64 || !StackAlign) return makeUnexpected(ErrorCode::InternalError, "RISC-V ABI primitive type facts are invalid"); @@ -325,7 +328,7 @@ assignArguments(std::span<const ABIValue> Values, std::size_t FixedArgumentCount false, false); } else { auto View = - floatingRegisterView(Convention.FloatingArgumentRegisters[State.FPR++], Value.Type); + floatingRegisterView(Convention.FloatingArgumentRegisters[State.FPR++], Value); if (!View) return std::unexpected(View.error()); Assignment = registerAssignment(Value, Index + Fragment, *View, Value.Type, false, false); @@ -356,7 +359,7 @@ assignArguments(std::span<const ABIValue> Values, std::size_t FixedArgumentCount const bool HasGPR = !ForceEntireGroupToStack && State.GPR < Convention.IntegerArgumentRegisters.size(); if (HasGPR) { - const bool Bitcast = isSupportedFloat(Value.Type); + const bool Bitcast = isSupportedFloat(Value); auto Assignment = registerAssignment(Value, Index + Fragment, Convention.IntegerArgumentRegisters[State.GPR++], *I64, VariadicArgument, Bitcast); @@ -380,7 +383,7 @@ assignArguments(std::span<const ABIValue> Values, std::size_t FixedArgumentCount if (!AlignedOffset) return std::unexpected(AlignedOffset.error()); State.StackOffset = *AlignedOffset; - const LLT LocationType = isSupportedFloat(Value.Type) ? Value.Type : *I64; + const LowLevelType LocationType = isSupportedFloat(Value) ? Value.Type : *I64; auto Assignment = stackAssignment(Value, Index + Fragment, State.StackOffset, LocationType, VariadicArgument, RequiredAlignment); if (!Assignment) @@ -415,7 +418,7 @@ assignReturns(std::span<const ABIValue> Values, bool RequireRegisters, return makeUnexpected(ErrorCode::Unsupported, "RISC-V direct returns are limited to two explicit fragments"); } - auto I64 = LLT::makeInteger(64); + auto I64 = LowLevelType::makeCategoryNeutralScalar(64); if (!I64) return std::unexpected(I64.error()); @@ -430,17 +433,17 @@ assignReturns(std::span<const ABIValue> Values, bool RequireRegisters, "return fragments cannot carry argument-only ABI flags"); } const bool UseFloatingRegister = - isSupportedFloat(Value.Type) && FPR < Convention.FloatingReturnRegisters.size(); + isSupportedFloat(Value) && FPR < Convention.FloatingReturnRegisters.size(); Expected<CCAssignment> Assignment = makeUnexpected( ErrorCode::Unsupported, "RISC-V calling convention has no return register available"); if (UseFloatingRegister) { - auto View = floatingRegisterView(Convention.FloatingReturnRegisters[FPR++], Value.Type); + auto View = floatingRegisterView(Convention.FloatingReturnRegisters[FPR++], Value); if (!View) return std::unexpected(View.error()); Assignment = registerAssignment(Value, Index, *View, Value.Type, false, false); } else if (GPR < Convention.IntegerReturnRegisters.size()) { Assignment = registerAssignment(Value, Index, Convention.IntegerReturnRegisters[GPR++], *I64, - false, isSupportedFloat(Value.Type)); + false, isSupportedFloat(Value)); } if (!Assignment) return std::unexpected(Assignment.error()); @@ -924,8 +927,9 @@ createMemoryOperand(MachineFunction &Function, MemoryAccessFlags Accesses, std:: if (!Info) return std::unexpected(Info.error()); if (!Info->get().Type || *Info->get().Type != Assignment.ValueType) { - return makeUnexpected(ErrorCode::VerificationError, - "call-lowering plan register LLT differs from MachineRegisterInfo"); + return makeUnexpected( + ErrorCode::VerificationError, + "call-lowering plan register LowLevelType differs from MachineRegisterInfo"); } return {}; }; @@ -952,10 +956,12 @@ createMemoryOperand(MachineFunction &Function, MemoryAccessFlags Accesses, std:: auto Info = Registers.virtualRegisterInfo(CalleeReg); if (!Info) return std::unexpected(Info.error()); - const std::optional<LLT> Type = Info->get().Type; - if (!Type || ((!Type->isPointer() && !Type->isInteger()) || Type->scalarBitWidth() != 64)) { - return makeUnexpected(ErrorCode::VerificationError, - "indirect RISC-V callee requires a 64-bit pointer or integer LLT"); + const std::optional<LowLevelType> Type = Info->get().Type; + if (!Type || ((!Type->isPointer() && !Type->isCategoryNeutralScalar()) || + Type->scalarBitWidth() != 64)) { + return makeUnexpected( + ErrorCode::VerificationError, + "indirect RISC-V callee requires a 64-bit pointer or integer LowLevelType"); } } } diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index a7160b4..e4c937f 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -31,8 +31,8 @@ namespace rcc::riscv { namespace { -[[nodiscard]] std::optional<LLT> registerType(const MachineFunction &Function, - const MachineOperand &Operand) { +[[nodiscard]] std::optional<LowLevelType> registerType(const MachineFunction &Function, + const MachineOperand &Operand) { const Register *Reg = Operand.getIf<Register>(); if (Reg == nullptr || !Reg->isVirtual()) return std::nullopt; @@ -42,43 +42,59 @@ namespace { return Info->get().Type; } -[[nodiscard]] std::optional<LLT> resultType(const MachineFunction &Function, - const MachineInstr &Instruction) { +[[nodiscard]] std::optional<LowLevelType> resultType(const MachineFunction &Function, + const MachineInstr &Instruction) { const MachineOperand *Result = Instruction.operandAt(0); return Result == nullptr ? std::nullopt : registerType(Function, *Result); } -[[nodiscard]] std::optional<LLT> operandType(const MachineFunction &Function, - const MachineInstr &Instruction, std::size_t Index) { +[[nodiscard]] std::optional<LowLevelType> +operandType(const MachineFunction &Function, const MachineInstr &Instruction, std::size_t Index) { const MachineOperand *Operand = Instruction.operandAt(Index); return Operand == nullptr ? std::nullopt : registerType(Function, *Operand); } -[[nodiscard]] bool isRVFloatType(LLT Type) noexcept { - if (!Type.isFloat()) - return false; - const std::optional<FloatSemantics> Semantics = Type.floatSemantics(); - return Semantics && - (*Semantics == FloatSemantics::IEEESingle || *Semantics == FloatSemantics::IEEEDouble); +[[nodiscard]] bool isSupportedFloatingScalar(LowLevelType Type) noexcept { + return Type.isCategoryNeutralScalar() && + (Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64); } -[[nodiscard]] bool isSupportedIntegerType(LLT Type) noexcept { - return ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 && +[[nodiscard]] bool isSupportedIntegerType(LowLevelType Type) noexcept { + return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 && Type.scalarBitWidth() <= 64) || (Type.isPointer() && Type.scalarBitWidth() == 64); } -[[nodiscard]] bool isSupportedIntegerScalar(LLT Type) noexcept { - return (Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 && +[[nodiscard]] bool isSupportedIntegerScalar(LowLevelType Type) noexcept { + return Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 && Type.scalarBitWidth() <= 64; } -[[nodiscard]] bool isScalarGPRType(LLT Type) noexcept { - return ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 && +[[nodiscard]] bool isScalarGPRType(LowLevelType Type) noexcept { + return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 && Type.scalarBitWidth() <= 64) || (Type.isPointer() && Type.scalarBitWidth() == 64); } +[[nodiscard]] constexpr RegisterBankID fprBank() noexcept { + return RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::FPR)); +} + +[[nodiscard]] Expected<RegisterBankID> registerBank(const MachineFunction &Function, Register Reg) { + if (!Reg.isVirtual()) { + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V generic instruction requires a virtual register"); + } + auto Info = Function.registerInfo().virtualRegisterInfo(Reg); + if (!Info) + return std::unexpected(Info.error()); + if (!Info->get().Bank) { + return makeUnexpected(ErrorCode::VerificationError, + "RISC-V instruction selection requires an assigned register bank"); + } + return *Info->get().Bank; +} + [[nodiscard]] bool fitsSigned(std::int64_t Value, std::uint32_t Bits) noexcept { const std::int64_t Minimum = -(std::int64_t{1} << (Bits - 1U)); const std::int64_t Maximum = (std::int64_t{1} << (Bits - 1U)) - 1; @@ -146,9 +162,9 @@ public: const MachineFunction &Function, const TargetDescription &Target) const override { if (Instruction.opcode() == instructionOpcode(InstructionOpcode::G_SLLW)) { - const std::optional<LLT> Type = resultType(Function, Instruction); - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Type = resultType(Function, Instruction); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); return Type && Left && Right && isScalarGPRType(*Type) && Type->scalarBitWidth() == 64 && *Left == *Type && *Right == *Type ? Expected<void>{} @@ -158,9 +174,9 @@ public: if (!isGenericOpcode(Instruction.opcode())) return {}; const GenericOpcode Generic = static_cast<GenericOpcode>(Instruction.opcode().value()); - const std::optional<LLT> Type = resultType(Function, Instruction); + const std::optional<LowLevelType> Type = resultType(Function, Instruction); const auto Integer = [Type] { return Type && isSupportedIntegerType(*Type); }; - const auto Float = [Type] { return Type && isRVFloatType(*Type); }; + const auto Float = [Type] { return Type && isSupportedFloatingScalar(*Type); }; auto Classification = Subtarget.getLegalizerInfo()->classify(Instruction, Function, Target); if (!Classification) return std::unexpected(Classification.error()); @@ -226,8 +242,7 @@ public: const MachineOperand *Immediate = Instruction.operandAt(1); const auto *Floating = Immediate == nullptr ? nullptr : Immediate->getIf<FloatingImmediateOperand>(); - const std::optional<FloatSemantics> Semantics = Type ? Type->floatSemantics() : std::nullopt; - if (!Float() || Floating == nullptr || !Semantics || Floating->Bits.semantics() != *Semantics) + if (!Float() || Floating == nullptr || Floating->Bits.bitWidth() != Type->scalarBitWidth()) return makeUnexpected(ErrorCode::Unsupported, "RISC-V selector requires a matching floating constant"); return {}; @@ -240,7 +255,6 @@ public: case GenericOpcode::G_CONSTANT_FOLD_BARRIER: case GenericOpcode::G_PTRTOINT: case GenericOpcode::G_INTTOPTR: - case GenericOpcode::G_BITCAST: case GenericOpcode::G_TRUNC: case GenericOpcode::G_SEXT: case GenericOpcode::G_SEXT_INREG: @@ -307,7 +321,7 @@ public: if (Instruction.opcode() == instructionOpcode(InstructionOpcode::G_SLLW)) return Instruction.setOpcode(instructionOpcode(InstructionOpcode::SLLW)); const GenericOpcode Generic = static_cast<GenericOpcode>(Instruction.opcode().value()); - const std::optional<LLT> Type = resultType(Function, Instruction); + const std::optional<LowLevelType> Type = resultType(Function, Instruction); const auto SelectDirect = [&Instruction](InstructionOpcode Selected) { return Instruction.setOpcode(instructionOpcode(Selected)); @@ -364,7 +378,7 @@ public: case GenericOpcode::G_PTRMASK: return SelectDirect(InstructionOpcode::AND); case GenericOpcode::G_LOAD: - return selectLoad(Instruction, Type); + return selectLoad(Instruction, Function, Type); case GenericOpcode::G_SEXTLOAD: return selectExtLoad(Instruction, Type, true); case GenericOpcode::G_ZEXTLOAD: @@ -397,8 +411,6 @@ public: case GenericOpcode::G_PTRTOINT: case GenericOpcode::G_INTTOPTR: return Instruction.setOpcode(opcode(GenericOpcode::COPY)); - case GenericOpcode::G_BITCAST: - return selectBitcast(Instruction, Function); case GenericOpcode::G_FADD: return selectRoundingBinary(Instruction, Type, InstructionOpcode::FADD_S, InstructionOpcode::FADD_D); @@ -526,11 +538,17 @@ public: } private: - [[nodiscard]] Expected<Register> createTemporary(MachineFunction &Function, LLT Type, - const TargetDescription &Target) const { + [[nodiscard]] Expected<Register> + createTemporary(MachineFunction &Function, LowLevelType Type, const TargetDescription &Target, + std::optional<RegisterBankID> Bank = std::nullopt) const { auto Temporary = Function.registerInfo().createVirtualRegister(Type); if (!Temporary) return std::unexpected(Temporary.error()); + if (Bank) { + auto SetBank = Function.registerInfo().setRegisterBank(*Temporary, *Bank); + if (!SetBank) + return std::unexpected(SetBank.error()); + } auto Constraint = RegisterBanks.constrainRegister(Function, *Temporary, Target); if (!Constraint) return std::unexpected(Constraint.error()); @@ -624,7 +642,7 @@ private: [[nodiscard]] Expected<Register> normalizeIntegerBefore(MachineInstr &Anchor, MachineFunction &Function, const TargetDescription &Target, - Register Source, LLT Type, + Register Source, LowLevelType Type, bool Signed) const { if (!isSupportedIntegerScalar(Type)) return makeUnexpected(ErrorCode::Unsupported, @@ -689,9 +707,9 @@ private: [[nodiscard]] Expected<MachineInstr *> buildGPRSelectAfter(MachineIRBuilder &Builder, MachineInstr &Anchor, MachineFunction &Function, - const TargetDescription &Target, LLT ValueType, Register Destination, + const TargetDescription &Target, LowLevelType ValueType, Register Destination, Register Condition, Register TrueValue, Register FalseValue) const { - auto IntegerType = LLT::makeInteger(ValueType.scalarBitWidth()); + auto IntegerType = LowLevelType::makeCategoryNeutralScalar(ValueType.scalarBitWidth()); if (!IntegerType) return std::unexpected(IntegerType.error()); auto Mask = createTemporary(Function, *IntegerType, Target); @@ -725,7 +743,7 @@ private: [[nodiscard]] Expected<void> selectDivRem(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, bool Signed) const { + std::optional<LowLevelType> Type, bool Signed) const { const MachineOperand *RemainderOperand = Instruction.operandAt(1); const MachineOperand *LeftOperand = Instruction.operandAt(2); const MachineOperand *RightOperand = Instruction.operandAt(3); @@ -772,7 +790,8 @@ private: [[nodiscard]] Expected<void> selectMultiplyHigh(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, bool Signed) const { + std::optional<LowLevelType> Type, + bool Signed) const { if (!Type) return makeUnexpected(ErrorCode::VerificationError, "RISC-V high multiplication has no result type"); @@ -793,7 +812,7 @@ private: "RISC-V high multiplication has invalid register operands"); const Register DestinationRegister = *Destination; const Register RightRegister = *Right; - auto I64 = LLT::makeInteger(64); + auto I64 = LowLevelType::makeCategoryNeutralScalar(64); if (!I64) return std::unexpected(I64.error()); auto ExtendedLeft = createTemporary(Function, *I64, Target); @@ -868,7 +887,7 @@ private: [[nodiscard]] Expected<void> selectIntegerMinMax(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, GenericOpcode Generic) const { const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *LeftOperand = Instruction.operandAt(1); @@ -880,7 +899,7 @@ private: if (!Type || Destination == nullptr || Left == nullptr || Right == nullptr) return makeUnexpected(ErrorCode::VerificationError, "RISC-V integer min/max has invalid operands"); - auto I1 = LLT::makeInteger(1); + auto I1 = LowLevelType::makeCategoryNeutralScalar(1); if (!I1) return std::unexpected(I1.error()); auto Condition = createTemporary(Function, *I1, Target); @@ -922,7 +941,7 @@ private: [[nodiscard]] Expected<void> selectValue(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type) const { + std::optional<LowLevelType> Type) const { const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *ConditionOperand = Instruction.operandAt(1); const MachineOperand *TrueOperand = Instruction.operandAt(2); @@ -942,7 +961,7 @@ private: const Register DestinationRegister = *Destination; const Register TrueRegister = *TrueValue; const Register FalseRegister = *FalseValue; - auto I1 = LLT::makeInteger(1); + auto I1 = LowLevelType::makeCategoryNeutralScalar(1); if (!I1) return std::unexpected(I1.error()); auto NormalizedCondition = createTemporary(Function, *I1, Target); @@ -964,8 +983,12 @@ private: if (!SetNormalize) return std::unexpected(SetNormalize.error()); + auto DestinationBank = registerBank(Function, DestinationRegister); + if (!DestinationBank) + return std::unexpected(DestinationBank.error()); + MachineIRBuilder Builder(Function, Target); - if (!Type->isFloat()) { + if (*DestinationBank != fprBank()) { auto Selected = buildGPRSelectAfter(Builder, Instruction, Function, Target, *Type, DestinationRegister, *NormalizedCondition, TrueRegister, FalseRegister); @@ -974,7 +997,7 @@ private: return {}; } - auto IntegerType = LLT::makeInteger(Type->scalarBitWidth()); + auto IntegerType = LowLevelType::makeCategoryNeutralScalar(Type->scalarBitWidth()); if (!IntegerType) return std::unexpected(IntegerType.error()); auto IntegerTrue = createTemporary(Function, *IntegerType, Target); @@ -1010,7 +1033,7 @@ private: [[nodiscard]] Expected<void> selectAbsoluteValue(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type) const { + std::optional<LowLevelType> Type) const { const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *SourceOperand = Instruction.operandAt(1); const Register *Destination = @@ -1059,12 +1082,13 @@ private: [[nodiscard]] Expected<std::pair<Register, MachineInstr *>> buildSignedOverflowAfter(MachineIRBuilder &Builder, MachineInstr &Anchor, - MachineFunction &Function, const TargetDescription &Target, LLT Type, - Register Result, Register Left, Register Right, bool IsAdd) const { + MachineFunction &Function, const TargetDescription &Target, + LowLevelType Type, Register Result, Register Left, Register Right, + bool IsAdd) const { auto FirstDifference = createTemporary(Function, Type, Target); auto SecondDifference = createTemporary(Function, Type, Target); auto SignBits = createTemporary(Function, Type, Target); - auto I1 = LLT::makeInteger(1); + auto I1 = LowLevelType::makeCategoryNeutralScalar(1); if (!I1) return std::unexpected(I1.error()); auto Overflow = createTemporary(Function, *I1, Target); @@ -1101,7 +1125,7 @@ private: [[nodiscard]] Expected<void> selectOverflow(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, GenericOpcode Generic) const { const MachineOperand *ResultOperand = Instruction.operandAt(0); const MachineOperand *OverflowOperand = Instruction.operandAt(1); @@ -1183,7 +1207,7 @@ private: return {}; } - auto I64 = LLT::makeInteger(64); + auto I64 = LowLevelType::makeCategoryNeutralScalar(64); if (!I64) return std::unexpected(I64.error()); auto Zero = physicalRegister(PhysicalRegisterID::X0); @@ -1305,7 +1329,7 @@ private: [[nodiscard]] Expected<void> selectExtendedOverflow(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, GenericOpcode Generic) const { const MachineOperand *ResultOperand = Instruction.operandAt(0); const MachineOperand *CarryOutOperand = Instruction.operandAt(1); @@ -1336,7 +1360,7 @@ private: IsAdd ? (IsWord ? InstructionOpcode::ADDW : InstructionOpcode::ADD) : (IsWord ? InstructionOpcode::SUBW : InstructionOpcode::SUB); auto Partial = createTemporary(Function, *Type, Target); - auto I1 = LLT::makeInteger(1); + auto I1 = LowLevelType::makeCategoryNeutralScalar(1); if (!Partial || !I1) return std::unexpected(!Partial ? Partial.error() : I1.error()); auto NormalizedCarry = createTemporary(Function, *I1, Target); @@ -1404,7 +1428,7 @@ private: [[nodiscard]] Expected<void> selectAtomicRMW(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, GenericOpcode Generic) const { const MachineOperand *AddressOperand = Instruction.operandAt(1); const MachineOperand *ValueOperand = Instruction.operandAt(2); @@ -1484,8 +1508,8 @@ private: MachineFunction &Function, const TargetDescription &Target, GenericOpcode Generic, - std::optional<LLT> Type) const { - const std::optional<LLT> SourceType = operandType(Function, Instruction, 1); + std::optional<LowLevelType> Type) const { + const std::optional<LowLevelType> SourceType = operandType(Function, Instruction, 1); const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *SourceOperand = Instruction.operandAt(1); const Register *Destination = @@ -1539,7 +1563,7 @@ private: [[nodiscard]] Expected<void> selectSignExtendInRegister(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type) const { + std::optional<LowLevelType> Type) const { const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *SourceOperand = Instruction.operandAt(1); const Register *Destination = @@ -1610,7 +1634,7 @@ private: DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf<Register>(); const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf<Register>(); - const std::optional<LLT> LeftType = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> LeftType = operandType(Function, Instruction, 2); if (Predicate == nullptr || Predicate->integerPredicate() == nullptr || Destination == nullptr || Left == nullptr || Right == nullptr || !LeftType) return makeUnexpected(ErrorCode::VerificationError, @@ -1779,8 +1803,8 @@ private: DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf<Register>(); const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf<Register>(); - const std::optional<LLT> FloatType = operandType(Function, Instruction, 2); - const std::optional<LLT> ResultType = resultType(Function, Instruction); + const std::optional<LowLevelType> FloatType = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> ResultType = resultType(Function, Instruction); if (Predicate == nullptr || Predicate->floatingPredicate() == nullptr || Destination == nullptr || Left == nullptr || Right == nullptr || !FloatType || !ResultType) return makeUnexpected(ErrorCode::VerificationError, @@ -1951,8 +1975,9 @@ private: [[nodiscard]] Expected<void> selectFloatToInteger(MachineInstr &Instruction, MachineFunction &Function, - std::optional<LLT> Type, bool Unsigned) const { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + std::optional<LowLevelType> Type, + bool Unsigned) const { + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); if (!Type || !Source) return makeUnexpected(ErrorCode::VerificationError, "RISC-V floating-to-integer conversion has invalid types"); @@ -1973,8 +1998,9 @@ private: [[nodiscard]] Expected<void> selectIntegerToFloat(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type, bool Unsigned) const { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + std::optional<LowLevelType> Type, + bool Unsigned) const { + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); const MachineOperand *SourceOperand = Instruction.operandAt(1); const Register *SourceRegister = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>(); @@ -2003,12 +2029,12 @@ private: } [[nodiscard]] Expected<void> selectFloatingMinMax(MachineInstr &Instruction, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, InstructionOpcode Single, InstructionOpcode Double) const { - if (Type && Type->isFloat() && Type->scalarBitWidth() == 32) + if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 32) return Instruction.setOpcode(instructionOpcode(Single)); - if (Type && Type->isFloat() && Type->scalarBitWidth() == 64) + if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64) return Instruction.setOpcode(instructionOpcode(Double)); return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this floating min/max type"); @@ -2068,40 +2094,20 @@ private: return Instruction.setOpcode(instructionOpcode(InstructionOpcode::EBREAK)); } - [[nodiscard]] Expected<void> selectBitcast(MachineInstr &Instruction, - MachineFunction &Function) const { - const std::optional<LLT> DestinationType = resultType(Function, Instruction); - const std::optional<LLT> SourceType = operandType(Function, Instruction, 1); - if (!DestinationType || !SourceType) - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V bitcast has invalid register types"); - if (DestinationType->isInteger() && SourceType->isFloat()) { - return Instruction.setOpcode(instructionOpcode(SourceType->scalarBitWidth() == 32 - ? InstructionOpcode::FMV_X_W - : InstructionOpcode::FMV_X_D)); - } - if (DestinationType->isFloat() && SourceType->isInteger()) { - return Instruction.setOpcode(instructionOpcode(DestinationType->scalarBitWidth() == 32 - ? InstructionOpcode::FMV_W_X - : InstructionOpcode::FMV_D_X)); - } - return makeUnexpected(ErrorCode::Unsupported, "RISC-V bitcast pair is unsupported"); - } - [[nodiscard]] Expected<void> selectIntegerBinary(MachineInstr &Instruction, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, InstructionOpcode DoubleWord, InstructionOpcode Word) const { if (!Type || !isSupportedIntegerType(*Type)) return makeUnexpected(ErrorCode::Unsupported, "RISC-V integer instruction requires a supported scalar integer"); - const bool IsWord = Type->isInteger() && Type->scalarBitWidth() <= 32; + const bool IsWord = Type->isCategoryNeutralScalar() && Type->scalarBitWidth() <= 32; return Instruction.setOpcode(instructionOpcode(IsWord ? Word : DoubleWord)); } [[nodiscard]] Expected<void> selectNormalizedIntegerBinary(MachineInstr &Instruction, MachineFunction &Function, - const TargetDescription &Target, std::optional<LLT> Type, + const TargetDescription &Target, std::optional<LowLevelType> Type, InstructionOpcode DoubleWord, InstructionOpcode Word, bool Signed, bool NormalizeRight) const { const MachineOperand *LeftOperand = Instruction.operandAt(1); @@ -2134,8 +2140,8 @@ private: return Instruction.setOpcode(instructionOpcode(IsWord ? Word : DoubleWord)); } - [[nodiscard]] Expected<void> selectLoad(MachineInstr &Instruction, - std::optional<LLT> Type) const { + [[nodiscard]] Expected<void> selectLoad(MachineInstr &Instruction, MachineFunction &Function, + std::optional<LowLevelType> Type) const { if (!Type) return makeUnexpected(ErrorCode::VerificationError, "load result has no virtual-register type"); @@ -2143,8 +2149,16 @@ private: if (!Bytes) return makeUnexpected(ErrorCode::Unsupported, "RISC-V load size does not match its result type"); + const MachineOperand *DestinationOperand = Instruction.operandAt(0); + const Register *Destination = + DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); + if (Destination == nullptr) + return makeUnexpected(ErrorCode::VerificationError, "RISC-V load has no destination"); + auto Bank = registerBank(Function, *Destination); + if (!Bank) + return std::unexpected(Bank.error()); if (Instruction.memOperands().front()->isAtomic()) { - if (!isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8)) + if (*Bank == fprBank() || !isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8)) return makeUnexpected(ErrorCode::Unsupported, "RISC-V atomic load requires a 32-bit or 64-bit GPR value"); return Instruction.setOpcode( @@ -2153,7 +2167,7 @@ private: auto AppendOffset = appendImmediate(Instruction, 0); if (!AppendOffset) return std::unexpected(AppendOffset.error()); - if (isSupportedIntegerType(*Type)) { + if (*Bank != fprBank() && isSupportedIntegerType(*Type)) { const InstructionOpcode Selected = *Bytes == 1 ? InstructionOpcode::LB : *Bytes == 2 ? InstructionOpcode::LH : *Bytes == 4 ? InstructionOpcode::LW @@ -2163,15 +2177,15 @@ private: return makeUnexpected(ErrorCode::Unsupported, "RISC-V integer load width is unsupported"); return Instruction.setOpcode(instructionOpcode(Selected)); } - if (Type->isFloat() && Type->scalarBitWidth() == 32) + if (*Bank == fprBank() && Type->scalarBitWidth() == 32 && *Bytes == 4) return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FLW)); - if (Type->isFloat() && Type->scalarBitWidth() == 64) + if (*Bank == fprBank() && Type->scalarBitWidth() == 64 && *Bytes == 8) return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FLD)); return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this generic load type"); } - [[nodiscard]] Expected<void> selectExtLoad(MachineInstr &Instruction, std::optional<LLT> Type, - bool Signed) const { + [[nodiscard]] Expected<void> selectExtLoad(MachineInstr &Instruction, + std::optional<LowLevelType> Type, bool Signed) const { if (!Type || !isSupportedIntegerType(*Type)) return makeUnexpected(ErrorCode::Unsupported, "RISC-V extension load requires an integer result"); @@ -2201,10 +2215,10 @@ private: return makeUnexpected(ErrorCode::VerificationError, "RISC-V floating extension load has no destination register"); const Register DestinationRegister = *Destination; - auto F32 = LLT::makeFloat(FloatSemantics::IEEESingle); + auto F32 = LowLevelType::makeCategoryNeutralScalar(32); if (!F32) return std::unexpected(F32.error()); - auto Temporary = createTemporary(Function, *F32, Target); + auto Temporary = createTemporary(Function, *F32, Target, fprBank()); if (!Temporary) return std::unexpected(Temporary.error()); auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary); @@ -2233,10 +2247,10 @@ private: return makeUnexpected(ErrorCode::VerificationError, "RISC-V floating truncation store has no value register"); const Register ValueRegister = *Value; - auto F32 = LLT::makeFloat(FloatSemantics::IEEESingle); + auto F32 = LowLevelType::makeCategoryNeutralScalar(32); if (!F32) return std::unexpected(F32.error()); - auto Temporary = createTemporary(Function, *F32, Target); + auto Temporary = createTemporary(Function, *F32, Target, fprBank()); if (!Temporary) return std::unexpected(Temporary.error()); MachineIRBuilder Builder(Function, Target); @@ -2270,7 +2284,7 @@ private: [[nodiscard]] Expected<void> selectStore(MachineInstr &Instruction, MachineFunction &Function) const { const MachineOperand *Value = Instruction.operandAt(0); - const std::optional<LLT> Type = + const std::optional<LowLevelType> Type = Value == nullptr ? std::nullopt : registerType(Function, *Value); if (!Type) return makeUnexpected(ErrorCode::VerificationError, @@ -2279,8 +2293,14 @@ private: if (!Bytes) return makeUnexpected(ErrorCode::Unsupported, "RISC-V store size does not match its value type"); + const Register *ValueRegister = Value->getIf<Register>(); + if (ValueRegister == nullptr) + return makeUnexpected(ErrorCode::VerificationError, "RISC-V store has no value register"); + auto Bank = registerBank(Function, *ValueRegister); + if (!Bank) + return std::unexpected(Bank.error()); if (Instruction.memOperands().front()->isAtomic()) { - if (!isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8)) + if (*Bank == fprBank() || !isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8)) return makeUnexpected(ErrorCode::Unsupported, "RISC-V atomic store requires a 32-bit or 64-bit GPR value"); auto Zero = physicalRegister(PhysicalRegisterID::X0); @@ -2295,7 +2315,7 @@ private: auto AppendOffset = appendImmediate(Instruction, 0); if (!AppendOffset) return std::unexpected(AppendOffset.error()); - if (isSupportedIntegerType(*Type)) { + if (*Bank != fprBank() && isSupportedIntegerType(*Type)) { const InstructionOpcode Selected = *Bytes == 1 ? InstructionOpcode::SB : *Bytes == 2 ? InstructionOpcode::SH : *Bytes == 4 ? InstructionOpcode::SW @@ -2305,9 +2325,9 @@ private: return makeUnexpected(ErrorCode::Unsupported, "RISC-V integer store width is unsupported"); return Instruction.setOpcode(instructionOpcode(Selected)); } - if (Type->isFloat() && Type->scalarBitWidth() == 32) + if (*Bank == fprBank() && Type->scalarBitWidth() == 32 && *Bytes == 4) return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FSW)); - if (Type->isFloat() && Type->scalarBitWidth() == 64) + if (*Bank == fprBank() && Type->scalarBitWidth() == 64 && *Bytes == 8) return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FSD)); return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this generic store type"); } @@ -2335,7 +2355,7 @@ private: [[nodiscard]] Expected<void> selectIntegerConstant(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type) const { + std::optional<LowLevelType> Type) const { if (!Type || !isSupportedIntegerType(*Type)) { return makeUnexpected(ErrorCode::Unsupported, "RISC-V constant selection requires an i1-i64 or pointer result"); @@ -2357,7 +2377,7 @@ private: const Register Destination = *DestinationValue; const std::int64_t Value = *ImmediateValue; const std::uint32_t ImmediateTargetFlags = ImmediateOperand->targetFlags(); - const bool IsWord = Type->isInteger() && Type->scalarBitWidth() <= 32; + const bool IsWord = Type->isCategoryNeutralScalar() && Type->scalarBitWidth() <= 32; const InstructionOpcode AddImmediate = IsWord ? InstructionOpcode::ADDIW : InstructionOpcode::ADDI; const InstructionOpcode ShiftLeftImmediate = @@ -2488,14 +2508,13 @@ private: [[nodiscard]] Expected<void> selectFloatingConstant(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional<LLT> Type) const { - if (!Type || !isRVFloatType(*Type)) + std::optional<LowLevelType> Type) const { + if (!Type || !isSupportedFloatingScalar(*Type)) return makeUnexpected(ErrorCode::Unsupported, "RISC-V floating constant requires f32 or f64"); const MachineOperand *Immediate = Instruction.operandAt(1); const auto *Floating = Immediate == nullptr ? nullptr : Immediate->getIf<FloatingImmediateOperand>(); - const std::optional<FloatSemantics> Semantics = Type->floatSemantics(); - if (Floating == nullptr || !Semantics || Floating->Bits.semantics() != *Semantics) + if (Floating == nullptr || Floating->Bits.bitWidth() != Type->scalarBitWidth()) return makeUnexpected(ErrorCode::VerificationError, "RISC-V floating constant has mismatched bit semantics"); const MachineOperand *DestinationOperand = Instruction.operandAt(0); @@ -2511,7 +2530,7 @@ private: auto Integer = APInt::fromUnsigned(64, Bits); if (!Integer) return std::unexpected(Integer.error()); - auto IntegerType = LLT::makeInteger(64); + auto IntegerType = LowLevelType::makeCategoryNeutralScalar(64); if (!IntegerType) return std::unexpected(IntegerType.error()); auto Temporary = createTemporary(Function, *IntegerType, Target); @@ -2564,35 +2583,35 @@ private: } [[nodiscard]] Expected<void> selectRoundingBinary(MachineInstr &Instruction, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, InstructionOpcode Single, InstructionOpcode Double) const { auto RoundingMode = appendImmediate(Instruction, 0); if (!RoundingMode) return std::unexpected(RoundingMode.error()); - if (Type && Type->isFloat() && Type->scalarBitWidth() == 32) + if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 32) return Instruction.setOpcode(instructionOpcode(Single)); - if (Type && Type->isFloat() && Type->scalarBitWidth() == 64) + if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64) return Instruction.setOpcode(instructionOpcode(Double)); return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this floating binary type"); } [[nodiscard]] Expected<void> selectRoundingTernary(MachineInstr &Instruction, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, InstructionOpcode Single, InstructionOpcode Double) const { return selectRoundingBinary(Instruction, Type, Single, Double); } [[nodiscard]] Expected<void> selectRoundingUnary(MachineInstr &Instruction, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, InstructionOpcode Single, InstructionOpcode Double) const { return selectRoundingBinary(Instruction, Type, Single, Double); } [[nodiscard]] Expected<void> selectSignInjection(MachineInstr &Instruction, - std::optional<LLT> Type, + std::optional<LowLevelType> Type, InstructionOpcode Single, InstructionOpcode Double) const { const MachineOperand *Source = Instruction.operandAt(1); @@ -2603,9 +2622,9 @@ private: auto Duplicate = insertVirtualUse(Instruction, 2, *SourceReg); if (!Duplicate) return std::unexpected(Duplicate.error()); - if (Type && Type->isFloat() && Type->scalarBitWidth() == 32) + if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 32) return Instruction.setOpcode(instructionOpcode(Single)); - if (Type && Type->isFloat() && Type->scalarBitWidth() == 64) + if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64) return Instruction.setOpcode(instructionOpcode(Double)); return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this floating unary type"); } diff --git a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp index eace5ad..1a29ebf 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp @@ -31,7 +31,8 @@ namespace rcc::riscv { namespace { -[[nodiscard]] std::optional<LLT> registerType(const MachineFunction &Function, Register Reg) { +[[nodiscard]] std::optional<LowLevelType> registerType(const MachineFunction &Function, + Register Reg) { if (!Reg.isVirtual()) return std::nullopt; auto Info = Function.registerInfo().virtualRegisterInfo(Reg); @@ -40,62 +41,60 @@ namespace { return Info->get().Type; } -[[nodiscard]] std::optional<LLT> registerType(const MachineFunction &Function, - const MachineOperand &Operand) { +[[nodiscard]] std::optional<LowLevelType> registerType(const MachineFunction &Function, + const MachineOperand &Operand) { const Register *Reg = Operand.getIf<Register>(); return Reg == nullptr ? std::nullopt : registerType(Function, *Reg); } -[[nodiscard]] std::optional<LLT> resultType(const MachineFunction &Function, - const MachineInstr &Instruction) { +[[nodiscard]] std::optional<LowLevelType> resultType(const MachineFunction &Function, + const MachineInstr &Instruction) { const MachineOperand *Result = Instruction.operandAt(0); return Result == nullptr ? std::nullopt : registerType(Function, *Result); } -[[nodiscard]] std::optional<LLT> operandType(const MachineFunction &Function, - const MachineInstr &Instruction, std::size_t Index) { +[[nodiscard]] std::optional<LowLevelType> +operandType(const MachineFunction &Function, const MachineInstr &Instruction, std::size_t Index) { const MachineOperand *Operand = Instruction.operandAt(Index); return Operand == nullptr ? std::nullopt : registerType(Function, *Operand); } -[[nodiscard]] bool isRVFloatType(LLT Type) noexcept { - if (!Type.isFloat()) - return false; - const std::optional<FloatSemantics> Semantics = Type.floatSemantics(); - return Semantics && - (*Semantics == FloatSemantics::IEEESingle || *Semantics == FloatSemantics::IEEEDouble); +[[nodiscard]] bool isSupportedFloatingScalar(LowLevelType Type) noexcept { + return Type.isCategoryNeutralScalar() && + (Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64); } -[[nodiscard]] bool isSupportedIntegerType(LLT Type) noexcept { - return ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 && +[[nodiscard]] bool isSupportedIntegerType(LowLevelType Type) noexcept { + return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 && Type.scalarBitWidth() <= 64) || (Type.isPointer() && Type.scalarBitWidth() == 64); } -[[nodiscard]] bool isSupportedIntegerScalar(LLT Type) noexcept { - return (Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 && +[[nodiscard]] bool isSupportedIntegerScalar(LowLevelType Type) noexcept { + return Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 && Type.scalarBitWidth() <= 64; } -[[nodiscard]] bool isNativeIntegerScalar(LLT Type) noexcept { - return (Type.isInteger() || Type.isAnyScalar()) && +[[nodiscard]] bool isNativeIntegerScalar(LowLevelType Type) noexcept { + return Type.isCategoryNeutralScalar() && (Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64); } -[[nodiscard]] bool isScalarGPRType(LLT Type) noexcept { - return ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 && +[[nodiscard]] bool isScalarGPRType(LowLevelType Type) noexcept { + return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 && Type.scalarBitWidth() <= 64) || (Type.isPointer() && Type.scalarBitWidth() == 64); } -[[nodiscard]] bool isI1Type(LLT Type) noexcept { - return (Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() == 1; +[[nodiscard]] bool isI1Type(LowLevelType Type) noexcept { + return Type.isCategoryNeutralScalar() && Type.scalarBitWidth() == 1; } -[[nodiscard]] bool isScalarIntegerExtension(LLT Destination, LLT Source) noexcept { - return (Destination.isInteger() || Destination.isAnyScalar()) && - (Source.isInteger() || Source.isAnyScalar()) && Destination.scalarBitWidth() != 0 && - Source.scalarBitWidth() != 0 && Source.scalarBitWidth() < Destination.scalarBitWidth() && +[[nodiscard]] bool isScalarIntegerExtension(LowLevelType Destination, + LowLevelType Source) noexcept { + return Destination.isCategoryNeutralScalar() && Source.isCategoryNeutralScalar() && + Destination.scalarBitWidth() != 0 && Source.scalarBitWidth() != 0 && + Source.scalarBitWidth() < Destination.scalarBitWidth() && Destination.scalarBitWidth() <= 64; } @@ -394,11 +393,12 @@ wideConstantUnmergePlan(const MachineInstr &Constant, const MachineFunction &Fun std::uint64_t Value); [[nodiscard]] Expected<Register> buildBinaryBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - GenericOpcode Generic, LLT Type, Register Left, - Register Right); + GenericOpcode Generic, LowLevelType Type, + Register Left, Register Right); [[nodiscard]] Expected<Register> buildUnaryBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - GenericOpcode Generic, LLT Type, Register Source); + GenericOpcode Generic, LowLevelType Type, + Register Source); [[nodiscard]] Expected<void> eraseInstruction(MachineInstr &Instruction); @@ -462,7 +462,7 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun const Register *Narrow = NarrowOperand == nullptr ? nullptr : NarrowOperand->getIf<Register>(); const MachineOperand *WideOperand = Truncation->operandAt(1); const Register *Wide = WideOperand == nullptr ? nullptr : WideOperand->getIf<Register>(); - const std::optional<LLT> WideType = + const std::optional<LowLevelType> WideType = WideOperand == nullptr ? std::nullopt : registerType(Function, *WideOperand); if (Narrow == nullptr || Wide == nullptr || !Wide->isVirtual() || !WideType || *WideType != *DestinationType || singleRegisterUse(Function, *Narrow) != OnlyUse) @@ -533,7 +533,7 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun if (Destination == nullptr || !Destination->isVirtual() || Immediate == nullptr) return makeUnexpected(ErrorCode::VerificationError, "RISC-V narrow constant legalization has invalid operands"); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto SetType = Function.registerInfo().setType(*Destination, *Type); @@ -554,7 +554,8 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun [[nodiscard]] Expected<Register> widenAtomicCompareExchangeSource(MachineInstr &Instruction, MachineFunction &Function, MachineIRBuilder &Builder, - Register Source, LLT WideType) { + Register Source, + LowLevelType WideType) { const auto SourceType = registerType(Function, Source); if (!SourceType) return makeUnexpected(ErrorCode::VerificationError, @@ -578,7 +579,7 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun [[nodiscard]] Expected<void> lowerAtomicCompareExchange(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional<LLT> OriginalType = resultType(Function, Instruction); + const std::optional<LowLevelType> OriginalType = resultType(Function, Instruction); const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *CompareOperand = Instruction.operandAt(2); const MachineOperand *NewValueOperand = Instruction.operandAt(3); @@ -593,7 +594,7 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun "RISC-V narrow compare-exchange has invalid operands"); const Register OriginalDestination = *Destination; - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); MachineIRBuilder Builder(Function, Target); @@ -610,7 +611,7 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun MachineInstr *FoldedExtension = singleRegisterUse(Function, OriginalDestination); if (FoldedExtension != nullptr && FoldedExtension->opcode() == opcode(GenericOpcode::G_ANYEXT) && operandType(Function, *FoldedExtension, 0) - .transform([](LLT Type) { return Type.scalarBitWidth() == 64; }) + .transform([](LowLevelType Type) { return Type.scalarBitWidth() == 64; }) .value_or(false)) { const MachineOperand *WideDestinationOperand = FoldedExtension->operandAt(0); const Register *FoldedDestination = @@ -668,7 +669,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction const Register *Compare = CompareOperand == nullptr ? nullptr : CompareOperand->getIf<Register>(); const Register *NewValue = NewValueOperand == nullptr ? nullptr : NewValueOperand->getIf<Register>(); - const std::optional<LLT> ValueType = resultType(Function, Instruction); + const std::optional<LowLevelType> ValueType = resultType(Function, Instruction); if (OldValue == nullptr || Success == nullptr || Address == nullptr || Compare == nullptr || NewValue == nullptr || !ValueType || Instruction.memOperands().size() != 1) return makeUnexpected(ErrorCode::VerificationError, @@ -727,7 +728,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction [[nodiscard]] Expected<Register> widenIntegerCompareSource(MachineInstr &Instruction, MachineFunction &Function, MachineIRBuilder &Builder, - Register Source, LLT WideType) { + Register Source, LowLevelType WideType) { const auto SourceType = registerType(Function, Source); if (!SourceType) return makeUnexpected(ErrorCode::VerificationError, @@ -751,7 +752,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction const MachineOperand *ExtendedOperand = User->operandAt(0); const Register *Extended = ExtendedOperand == nullptr ? nullptr : ExtendedOperand->getIf<Register>(); - const std::optional<LLT> ExtendedType = + const std::optional<LowLevelType> ExtendedType = ExtendedOperand == nullptr ? std::nullopt : registerType(Function, *ExtendedOperand); if (Extended == nullptr || !ExtendedType || *ExtendedType != WideType || (Def == nullptr || (Def->opcode() != opcode(GenericOpcode::G_CONSTANT) && @@ -778,7 +779,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction Def->operandCount() == 2) { const MachineOperand *WideOperand = Def->operandAt(1); const Register *WideSource = WideOperand == nullptr ? nullptr : WideOperand->getIf<Register>(); - const std::optional<LLT> ExistingWideType = + const std::optional<LowLevelType> ExistingWideType = WideOperand == nullptr ? std::nullopt : registerType(Function, *WideOperand); if (WideSource != nullptr && ExistingWideType && *ExistingWideType == WideType) { auto Result = Function.registerInfo().createVirtualRegister(WideType); @@ -825,7 +826,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction const Register OriginalLeft = *Left; const Register OriginalRight = *Right; - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); MachineIRBuilder Builder(Function, Target); @@ -855,7 +856,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction FoldedExtension->opcode() == opcode(GenericOpcode::G_SEXT) || FoldedExtension->opcode() == opcode(GenericOpcode::G_ZEXT)) && operandType(Function, *FoldedExtension, 0) - .transform([](LLT Type) { return Type.scalarBitWidth() == 64; }) + .transform([](LowLevelType Type) { return Type.scalarBitWidth() == 64; }) .value_or(false)) { const MachineOperand *ExtendedOperand = FoldedExtension->operandAt(0); const Register *Extended = @@ -923,7 +924,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction const std::uint64_t Mask = Plan->SourceWidth == 64 ? std::numeric_limits<std::uint64_t>::max() : (std::uint64_t{1} << Plan->SourceWidth) - 1U; - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); MachineIRBuilder Builder(Function, Target); @@ -964,7 +965,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction if (Plan->SourceWidth == 32 && (Plan->Generic == GenericOpcode::G_ADD || Plan->Generic == GenericOpcode::G_SUB)) { - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); auto Temporary = Function.registerInfo().createVirtualRegister(*WideType); @@ -1043,7 +1044,7 @@ lowerAtomicCompareExchangeWithSuccess(MachineInstr &Instruction, MachineFunction if (!PoolIndex) return std::unexpected(PoolIndex.error()); - auto PointerType = LLT::makePointer(0, 64); + auto PointerType = LowLevelType::makePointer(0, 64); if (!PointerType) return std::unexpected(PointerType.error()); auto Address = Function.registerInfo().createVirtualRegister(*PointerType); @@ -1143,11 +1144,11 @@ memoryAccessBytes(const MachineInstr &Instruction) noexcept { return Description.Size.minimumBytes(); } -[[nodiscard]] bool memoryMatchesType(const MachineInstr &Instruction, LLT Type) noexcept { +[[nodiscard]] bool memoryMatchesType(const MachineInstr &Instruction, LowLevelType Type) noexcept { const auto Bytes = memoryAccessBytes(Instruction); - if (!Bytes || (!isSupportedIntegerType(Type) && !isRVFloatType(Type))) + if (!Bytes || (!isSupportedIntegerType(Type) && !isSupportedFloatingScalar(Type))) return false; - if (isRVFloatType(Type)) + if (isSupportedFloatingScalar(Type)) return Type.scalarBitWidth() == 32 ? *Bytes == 4 : *Bytes == 8; const std::uint64_t ValueBytes = (Type.scalarBitWidth() + 7U) / 8U; return (*Bytes == 1 || *Bytes == 2 || *Bytes == 4 || *Bytes == 8) && *Bytes <= ValueBytes; @@ -1224,7 +1225,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, MachineInstr &Anchor, std::uint32_t Width, std::uint64_t Value) { - auto Type = LLT::makeAnyScalar(Width); + auto Type = LowLevelType::makeCategoryNeutralScalar(Width); if (!Type) return std::unexpected(Type.error()); auto Result = Builder.function().registerInfo().createVirtualRegister(*Type); @@ -1250,7 +1251,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, } [[nodiscard]] Expected<Register> buildUnaryBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - GenericOpcode Generic, LLT Type, + GenericOpcode Generic, LowLevelType Type, Register Source) { auto Result = Builder.function().registerInfo().createVirtualRegister(Type); if (!Result) @@ -1272,8 +1273,8 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, } [[nodiscard]] Expected<Register> buildBinaryBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - GenericOpcode Generic, LLT Type, Register Left, - Register Right) { + GenericOpcode Generic, LowLevelType Type, + Register Left, Register Right) { auto Result = Builder.function().registerInfo().createVirtualRegister(Type); if (!Result) return std::unexpected(Result.error()); @@ -1321,7 +1322,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, [[nodiscard]] Expected<void> widenNarrowMultiply(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional<LLT> Type = resultType(Function, Instruction); + const std::optional<LowLevelType> Type = resultType(Function, Instruction); const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *LeftOperand = Instruction.operandAt(1); const MachineOperand *RightOperand = Instruction.operandAt(2); @@ -1342,7 +1343,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, return foldNarrowAnyExtBinary(*Extension, Function, Target); } - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); MachineIRBuilder Builder(Function, Target); @@ -1365,7 +1366,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, const TargetDescription &Target, CallingConvention Convention, const TargetCallLowering &CallLowering) { - const std::optional<LLT> Type = resultType(Function, Instruction); + const std::optional<LowLevelType> Type = resultType(Function, Instruction); const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *LeftOperand = Instruction.operandAt(1); const MachineOperand *RightOperand = Instruction.operandAt(2); @@ -1387,6 +1388,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, return ABIValue{ .Value = Reg, .Type = Type, + .Category = ABIValueCategory::Integer, .OriginalValue = Number, .FragmentIndex = 0, .FragmentCount = 1, @@ -1488,7 +1490,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, } } } - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); return buildUnaryBefore(Builder, Anchor, GenericOpcode::G_ZEXT, *WideType, Source); @@ -1562,7 +1564,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, [[nodiscard]] Expected<void> lowerMergeValues(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional<LLT> DestinationType = resultType(Function, Instruction); + const std::optional<LowLevelType> DestinationType = resultType(Function, Instruction); if (!DestinationType || DestinationType->scalarBitWidth() == 0) return makeUnexpected(ErrorCode::VerificationError, "RISC-V merge destination has no scalar type"); @@ -1582,7 +1584,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, MachineInstr *Use = singleUseInstruction(Function, *Destination); if (Use != nullptr && Use->opcode() == opcode(GenericOpcode::G_ZEXT) && operandType(Function, *Use, 0) - .transform([](LLT Type) { return Type.scalarBitWidth() == 64; }) + .transform([](LowLevelType Type) { return Type.scalarBitWidth() == 64; }) .value_or(false)) { const MachineOperand *ExtendedOperand = Use->operandAt(0); const Register *Extended = @@ -1594,7 +1596,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, } } - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); MachineIRBuilder Builder(Function, Target); @@ -1613,7 +1615,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, Terms.push_back(*WideSource); continue; } - const std::optional<LLT> SourceType = registerType(Function, *Operand); + const std::optional<LowLevelType> SourceType = registerType(Function, *Operand); if (!SourceType) return makeUnexpected(ErrorCode::VerificationError, "RISC-V merge source has no scalar type"); const std::uint64_t Shift = @@ -1758,8 +1760,8 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, return makeUnexpected(ErrorCode::VerificationError, "RISC-V unmerge has invalid register operands"); const std::size_t OutputCount = Instruction.operandCount() - 1U; - const std::optional<LLT> OutputType = operandType(Function, Instruction, 0); - const std::optional<LLT> SourceType = operandType(Function, Instruction, OutputCount); + const std::optional<LowLevelType> OutputType = operandType(Function, Instruction, 0); + const std::optional<LowLevelType> SourceType = operandType(Function, Instruction, OutputCount); if (!OutputType || !SourceType) return makeUnexpected(ErrorCode::VerificationError, "RISC-V unmerge operands have no scalar types"); @@ -1770,7 +1772,7 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>(); if (Source == nullptr) return makeUnexpected(ErrorCode::VerificationError, "RISC-V unmerge source is not a register"); - auto WideType = LLT::makeAnyScalar(64); + auto WideType = LowLevelType::makeCategoryNeutralScalar(64); if (!WideType) return std::unexpected(WideType.error()); MachineIRBuilder Builder(Function, Target); @@ -1794,11 +1796,11 @@ void eraseDeadArtifacts(std::span<MachineInstr *const> Candidates, } MachineInstr *Extension = singleUseInstruction(Function, *Output); - const bool FoldZExt = Extension != nullptr && - Extension->opcode() == opcode(GenericOpcode::G_ZEXT) && - operandType(Function, *Extension, 0) - .transform([](LLT Type) { return Type.scalarBitWidth() == 64; }) - .value_or(false); + const bool FoldZExt = + Extension != nullptr && Extension->opcode() == opcode(GenericOpcode::G_ZEXT) && + operandType(Function, *Extension, 0) + .transform([](LowLevelType Type) { return Type.scalarBitWidth() == 64; }) + .value_or(false); if (FoldZExt) { const MachineOperand *ExtendedOperand = Extension->operandAt(0); const Register *Extended = @@ -1851,7 +1853,7 @@ collectWideValueParts(Register Value, MachineFunction &Function, unsigned Depth const auto Type = registerType(Function, Value); if (!Type) return makeUnexpected(ErrorCode::VerificationError, "RISC-V wide value has no scalar type"); - if ((!Type->isInteger() && !Type->isAnyScalar()) || Type->scalarBitWidth() == 0) + if (!Type->isCategoryNeutralScalar() || Type->scalarBitWidth() == 0) return makeUnexpected(ErrorCode::Unsupported, "RISC-V wide-value decomposition requires an integer scalar"); if (Type->scalarBitWidth() <= 64) @@ -1869,7 +1871,7 @@ collectWideValueParts(Register Value, MachineFunction &Function, unsigned Depth for (std::size_t Index = 1; Index < Def->operandCount(); ++Index) { const MachineOperand *Operand = Def->operandAt(Index); const Register *Part = Operand == nullptr ? nullptr : Operand->getIf<Register>(); - const std::optional<LLT> PartType = + const std::optional<LowLevelType> PartType = Operand == nullptr ? std::nullopt : registerType(Function, *Operand); if (Part == nullptr || !PartType || PartType->scalarBitWidth() != 64) return makeUnexpected(ErrorCode::Unsupported, @@ -1932,7 +1934,7 @@ struct WideResultPlan final { for (std::size_t Index = 0; Index < RequiredParts; ++Index) { const MachineOperand *Operand = Use->operandAt(Index); const Register *Output = Operand == nullptr ? nullptr : Operand->getIf<Register>(); - const std::optional<LLT> Type = + const std::optional<LowLevelType> Type = Operand == nullptr ? std::nullopt : registerType(Function, *Operand); if (Output == nullptr || !Type || Type->scalarBitWidth() != 64) return makeUnexpected(ErrorCode::Unsupported, @@ -1946,7 +1948,7 @@ struct WideResultPlan final { MachineInstr &Anchor, IntegerPredicate Predicate, Register Left, Register Right) { - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto Result = Builder.function().registerInfo().createVirtualRegister(*Type); @@ -1973,8 +1975,8 @@ struct WideResultPlan final { } [[nodiscard]] Expected<Register> buildSelectBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - LLT Type, Register Condition, Register TrueValue, - Register FalseValue) { + LowLevelType Type, Register Condition, + Register TrueValue, Register FalseValue) { auto Result = Builder.function().registerInfo().createVirtualRegister(Type); if (!Result) return std::unexpected(Result.error()); @@ -2007,7 +2009,7 @@ struct TwoLimbShiftResult final { emitTwoLimbLeftShiftBody(MachineIRBuilder &Builder, MachineInstr &Anchor, Register Low, Register High, Register Amount, Register AmountExcess, Register AmountLack, Register Zero, Register IsShort, Register IsZero) { - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto LowShort = buildBinaryBefore(Builder, Anchor, GenericOpcode::G_SHL, *Type, Low, Amount); @@ -2042,7 +2044,7 @@ emitTwoLimbLeftShiftBody(MachineIRBuilder &Builder, MachineInstr &Anchor, Regist [[nodiscard]] Expected<TwoLimbShiftResult> emitTwoLimbLeftShift(MachineIRBuilder &Builder, MachineInstr &Anchor, Register Low, Register High, Register Amount) { - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto Boundary = buildIntegerConstantBefore(Builder, Anchor, 64, 64); @@ -2074,7 +2076,7 @@ emitTwoLimbLeftShiftBody(MachineIRBuilder &Builder, MachineInstr &Anchor, Regist emitLowLimbOfTwoLimbLogicalRightShift(MachineIRBuilder &Builder, MachineInstr &Anchor, Register Low, Register High, Register Amount, Register Boundary, Register Zero) { - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto AmountExcess = @@ -2119,7 +2121,7 @@ emitThreeLimbLeftShift(MachineIRBuilder &Builder, MachineInstr &Anchor, if (Parts.size() != 3) return makeUnexpected(ErrorCode::VerificationError, "RISC-V three-limb shift requires exactly three limbs"); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); @@ -2291,7 +2293,7 @@ emitThreeLimbLeftShift(MachineIRBuilder &Builder, MachineInstr &Anchor, if (Left.size() != Right.size() || Left.size() < 2) return makeUnexpected(ErrorCode::VerificationError, "RISC-V wide add requires matching multi-limb operands"); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); std::vector<Register> Results; @@ -2356,7 +2358,7 @@ emitThreeLimbLeftShift(MachineIRBuilder &Builder, MachineInstr &Anchor, if (Left.size() != Right.size() || Left.size() < 2) return makeUnexpected(ErrorCode::VerificationError, "RISC-V wide sub requires matching multi-limb operands"); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); std::vector<Register> Results; @@ -2415,7 +2417,7 @@ emitWideBitwise(MachineIRBuilder &Builder, MachineInstr &Anchor, GenericOpcode G if (Left.size() != Right.size() || Left.size() < 2) return makeUnexpected(ErrorCode::VerificationError, "RISC-V wide bitwise operation requires matching multi-limb operands"); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); std::vector<Register> Results; @@ -2500,7 +2502,8 @@ emitWideBitwise(MachineIRBuilder &Builder, MachineInstr &Anchor, GenericOpcode G Truncation->opcode() != opcode(GenericOpcode::G_TRUNC) || Truncation->operandCount() != 2) return false; return operandType(Function, *Truncation, 1) - .transform([](LLT Type) { return isScalarGPRType(Type) && Type.scalarBitWidth() == 64; }) + .transform( + [](LowLevelType Type) { return isScalarGPRType(Type) && Type.scalarBitWidth() == 64; }) .value_or(false); } @@ -2515,7 +2518,7 @@ emitWideBitwise(MachineIRBuilder &Builder, MachineInstr &Anchor, GenericOpcode G const MachineOperand *Definition = Function.registerInfo().getUniqueVRegDef(Condition); MachineInstr *Truncation = const_cast<MachineInstr *>(Definition->parent()); const Register Source = *Truncation->operandAt(1)->getIf<Register>(); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); MachineIRBuilder Builder(Function, Target); @@ -2549,7 +2552,7 @@ struct NarrowPhiIncoming final { [[nodiscard]] Expected<Register> buildIncomingConversion(MachineFunction &Function, const TargetDescription &Target, MachineBasicBlock &Block, MachineInstr *Anchor, GenericOpcode Generic, - LLT Type, Register Source) { + LowLevelType Type, Register Source) { auto Result = Function.registerInfo().createVirtualRegister(Type); if (!Result) return std::unexpected(Result.error()); @@ -2573,14 +2576,14 @@ buildIncomingConversion(MachineFunction &Function, const TargetDescription &Targ [[nodiscard]] Expected<void> lowerNarrowPhi(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional<LLT> OriginalType = resultType(Function, Instruction); + const std::optional<LowLevelType> OriginalType = resultType(Function, Instruction); const MachineOperand *DestinationOperand = Instruction.operandAt(0); const Register *Destination = DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); if (!OriginalType || Destination == nullptr || OriginalType->scalarBitWidth() >= 32 || Instruction.operandCount() < 3 || (Instruction.operandCount() % 2U) == 0) return makeUnexpected(ErrorCode::VerificationError, "RISC-V narrow PHI has invalid operands"); - auto LegalType = LLT::makeAnyScalar(32); + auto LegalType = LowLevelType::makeCategoryNeutralScalar(32); if (!LegalType) return std::unexpected(LegalType.error()); @@ -2603,7 +2606,7 @@ buildIncomingConversion(MachineFunction &Function, const TargetDescription &Targ if (Def != nullptr && Def->opcode() == opcode(GenericOpcode::G_TRUNC) && Def->operandCount() == 2 && singleRegisterUse(Function, *Value) == &Instruction && operandType(Function, *Def, 1) - .transform([](LLT Type) { return Type.scalarBitWidth() >= 32; }) + .transform([](LowLevelType Type) { return Type.scalarBitWidth() >= 32; }) .value_or(false)) { Reusable = Def; } @@ -2731,7 +2734,7 @@ buildIncomingConversion(MachineFunction &Function, const TargetDescription &Targ auto ResultPlan = wideResultPlan(*Destination, Function, PartCount); if (!ResultPlan) return std::unexpected(ResultPlan.error()); - auto Type = LLT::makeAnyScalar(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); MachineIRBuilder Builder(Function, Target); @@ -2800,7 +2803,7 @@ buildIncomingConversion(MachineFunction &Function, const TargetDescription &Targ if (Trunc == nullptr || Trunc->opcode() != opcode(GenericOpcode::G_TRUNC) || Trunc->operandAt(1) != &Use) return false; - const std::optional<LLT> Result = resultType(Function, *Trunc); + const std::optional<LowLevelType> Result = resultType(Function, *Trunc); if (!Result || Result->scalarBitWidth() > LowType->scalarBitWidth()) return false; } @@ -2813,13 +2816,14 @@ struct RV64ScalarLayout final { std::uint64_t ABIAlignment = 0; }; -[[nodiscard]] std::optional<RV64ScalarLayout> rv64ScalarLayout(LLT Type) noexcept { +[[nodiscard]] std::optional<RV64ScalarLayout> rv64ScalarLayout(LowLevelType Type) noexcept { if (Type.isPointer()) { return Type.addressSpace() == 0 && Type.scalarBitWidth() == 64 ? std::optional<RV64ScalarLayout>{{8, 8, 8}} : std::nullopt; } - if ((!isSupportedIntegerType(Type) && !isRVFloatType(Type)) || Type.scalarBitWidth() == 0) { + if ((!isSupportedIntegerType(Type) && !isSupportedFloatingScalar(Type)) || + Type.scalarBitWidth() == 0) { return std::nullopt; } const std::uint64_t StoreBytes = (Type.scalarBitWidth() + 7U) / 8U; @@ -2828,7 +2832,7 @@ struct RV64ScalarLayout final { } [[nodiscard]] Expected<const MachineMemOperand *> -createMemoryAccess(MachineFunction &Function, MemoryAccessFlag Access, LLT Type, +createMemoryAccess(MachineFunction &Function, MemoryAccessFlag Access, LowLevelType Type, std::uint64_t SizeBytes, std::uint64_t AlignmentBytes) { auto Size = MemorySize::fixed(SizeBytes); auto Align = Alignment::create(AlignmentBytes); @@ -2845,8 +2849,8 @@ createMemoryAccess(MachineFunction &Function, MemoryAccessFlag Access, LLT Type, struct VAArgPlan final { Register Destination; Register ListPointer; - LLT DestinationType; - LLT PointerType; + LowLevelType DestinationType; + LowLevelType PointerType; std::uint64_t Alignment = 0; RV64ScalarLayout ValueLayout; }; @@ -2863,8 +2867,8 @@ struct VAArgPlan final { const Register *Destination = DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); const Register *ListPointer = ListOperand == nullptr ? nullptr : ListOperand->getIf<Register>(); - const std::optional<LLT> DestinationType = resultType(Function, Instruction); - const std::optional<LLT> PointerType = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> DestinationType = resultType(Function, Instruction); + const std::optional<LowLevelType> PointerType = operandType(Function, Instruction, 1); const auto AlignmentValue = AlignmentOperand == nullptr ? Expected<std::int64_t>(std::unexpected( Error(ErrorCode::InvalidArgument, "missing alignment"))) @@ -2989,7 +2993,7 @@ struct VAArgPlan final { struct VACopyPlan final { Register Destination; Register Source; - LLT PointerType; + LowLevelType PointerType; }; [[nodiscard]] std::optional<VACopyPlan> vacopyPlan(const MachineInstr &Instruction, @@ -3006,8 +3010,8 @@ struct VACopyPlan final { const Register *Destination = DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>(); - const std::optional<LLT> DestinationType = operandType(Function, Instruction, 1); - const std::optional<LLT> SourceType = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> DestinationType = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> SourceType = operandType(Function, Instruction, 2); if (Intrinsic == nullptr || Intrinsic->ID != intrinsicID(GenericIntrinsic::VACopy) || Destination == nullptr || Source == nullptr || !Destination->isVirtual() || !Source->isVirtual() || !DestinationOperand->isUse() || !SourceOperand->isUse() || @@ -3095,7 +3099,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In return LegalizationAction::Legal; const GenericOpcode Generic = static_cast<GenericOpcode>(Instruction.opcode().value()); - const std::optional<LLT> Type = resultType(Function, Instruction); + const std::optional<LowLevelType> Type = resultType(Function, Instruction); switch (Generic) { case GenericOpcode::G_INTRINSIC_W_SIDE_EFFECTS: return vacopyPlan(Instruction, Function) ? LegalizationAction::Custom @@ -3110,7 +3114,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_BR: return LegalizationAction::Legal; case GenericOpcode::G_BRCOND: { - const std::optional<LLT> Condition = operandType(Function, Instruction, 0); + const std::optional<LowLevelType> Condition = operandType(Function, Instruction, 0); if (!Condition || !isScalarGPRType(*Condition)) return LegalizationAction::Unsupported; return canLowerNarrowBranchCondition(Instruction, Function) ? LegalizationAction::Custom @@ -3120,28 +3124,28 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In if (!Type) return LegalizationAction::Unsupported; for (std::size_t Index = 1; Index < Instruction.operandCount(); Index += 2) { - const std::optional<LLT> Incoming = operandType(Function, Instruction, Index); + const std::optional<LowLevelType> Incoming = operandType(Function, Instruction, Index); if (!Incoming || *Incoming != *Type) return LegalizationAction::Unsupported; } - if ((Type->isInteger() || Type->isAnyScalar()) && Type->scalarBitWidth() > 64) + if (Type->isCategoryNeutralScalar() && Type->scalarBitWidth() > 64) return LegalizationAction::Custom; - if ((Type->isInteger() || Type->isAnyScalar()) && Type->scalarBitWidth() < 32) + if (Type->isCategoryNeutralScalar() && Type->scalarBitWidth() < 32) return LegalizationAction::Custom; - if (!isSupportedIntegerType(*Type) && !isRVFloatType(*Type)) + if (!isSupportedIntegerType(*Type)) return LegalizationAction::Unsupported; return LegalizationAction::Legal; } case GenericOpcode::G_IMPLICIT_DEF: - return Type && (isSupportedIntegerType(*Type) || isRVFloatType(*Type)) - ? LegalizationAction::Legal - : LegalizationAction::Unsupported; + return Type && isSupportedIntegerType(*Type) ? LegalizationAction::Legal + : LegalizationAction::Unsupported; case GenericOpcode::G_STORE: if (Instruction.operandCount() == 0) return LegalizationAction::Unsupported; - if (const std::optional<LLT> ValueType = registerType(Function, *Instruction.operandAt(0)); + if (const std::optional<LowLevelType> ValueType = + registerType(Function, *Instruction.operandAt(0)); ValueType) { - const std::optional<LLT> AddressType = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> AddressType = operandType(Function, Instruction, 1); if (!AddressType || !AddressType->isPointer() || AddressType->addressSpace() != 0 || AddressType->scalarBitWidth() != 64) { return LegalizationAction::Unsupported; @@ -3153,8 +3157,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In ? LegalizationAction::Legal : LegalizationAction::Unsupported; } - if ((isSupportedIntegerType(*ValueType) || isRVFloatType(*ValueType)) && - isSupportedNonAtomicMemoryAccess(Instruction) && + if (isSupportedIntegerType(*ValueType) && isSupportedNonAtomicMemoryAccess(Instruction) && memoryMatchesType(Instruction, *ValueType)) { return LegalizationAction::Legal; } @@ -3163,7 +3166,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SEXTLOAD: case GenericOpcode::G_ZEXTLOAD: { const auto Bytes = memoryAccessBytes(Instruction); - const std::optional<LLT> AddressType = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> AddressType = operandType(Function, Instruction, 1); return Type && Bytes && AddressType && isSupportedIntegerType(*Type) && AddressType->isPointer() && AddressType->addressSpace() == 0 && AddressType->scalarBitWidth() == 64 && @@ -3175,19 +3178,19 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_FPEXTLOAD: { const auto Bytes = memoryAccessBytes(Instruction); - const std::optional<LLT> AddressType = operandType(Function, Instruction, 1); - return Type && Bytes && AddressType && Type->isFloat() && Type->scalarBitWidth() == 64 && - AddressType->isPointer() && AddressType->addressSpace() == 0 && - AddressType->scalarBitWidth() == 64 && *Bytes == 4 && - isSupportedNonAtomicMemoryAccess(Instruction) + const std::optional<LowLevelType> AddressType = operandType(Function, Instruction, 1); + return Type && Bytes && AddressType && Type->isCategoryNeutralScalar() && + Type->scalarBitWidth() == 64 && AddressType->isPointer() && + AddressType->addressSpace() == 0 && AddressType->scalarBitWidth() == 64 && + *Bytes == 4 && isSupportedNonAtomicMemoryAccess(Instruction) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FPTRUNCSTORE: { - const std::optional<LLT> ValueType = operandType(Function, Instruction, 0); - const std::optional<LLT> AddressType = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> ValueType = operandType(Function, Instruction, 0); + const std::optional<LowLevelType> AddressType = operandType(Function, Instruction, 1); const auto Bytes = memoryAccessBytes(Instruction); - return ValueType && AddressType && Bytes && ValueType->isFloat() && + return ValueType && AddressType && Bytes && ValueType->isCategoryNeutralScalar() && ValueType->scalarBitWidth() == 64 && AddressType->isPointer() && AddressType->addressSpace() == 0 && AddressType->scalarBitWidth() == 64 && *Bytes == 4 && isSupportedNonAtomicMemoryAccess(Instruction) @@ -3196,7 +3199,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_LOAD: if (Type) { - const std::optional<LLT> AddressType = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> AddressType = operandType(Function, Instruction, 1); if (!AddressType || !AddressType->isPointer() || AddressType->addressSpace() != 0 || AddressType->scalarBitWidth() != 64) { return LegalizationAction::Unsupported; @@ -3208,8 +3211,8 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In ? LegalizationAction::Legal : LegalizationAction::Unsupported; } - if ((isSupportedIntegerType(*Type) || isRVFloatType(*Type)) && - isSupportedNonAtomicMemoryAccess(Instruction) && memoryMatchesType(Instruction, *Type)) { + if (isSupportedIntegerType(*Type) && isSupportedNonAtomicMemoryAccess(Instruction) && + memoryMatchesType(Instruction, *Type)) { return LegalizationAction::Legal; } } @@ -3218,33 +3221,35 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_FSUB: case GenericOpcode::G_FMUL: case GenericOpcode::G_FDIV: { - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); - return Type && Left && Right && isRVFloatType(*Type) && *Left == *Type && *Right == *Type + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); + return Type && Left && Right && isSupportedFloatingScalar(*Type) && *Left == *Type && + *Right == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FMA: { - const std::optional<LLT> First = operandType(Function, Instruction, 1); - const std::optional<LLT> Second = operandType(Function, Instruction, 2); - const std::optional<LLT> Third = operandType(Function, Instruction, 3); - return Type && First && Second && Third && isRVFloatType(*Type) && *First == *Type && - *Second == *Type && *Third == *Type + const std::optional<LowLevelType> First = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Second = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Third = operandType(Function, Instruction, 3); + return Type && First && Second && Third && isSupportedFloatingScalar(*Type) && + *First == *Type && *Second == *Type && *Third == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FNEG: case GenericOpcode::G_FABS: case GenericOpcode::G_FSQRT: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - return Type && Source && isRVFloatType(*Type) && *Source == *Type + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + return Type && Source && isSupportedFloatingScalar(*Type) && *Source == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FCOPYSIGN: { - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); - return Type && Left && Right && isRVFloatType(*Type) && *Left == *Type && *Right == *Type + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); + return Type && Left && Right && isSupportedFloatingScalar(*Type) && *Left == *Type && + *Right == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } @@ -3252,16 +3257,15 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In const MachineOperand *Immediate = Instruction.operandAt(1); const auto *Floating = Immediate == nullptr ? nullptr : Immediate->getIf<FloatingImmediateOperand>(); - const std::optional<FloatSemantics> Semantics = Type ? Type->floatSemantics() : std::nullopt; - return Type && isRVFloatType(*Type) && Floating != nullptr && Semantics && - Floating->Bits.semantics() == *Semantics + return Type && isSupportedFloatingScalar(*Type) && Floating != nullptr && + Floating->Bits.bitWidth() == Type->scalarBitWidth() ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_ASSERT_SEXT: case GenericOpcode::G_ASSERT_ZEXT: case GenericOpcode::G_ASSERT_ALIGN: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); return Type && Source && *Type == *Source && isScalarGPRType(*Type) && Instruction.operandCount() == 3 ? LegalizationAction::Legal @@ -3269,38 +3273,35 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_FREEZE: case GenericOpcode::G_CONSTANT_FOLD_BARRIER: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - return Type && Source && *Type == *Source && - (isSupportedIntegerType(*Type) || isRVFloatType(*Type)) + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + return Type && Source && *Type == *Source && isSupportedIntegerType(*Type) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_PTRTOINT: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - return Type && Source && Type->isInteger() && Type->scalarBitWidth() == 64 && + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + return Type && Source && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64 && Source->isPointer() && Source->scalarBitWidth() == 64 ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_INTTOPTR: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); return Type && Source && Type->isPointer() && Type->scalarBitWidth() == 64 && - Source->isInteger() && Source->scalarBitWidth() == 64 + Source->isCategoryNeutralScalar() && Source->scalarBitWidth() == 64 ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_BITCAST: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - const bool IntegerFloatPair = - Type && Source && Type->scalarBitWidth() == Source->scalarBitWidth() && - ((Type->isFloat() && Source->isInteger()) || (Type->isInteger() && Source->isFloat())) && - (Type->scalarBitWidth() == 32 || Type->scalarBitWidth() == 64); - return IntegerFloatPair ? LegalizationAction::Legal : LegalizationAction::Unsupported; + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + return Type && Source && *Type != *Source && Type->scalarBitWidth() == Source->scalarBitWidth() + ? LegalizationAction::Legal + : LegalizationAction::Unsupported; } case GenericOpcode::G_ANYEXT: case GenericOpcode::G_SEXT: case GenericOpcode::G_ZEXT: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); if (!Type || !Source) return LegalizationAction::Unsupported; if (!isScalarIntegerExtension(*Type, *Source)) { @@ -3309,8 +3310,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); MachineInstr *OnlyUse = Destination == nullptr ? nullptr : singleUseInstruction(Function, *Destination); - return (Type->isInteger() || Type->isAnyScalar()) && - (Source->isInteger() || Source->isAnyScalar()) && + return Type->isCategoryNeutralScalar() && Source->isCategoryNeutralScalar() && Type->scalarBitWidth() > 64 && Source->scalarBitWidth() < Type->scalarBitWidth() && OnlyUse != nullptr && OnlyUse->opcode() == opcode(GenericOpcode::G_UNMERGE_VALUES) @@ -3334,10 +3334,9 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In return LegalizationAction::Legal; } case GenericOpcode::G_TRUNC: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - if (Type && Source && (Type->isInteger() || Type->isAnyScalar()) && - (Source->isInteger() || Source->isAnyScalar()) && Type->scalarBitWidth() > 64 && - Source->scalarBitWidth() > Type->scalarBitWidth()) + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + if (Type && Source && Type->isCategoryNeutralScalar() && Source->isCategoryNeutralScalar() && + Type->scalarBitWidth() > 64 && Source->scalarBitWidth() > Type->scalarBitWidth()) return LegalizationAction::Legal; return Type && Source && isSupportedIntegerScalar(*Type) && isSupportedIntegerScalar(*Source) && Type->scalarBitWidth() != 0 && Source->scalarBitWidth() >= Type->scalarBitWidth() @@ -3351,19 +3350,20 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In const std::size_t SmallTypeIndex = Generic == GenericOpcode::G_MERGE_VALUES ? 1 : 0; const std::size_t BigTypeIndex = Generic == GenericOpcode::G_MERGE_VALUES ? 0 : Instruction.operandCount() - 1U; - const std::optional<LLT> SmallType = operandType(Function, Instruction, SmallTypeIndex); - const std::optional<LLT> BigType = operandType(Function, Instruction, BigTypeIndex); + const std::optional<LowLevelType> SmallType = + operandType(Function, Instruction, SmallTypeIndex); + const std::optional<LowLevelType> BigType = operandType(Function, Instruction, BigTypeIndex); if (SmallType && BigType && Generic == GenericOpcode::G_MERGE_VALUES && BigType->scalarBitWidth() > 64 && !canFoldWideMergeImmediately(Instruction, Function)) return LegalizationAction::Legal; - return SmallType && BigType && (SmallType->isInteger() || SmallType->isAnyScalar()) && - (BigType->isInteger() || BigType->isAnyScalar()) && - SmallType->scalarBitWidth() != 0 && BigType->scalarBitWidth() != 0 + return SmallType && BigType && SmallType->isCategoryNeutralScalar() && + BigType->isCategoryNeutralScalar() && SmallType->scalarBitWidth() != 0 && + BigType->scalarBitWidth() != 0 ? LegalizationAction::Custom : LegalizationAction::Unsupported; } case GenericOpcode::G_SEXT_INREG: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); const MachineOperand *WidthOperand = Instruction.operandAt(2); const auto Width = WidthOperand == nullptr @@ -3379,8 +3379,8 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In const MachineOperand *Predicate = Instruction.operandAt(1); const auto *IntegerPredicate = Predicate == nullptr ? nullptr : Predicate->getIf<PredicateOperand>(); - const std::optional<LLT> Left = operandType(Function, Instruction, 2); - const std::optional<LLT> Right = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 3); if (!Type || !isSupportedIntegerScalar(*Type) || IntegerPredicate == nullptr || IntegerPredicate->integerPredicate() == nullptr || !Left || !Right || *Left != *Right || !isSupportedIntegerType(*Left)) { @@ -3394,19 +3394,20 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In const MachineOperand *Predicate = Instruction.operandAt(1); const auto *FloatingPredicate = Predicate == nullptr ? nullptr : Predicate->getIf<PredicateOperand>(); - const std::optional<LLT> Left = operandType(Function, Instruction, 2); - const std::optional<LLT> Right = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 3); return Type && isI1Type(*Type) && FloatingPredicate != nullptr && FloatingPredicate->floatingPredicate() != nullptr && Left && Right && - *Left == *Right && isRVFloatType(*Left) + *Left == *Right && isSupportedFloatingScalar(*Left) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FPEXT: case GenericOpcode::G_FPTRUNC: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); const bool IsExtension = Generic == GenericOpcode::G_FPEXT; - return Type && Source && isRVFloatType(*Type) && isRVFloatType(*Source) && + return Type && Source && isSupportedFloatingScalar(*Type) && + isSupportedFloatingScalar(*Source) && ((IsExtension && Source->scalarBitWidth() == 32 && Type->scalarBitWidth() == 64) || (!IsExtension && Source->scalarBitWidth() == 64 && @@ -3416,39 +3417,39 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_FPTOSI: case GenericOpcode::G_FPTOUI: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - return Type && Source && isSupportedIntegerType(*Type) && isRVFloatType(*Source) + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + return Type && Source && isSupportedIntegerType(*Type) && isSupportedFloatingScalar(*Source) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_SITOFP: case GenericOpcode::G_UITOFP: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); - return Type && Source && isRVFloatType(*Type) && isSupportedIntegerType(*Source) + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); + return Type && Source && isSupportedFloatingScalar(*Type) && isSupportedIntegerType(*Source) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FMINNUM: case GenericOpcode::G_FMAXNUM: { - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); - return Type && Left && Right && isRVFloatType(*Type) && *Left == *Type && *Right == *Type + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); + return Type && Left && Right && isSupportedFloatingScalar(*Type) && *Left == *Type && + *Right == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_SELECT: { - const std::optional<LLT> Condition = operandType(Function, Instruction, 1); - const std::optional<LLT> TrueValue = operandType(Function, Instruction, 2); - const std::optional<LLT> FalseValue = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> Condition = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> TrueValue = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> FalseValue = operandType(Function, Instruction, 3); return Type && Condition && TrueValue && FalseValue && isScalarGPRType(*Condition) && - *TrueValue == *Type && *FalseValue == *Type && - (isSupportedIntegerType(*Type) || isRVFloatType(*Type)) + *TrueValue == *Type && *FalseValue == *Type && isSupportedIntegerType(*Type) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_PTRMASK: { - const std::optional<LLT> Pointer = operandType(Function, Instruction, 1); - const std::optional<LLT> Mask = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Pointer = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Mask = operandType(Function, Instruction, 2); return Type && Pointer && Mask && Type->isPointer() && Type->addressSpace() == 0 && Type->scalarBitWidth() == 64 && *Pointer == *Type && isSupportedIntegerScalar(*Mask) && Mask->scalarBitWidth() == 64 @@ -3456,16 +3457,16 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In : LegalizationAction::Unsupported; } case GenericOpcode::G_ABS: { - const std::optional<LLT> Source = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1); return Type && Source && *Source == *Type && isSupportedIntegerScalar(*Type) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_SDIVREM: case GenericOpcode::G_UDIVREM: { - const std::optional<LLT> Remainder = operandType(Function, Instruction, 1); - const std::optional<LLT> Left = operandType(Function, Instruction, 2); - const std::optional<LLT> Right = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> Remainder = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 3); return Type && Remainder && Left && Right && isSupportedIntegerScalar(*Type) && *Remainder == *Type && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3473,8 +3474,8 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_SMULH: case GenericOpcode::G_UMULH: { - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); return Type && Left && Right && isNativeIntegerScalar(*Type) && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3484,8 +3485,8 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SMAX: case GenericOpcode::G_UMIN: case GenericOpcode::G_UMAX: { - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); return Type && Left && Right && isSupportedIntegerScalar(*Type) && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3497,9 +3498,9 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SSUBO: case GenericOpcode::G_UMULO: case GenericOpcode::G_SMULO: { - const std::optional<LLT> Overflow = operandType(Function, Instruction, 1); - const std::optional<LLT> Left = operandType(Function, Instruction, 2); - const std::optional<LLT> Right = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> Overflow = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 3); return Type && Overflow && Left && Right && isNativeIntegerScalar(*Type) && isI1Type(*Overflow) && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3509,10 +3510,10 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_USUBE: case GenericOpcode::G_SADDE: case GenericOpcode::G_SSUBE: { - const std::optional<LLT> CarryOut = operandType(Function, Instruction, 1); - const std::optional<LLT> Left = operandType(Function, Instruction, 2); - const std::optional<LLT> Right = operandType(Function, Instruction, 3); - const std::optional<LLT> CarryIn = operandType(Function, Instruction, 4); + const std::optional<LowLevelType> CarryOut = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> CarryIn = operandType(Function, Instruction, 4); return Type && CarryOut && Left && Right && CarryIn && isNativeIntegerScalar(*Type) && isI1Type(*CarryOut) && isI1Type(*CarryIn) && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3528,8 +3529,8 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_ATOMICRMW_MIN: case GenericOpcode::G_ATOMICRMW_UMAX: case GenericOpcode::G_ATOMICRMW_UMIN: { - const std::optional<LLT> Address = operandType(Function, Instruction, 1); - const std::optional<LLT> Value = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Address = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Value = operandType(Function, Instruction, 2); const std::uint64_t Bytes = Type ? Type->scalarBitWidth() / 8U : 0; return Type && Address && Value && isNativeIntegerScalar(*Type) && *Value == *Type && Address->isPointer() && Address->addressSpace() == 0 && @@ -3540,11 +3541,11 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In : LegalizationAction::Unsupported; } case GenericOpcode::G_ATOMIC_CMPXCHG: { - const std::optional<LLT> Address = operandType(Function, Instruction, 1); - const std::optional<LLT> Compare = operandType(Function, Instruction, 2); - const std::optional<LLT> NewValue = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> Address = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Compare = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> NewValue = operandType(Function, Instruction, 3); if (!Type || !Address || !Compare || !NewValue || *Compare != *Type || *NewValue != *Type || - (!Type->isInteger() && !Type->isAnyScalar()) || + !Type->isCategoryNeutralScalar() || (Type->scalarBitWidth() != 8 && Type->scalarBitWidth() != 16 && Type->scalarBitWidth() != 32 && Type->scalarBitWidth() != 64) || !Address->isPointer() || Address->addressSpace() != 0 || Address->scalarBitWidth() != 64 || @@ -3555,13 +3556,12 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In return Type->scalarBitWidth() == 64 ? LegalizationAction::Legal : LegalizationAction::Custom; } case GenericOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: { - const std::optional<LLT> Success = operandType(Function, Instruction, 1); - const std::optional<LLT> Address = operandType(Function, Instruction, 2); - const std::optional<LLT> Compare = operandType(Function, Instruction, 3); - const std::optional<LLT> NewValue = operandType(Function, Instruction, 4); + const std::optional<LowLevelType> Success = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Address = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Compare = operandType(Function, Instruction, 3); + const std::optional<LowLevelType> NewValue = operandType(Function, Instruction, 4); return Type && Success && Address && Compare && NewValue && isI1Type(*Success) && - *Compare == *Type && *NewValue == *Type && - (Type->isInteger() || Type->isAnyScalar()) && + *Compare == *Type && *NewValue == *Type && Type->isCategoryNeutralScalar() && (Type->scalarBitWidth() == 8 || Type->scalarBitWidth() == 16 || Type->scalarBitWidth() == 32 || Type->scalarBitWidth() == 64) && Address->isPointer() && Address->addressSpace() == 0 && @@ -3605,7 +3605,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_BRINDIRECT: return operandType(Function, Instruction, 0) - .transform([](LLT Value) { + .transform([](LowLevelType Value) { return Value.isPointer() && Value.addressSpace() == 0 && Value.scalarBitWidth() == 64; }) @@ -3629,7 +3629,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In return wideConstantUnmergePlan(Instruction, Function).has_value() ? LegalizationAction::Custom : LegalizationAction::Unsupported; - if ((Type->isInteger() || Type->isAnyScalar()) && Type->scalarBitWidth() == 64) { + if (Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64) { auto Value = signedImmediate(*Immediate); if (Value && shouldUseRV64IntegerConstantPool(*Value)) return LegalizationAction::Custom; @@ -3650,10 +3650,10 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SHL: case GenericOpcode::G_LSHR: case GenericOpcode::G_ASHR: { - const std::optional<LLT> Left = operandType(Function, Instruction, 1); - const std::optional<LLT> Right = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2); if (!Type || !Left || !Right || *Left != *Type || *Right != *Type || - (!Type->isInteger() && !Type->isAnyScalar())) + !Type->isCategoryNeutralScalar()) return LegalizationAction::Unsupported; if (Type->scalarBitWidth() > 64) { return Generic == GenericOpcode::G_ADD || Generic == GenericOpcode::G_SUB || @@ -3670,7 +3670,7 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>(); MachineInstr *Extension = Destination == nullptr ? nullptr : singleRegisterUse(Function, *Destination); - const std::optional<LLT> ExtensionType = + const std::optional<LowLevelType> ExtensionType = Extension == nullptr ? std::nullopt : resultType(Function, *Extension); if (Extension != nullptr && Extension->opcode() == opcode(GenericOpcode::G_ANYEXT) && ExtensionType && ExtensionType->scalarBitWidth() == 64) { @@ -3682,8 +3682,8 @@ Expected<LegalizationAction> RISCVLegalizerInfo::classify(const MachineInstr &In : LegalizationAction::Unsupported; } case GenericOpcode::G_PTR_ADD: { - const std::optional<LLT> Pointer = operandType(Function, Instruction, 1); - const std::optional<LLT> Offset = operandType(Function, Instruction, 2); + const std::optional<LowLevelType> Pointer = operandType(Function, Instruction, 1); + const std::optional<LowLevelType> Offset = operandType(Function, Instruction, 2); return Type && Pointer && Offset && Type->isPointer() && Type->addressSpace() == 0 && Type->scalarBitWidth() == 64 && *Pointer == *Type && isSupportedIntegerScalar(*Offset) && Offset->scalarBitWidth() == 64 @@ -3737,7 +3737,7 @@ Expected<void> RISCVLegalizerInfo::lower(MachineInstr &Instruction, MachineFunct } if (Action == LegalizationAction::Custom && resultType(Function, Instruction) - .transform([](LLT Type) { return Type.scalarBitWidth() > 64; }) + .transform([](LowLevelType Type) { return Type.scalarBitWidth() > 64; }) .value_or(false)) { const Opcode Value = Instruction.opcode(); if (Value == opcode(GenericOpcode::G_ADD) || Value == opcode(GenericOpcode::G_SUB) || @@ -3783,8 +3783,8 @@ Expected<void> RISCVLegalizerInfo::lower(MachineInstr &Instruction, MachineFunct if (Action == LegalizationAction::Custom && Instruction.opcode() == opcode(GenericOpcode::G_CONSTANT)) { const MachineOperand *Immediate = Instruction.operandAt(1); - const std::optional<LLT> Type = resultType(Function, Instruction); - if (Immediate != nullptr && Type && (Type->isInteger() || Type->isAnyScalar()) && + const std::optional<LowLevelType> Type = resultType(Function, Instruction); + if (Immediate != nullptr && Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64) { auto Value = signedImmediate(*Immediate); if (Value && shouldUseRV64IntegerConstantPool(*Value)) diff --git a/backend/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp b/backend/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp index 7c60219..66a3371 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVRegisterBankInfo.cpp @@ -20,13 +20,9 @@ namespace rcc::riscv { namespace { -[[nodiscard]] bool isRVFloatType(LLT Type) noexcept { - return Type.isFloat() && (Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64); -} - -[[nodiscard]] bool isScalarGPRType(LLT Type) noexcept { +[[nodiscard]] bool isScalarGPRType(LowLevelType Type) noexcept { return (Type.isPointer() && Type.addressSpace() == 0 && Type.scalarBitWidth() == 64) || - ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() >= 1 && + (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() >= 1 && Type.scalarBitWidth() <= 64); } @@ -219,9 +215,9 @@ requiredBankForRegister(const MachineFunction &Function, Register Reg, "RISC-V selection requires a type for every virtual register"); } const VirtualRegisterInfo &RegisterInfo = Info->get(); - const LLT Type = RegisterInfo.Type.value_or(LLT{}); + const LowLevelType Type = RegisterInfo.Type.value_or(LowLevelType{}); RegisterClassID RequiredClass; - if ((RegisterInfo.Bank && *RegisterInfo.Bank == fprBank()) || Type.isFloat()) { + if (RegisterInfo.Bank && *RegisterInfo.Bank == fprBank()) { if (Type.scalarBitWidth() != 32 && Type.scalarBitWidth() != 64) { return makeUnexpected(ErrorCode::Unsupported, "RISC-V RV64GC has no floating register class for type '" + @@ -269,8 +265,7 @@ RISCVRegisterBankInfo::selectBank(const MachineFunction &Function, Register Reg, if (!Required) return std::unexpected(Required.error()); const bool IsConstrained = Required->has_value() || Info.Bank.has_value(); - const RegisterBankID Selected = - Required->value_or(isRVFloatType(*Info.Type) ? fprBank() : gprBank()); + const RegisterBankID Selected = Required->value_or(gprBank()); if (Info.Bank && *Info.Bank != Selected) { return makeUnexpected(ErrorCode::VerificationError, "RISC-V virtual register has a conflicting register bank"); diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index 910ea3f..91cad89 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -1923,7 +1923,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -1941,7 +1941,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -1959,7 +1959,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -1977,7 +1977,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -1994,7 +1994,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2011,7 +2011,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2028,7 +2028,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2045,7 +2045,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_DIV encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2061,7 +2061,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_SQRT encoding_category: R assembly_format: FRD_FRS1_RM @@ -2121,7 +2121,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2 @@ -2136,7 +2136,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2 @@ -2152,7 +2152,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2168,7 +2168,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2184,7 +2184,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2200,7 +2200,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2229,7 +2229,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: RD_FRS1_FRS2 @@ -2244,7 +2244,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: RD_FRS1_FRS2 @@ -2259,7 +2259,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: RD_FRS1_FRS2 @@ -2289,7 +2289,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_RS1_RM @@ -2305,7 +2305,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_RS1_RM @@ -2321,7 +2321,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_RS1_RM @@ -2337,7 +2337,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_RS1_RM @@ -2399,7 +2399,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -2417,7 +2417,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -2435,7 +2435,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -2453,7 +2453,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R4 assembly_format: FRD_FRS1_FRS2_FRS3_RM @@ -2470,7 +2470,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2487,7 +2487,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2504,7 +2504,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_MUL encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2521,7 +2521,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_DIV encoding_category: R assembly_format: FRD_FRS1_FRS2_RM @@ -2537,7 +2537,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_SQRT encoding_category: R assembly_format: FRD_FRS1_RM @@ -2597,7 +2597,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2 @@ -2612,7 +2612,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: FRD_FRS1_FRS2 @@ -2628,7 +2628,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2644,7 +2644,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2660,7 +2660,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2676,7 +2676,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: RD_FRS1_RM @@ -2705,7 +2705,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: RD_FRS1_FRS2 @@ -2720,7 +2720,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: RD_FRS1_FRS2 @@ -2735,7 +2735,7 @@ instructions: - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } num_explicit_defs: 1 - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_ADD encoding_category: R assembly_format: RD_FRS1_FRS2 @@ -2797,7 +2797,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_RS1_RM @@ -2813,7 +2813,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_RS1_RM @@ -2843,7 +2843,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_FRS1_RM @@ -3373,7 +3373,7 @@ instructions: - { kinds: [immediate], immediate_predicate: RM, name: RM } num_explicit_defs: 1 allow_extra_implicit_operands: true - flags: [produces_code] + flags: [may_raise_fp_exception, produces_code] scheduling_class: FP_CONVERT encoding_category: R assembly_format: FRD_FRS1_RM diff --git a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp index d5d932c..b9cdb48 100644 --- a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp +++ b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp @@ -45,7 +45,8 @@ registerBank(Register Reg, const MachineFunction &Function, const TargetDescript return std::nullopt; } -[[nodiscard]] std::optional<LLT> registerType(Register Reg, const MachineFunction &Function) { +[[nodiscard]] std::optional<LowLevelType> registerType(Register Reg, + const MachineFunction &Function) { if (!Reg.isVirtual()) return std::nullopt; auto Info = Function.registerInfo().virtualRegisterInfo(Reg); @@ -156,7 +157,7 @@ copyRegisters(const MachineInstr &Instruction) { const auto DestinationType = registerType(Registers->first, Function); const auto SourceType = registerType(Registers->second, Function); - const std::optional<LLT> Type = DestinationType ? DestinationType : SourceType; + const std::optional<LowLevelType> Type = DestinationType ? DestinationType : SourceType; if (!Type || Type->isVector() || (Type->scalarBitWidth() != 32 && Type->scalarBitWidth() != 64)) { return makeUnexpected(ErrorCode::Unsupported, "RISC-V cross-bank COPY requires a scalar 32-bit or 64-bit type"); diff --git a/backend/lib/Tooling/MIRFuzzer.cpp b/backend/lib/Tooling/MIRFuzzer.cpp index 467291c..dc6b8d1 100644 --- a/backend/lib/Tooling/MIRFuzzer.cpp +++ b/backend/lib/Tooling/MIRFuzzer.cpp @@ -186,7 +186,7 @@ private: MachineBasicBlock *Block = Function->firstBlock(); if (Block == nullptr) return false; - auto Type = LLT::makeInteger(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto Register = Function->registerInfo().createVirtualRegister(*Type); diff --git a/backend/unittests/CodeGen/CoreTypesTest.cpp b/backend/unittests/CodeGen/CoreTypesTest.cpp index b19d6b4..8ad0ce6 100644 --- a/backend/unittests/CodeGen/CoreTypesTest.cpp +++ b/backend/unittests/CodeGen/CoreTypesTest.cpp @@ -5,12 +5,10 @@ #include "rcc/CodeGen/Register.h" #include "rcc/CodeGen/StableID.h" -#include <array> #include <cstdint> #include <iostream> #include <string_view> #include <type_traits> -#include <unordered_set> namespace { @@ -32,126 +30,92 @@ private: }; void testLowLevelTypes(TestContext &Context) { - const rcc::LLT Invalid; - Context.expect(!Invalid.isValid(), "default LLT must be invalid"); - Context.expect(Invalid.toString() == "LLT_invalid", "invalid LLT spelling must be stable"); - - const rcc::LLT Token = rcc::LLT::token(); - Context.expect(Token.isToken(), "token LLT must preserve its kind"); - Context.expect(Token.scalarBitWidth() == 0, "token LLT must have no bit width"); - Context.expect(Token.toString() == "s0", "token LLT must use the MIR token spelling"); - - auto Any = rcc::LLT::makeAnyScalar(3); - auto Integer = rcc::LLT::makeInteger(3); - Context.expect(Any && Integer, "arbitrary positive scalar widths must be accepted"); - if (Any && Integer) { - Context.expect(Any->isAnyScalar(), "bag-of-bits LLT must preserve its kind"); - Context.expect(Integer->isInteger(), "integer LLT must preserve its kind"); - Context.expect(*Any != *Integer, "bag-of-bits and integer LLTs must remain distinct"); - Context.expect(Any->toString() == "s3", "bag-of-bits LLT spelling must include its width"); - Context.expect(Integer->toString() == "i3", "integer LLT spelling must include its width"); + const rcc::LowLevelType Invalid; + Context.expect(!Invalid.isValid(), "default LowLevelType must be invalid"); + Context.expect(Invalid.toString() == "LLT_invalid", + "invalid LowLevelType spelling must be stable"); + + const rcc::LowLevelType Token = rcc::LowLevelType::token(); + Context.expect(Token.isToken(), "token LowLevelType must preserve its kind"); + Context.expect(Token.scalarBitWidth() == 0, "token LowLevelType must have no bit width"); + Context.expect(Token.toString() == "s0", "token LowLevelType must use the MIR token spelling"); + + auto Scalar = rcc::LowLevelType::makeCategoryNeutralScalar(3); + auto SameScalar = rcc::LowLevelType::makeCategoryNeutralScalar(3); + Context.expect(Scalar && SameScalar, "arbitrary positive scalar widths must be accepted"); + if (Scalar && SameScalar) { + Context.expect(Scalar->isCategoryNeutralScalar(), + "scalar LowLevelType must preserve its category-neutral kind"); + Context.expect(*Scalar == *SameScalar, + "equal-width scalars must have one canonical low-level type"); + Context.expect(Scalar->toString() == "s3", + "scalar LowLevelType spelling must include its width"); } - Context.expect(!rcc::LLT::makeInteger(0), "zero-width integer LLT must be rejected"); - Context.expect(!rcc::LLT::makeInteger(std::uint64_t{1} << 16), - "integer LLT wider than the encoding must be rejected"); - - constexpr std::array FloatCases{ - std::pair{rcc::FloatSemantics::IEEEHalf, std::uint32_t{16}}, - std::pair{rcc::FloatSemantics::BFloat, std::uint32_t{16}}, - std::pair{rcc::FloatSemantics::IEEESingle, std::uint32_t{32}}, - std::pair{rcc::FloatSemantics::IEEEDouble, std::uint32_t{64}}, - std::pair{rcc::FloatSemantics::IEEEQuad, std::uint32_t{128}}, - std::pair{rcc::FloatSemantics::PPCDoubleDouble, std::uint32_t{128}}, - std::pair{rcc::FloatSemantics::Float8E5M2, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float8E5M2FNUZ, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float8E4M3, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float8E4M3FN, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float8E4M3FNUZ, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float8E4M3B11FNUZ, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float8E3M4, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::FloatTF32, std::uint32_t{19}}, - std::pair{rcc::FloatSemantics::Float8E8M0FNU, std::uint32_t{8}}, - std::pair{rcc::FloatSemantics::Float6E3M2FN, std::uint32_t{6}}, - std::pair{rcc::FloatSemantics::Float6E2M3FN, std::uint32_t{6}}, - std::pair{rcc::FloatSemantics::Float4E2M1FN, std::uint32_t{4}}, - std::pair{rcc::FloatSemantics::X87DoubleExtended, std::uint32_t{80}}, - }; - - std::unordered_set<rcc::LLT> FloatTypes; - for (const auto &[Semantics, BitWidth] : FloatCases) { - auto Type = rcc::LLT::makeFloat(Semantics); - Context.expect(Type.has_value(), "known floating-point semantics must be accepted"); - if (!Type) - continue; - Context.expect(Type->scalarBitWidth() == BitWidth, - "float LLT must preserve its semantics bit width"); - Context.expect(Type->floatSemantics() == Semantics, - "float LLT must preserve exact floating-point semantics"); - FloatTypes.insert(*Type); - } - Context.expect(FloatTypes.size() == FloatCases.size(), - "distinct floating-point semantics must produce distinct LLTs"); - Context.expect(!rcc::LLT::makeFloat(rcc::FloatSemantics::Count), - "unknown floating-point semantics must be rejected"); + Context.expect(!rcc::LowLevelType::makeCategoryNeutralScalar(0), + "zero-width scalar LowLevelType must be rejected"); + Context.expect(!rcc::LowLevelType::makeCategoryNeutralScalar(std::uint64_t{1} << 16), + "scalar LowLevelType wider than the encoding must be rejected"); - auto Pointer = rcc::LLT::makePointer(rcc::LLT::MaxAddressSpace, 64); + auto Pointer = rcc::LowLevelType::makePointer(rcc::LowLevelType::MaxAddressSpace, 64); Context.expect(Pointer.has_value(), "maximum encodable pointer address space must be accepted"); if (Pointer) { - Context.expect(Pointer->isPointer(), "pointer LLT must preserve its kind"); - Context.expect(Pointer->addressSpace() == rcc::LLT::MaxAddressSpace, - "pointer LLT must preserve its address space"); + Context.expect(Pointer->isPointer(), "pointer LowLevelType must preserve its kind"); + Context.expect(Pointer->addressSpace() == rcc::LowLevelType::MaxAddressSpace, + "pointer LowLevelType must preserve its address space"); Context.expect(Pointer->toString() == "p16777215:64", - "pointer LLT spelling must preserve address space and width"); + "pointer LowLevelType spelling must preserve address space and width"); } - Context.expect(!rcc::LLT::makePointer(std::uint64_t{1} << 24, 64), + Context.expect(!rcc::LowLevelType::makePointer(std::uint64_t{1} << 24, 64), "pointer address spaces wider than the encoding must be rejected"); - auto I33 = rcc::LLT::makeInteger(33); + auto I33 = rcc::LowLevelType::makeCategoryNeutralScalar(33); if (!I33) { Context.expect(false, "i33 construction must succeed before vector tests"); return; } - auto FixedVector = rcc::LLT::makeFixedVector(4, *I33); - Context.expect(FixedVector.has_value(), "fixed integer vector LLT must be accepted"); + auto FixedVector = rcc::LowLevelType::makeFixedVector(4, *I33); + Context.expect(FixedVector.has_value(), "fixed integer vector LowLevelType must be accepted"); if (FixedVector) { - Context.expect(FixedVector->isVector(), "fixed vector LLT must preserve vector kind"); + Context.expect(FixedVector->isVector(), "fixed vector LowLevelType must preserve vector kind"); Context.expect(!FixedVector->isScalableVector(), - "fixed vector LLT must not be marked scalable"); + "fixed vector LowLevelType must not be marked scalable"); Context.expect(FixedVector->minimumElementCount() == 4, - "fixed vector LLT must preserve element count"); + "fixed vector LowLevelType must preserve element count"); Context.expect(FixedVector->scalarElementType() == I33, - "fixed vector LLT must preserve its scalar element type"); - Context.expect(FixedVector->toString() == "<4 x i33>", - "fixed vector LLT spelling must be stable"); + "fixed vector LowLevelType must preserve its scalar element type"); + Context.expect(FixedVector->toString() == "<4 x s33>", + "fixed vector LowLevelType spelling must be stable"); } - auto BFloat = rcc::LLT::makeFloat(rcc::FloatSemantics::BFloat); - if (!BFloat) { - Context.expect(false, "bfloat construction must succeed before vector tests"); + auto S16 = rcc::LowLevelType::makeCategoryNeutralScalar(16); + if (!S16) { + Context.expect(false, "s16 construction must succeed before vector tests"); return; } - auto ScalableVector = rcc::LLT::makeScalableVector(1, *BFloat); + auto ScalableVector = rcc::LowLevelType::makeScalableVector(1, *S16); Context.expect(ScalableVector.has_value(), "scalable vector with one minimum lane must work"); if (ScalableVector) { Context.expect(ScalableVector->isScalableVector(), - "scalable vector LLT must preserve scalability"); - Context.expect(ScalableVector->isFloatVector() && !ScalableVector->isFloat(), - "float vectors must not be classified as scalar floats"); - Context.expect(ScalableVector->floatSemantics() == rcc::FloatSemantics::BFloat, - "float vectors must preserve exact floating-point semantics"); - Context.expect(ScalableVector->toString() == "<vscale x 1 x bf16>", - "scalable float vector spelling must preserve exact semantics"); + "scalable vector LowLevelType must preserve scalability"); + Context.expect(ScalableVector->isVectorValue(), + "category-neutral vectors must preserve their value kind"); + Context.expect(ScalableVector->scalarElementType() == S16, + "scalable vectors must preserve their element type"); + Context.expect(ScalableVector->toString() == "<vscale x 1 x s16>", + "scalable vector spelling must preserve its shape"); } - Context.expect(!rcc::LLT::makeFixedVector(1, *I33), "single-lane fixed vectors must be rejected"); - Context.expect(!rcc::LLT::makeScalableVector(0, *I33), + Context.expect(!rcc::LowLevelType::makeFixedVector(1, *I33), + "single-lane fixed vectors must be rejected"); + Context.expect(!rcc::LowLevelType::makeScalableVector(0, *I33), "zero-lane scalable vectors must be rejected"); - Context.expect(!rcc::LLT::makeFixedVector(4, Token), "token vector elements must be rejected"); + Context.expect(!rcc::LowLevelType::makeFixedVector(4, Token), + "token vector elements must be rejected"); if (FixedVector) { - Context.expect(!rcc::LLT::makeFixedVector(4, *FixedVector), - "nested LLT vectors must be rejected"); + Context.expect(!rcc::LowLevelType::makeFixedVector(4, *FixedVector), + "nested LowLevelType vectors must be rejected"); } } diff --git a/backend/unittests/CodeGen/GenericOpcodesTest.cpp b/backend/unittests/CodeGen/GenericOpcodesTest.cpp index 73c1c36..f946c90 100644 --- a/backend/unittests/CodeGen/GenericOpcodesTest.cpp +++ b/backend/unittests/CodeGen/GenericOpcodesTest.cpp @@ -53,7 +53,8 @@ private: return std::move(*Operand); } -[[nodiscard]] rcc::Register createVirtualRegister(rcc::MachineFunction &Function, rcc::LLT Type) { +[[nodiscard]] rcc::Register createVirtualRegister(rcc::MachineFunction &Function, + rcc::LowLevelType Type) { auto Reg = Function.registerInfo().createVirtualRegister(Type); if (!Reg) std::terminate(); @@ -284,16 +285,19 @@ void testShapesAndTypes(TestContext &Context) { if (!Set || !Function) return; - auto I32 = rcc::LLT::makeInteger(32); - auto I64 = rcc::LLT::makeInteger(64); - auto I1 = rcc::LLT::makeInteger(1); - auto S16 = rcc::LLT::makeAnyScalar(16); - auto F32 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEESingle); - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); - auto P64 = rcc::LLT::makePointer(0, 64); - auto V2I32 = I32 ? rcc::LLT::makeFixedVector(2, *I32) : rcc::Expected<rcc::LLT>{}; - auto V4I32 = I32 ? rcc::LLT::makeFixedVector(4, *I32) : rcc::Expected<rcc::LLT>{}; - auto V2P64 = P64 ? rcc::LLT::makeFixedVector(2, *P64) : rcc::Expected<rcc::LLT>{}; + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); + auto S16 = rcc::LowLevelType::makeCategoryNeutralScalar(16); + auto F32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto P64 = rcc::LowLevelType::makePointer(0, 64); + auto V2I32 = + I32 ? rcc::LowLevelType::makeFixedVector(2, *I32) : rcc::Expected<rcc::LowLevelType>{}; + auto V4I32 = + I32 ? rcc::LowLevelType::makeFixedVector(4, *I32) : rcc::Expected<rcc::LowLevelType>{}; + auto V2P64 = + P64 ? rcc::LowLevelType::makeFixedVector(2, *P64) : rcc::Expected<rcc::LowLevelType>{}; if (!I1 || !I32 || !I64 || !S16 || !F32 || !F64 || !P64 || !V2I32 || !V4I32 || !V2P64) std::terminate(); auto Dst32 = (*Function)->registerInfo().createVirtualRegister(*I32); @@ -324,7 +328,7 @@ void testShapesAndTypes(TestContext &Context) { AddOperands.back() = registerOperand(*Wide, false); Context.expect(!Set->validateExplicitOperands(rcc::opcode(rcc::GenericOpcode::G_ADD), AddOperands, (*Function)->registerInfo()), - "G_ADD must reject a source from a different LLT equality group"); + "G_ADD must reject a source from a different LowLevelType equality group"); auto ZeroImmediate = rcc::APInt::fromUnsigned(64, 0); std::vector<rcc::MachineOperand> PointerConstant; @@ -483,10 +487,6 @@ void testShapesAndTypes(TestContext &Context) { FloatingLoad, (*Function)->registerInfo()) .has_value(), "G_FPEXTLOAD must accept a scalar floating result and pointer address"); - FloatingLoad[0] = registerOperand(*Wide, true); - Context.expect(!Set->validateExplicitOperands(rcc::opcode(rcc::GenericOpcode::G_FPEXTLOAD), - FloatingLoad, (*Function)->registerInfo()), - "G_FPEXTLOAD must reject an integer result"); const std::array<std::uint64_t, 1> FloatWords{0}; auto FloatBits = rcc::APFloat::create(rcc::FloatSemantics::IEEESingle, FloatWords); @@ -513,7 +513,7 @@ void testShapesAndTypes(TestContext &Context) { Context.expect(Set->validateExplicitOperands(rcc::opcode(rcc::GenericOpcode::G_FCONSTANT), FConstantOperands, (*Function)->registerInfo()) .has_value(), - "G_FCONSTANT must accept a bit-width-compatible LLVM scalar LLT"); + "G_FCONSTANT must accept a bit-width-compatible LLVM scalar LowLevelType"); } void testInstructionMemorySemantics(TestContext &Context) { @@ -524,12 +524,12 @@ void testInstructionMemorySemantics(TestContext &Context) { if (!Set || !Function) return; - const rcc::LLT I1 = *rcc::LLT::makeInteger(1); - const rcc::LLT I32 = *rcc::LLT::makeInteger(32); - const rcc::LLT I64 = *rcc::LLT::makeInteger(64); - const rcc::LLT F64 = *rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); - const rcc::LLT P0 = *rcc::LLT::makePointer(0, 64); - const rcc::LLT P1 = *rcc::LLT::makePointer(1, 64); + const rcc::LowLevelType I1 = *rcc::LowLevelType::makeCategoryNeutralScalar(1); + const rcc::LowLevelType I32 = *rcc::LowLevelType::makeCategoryNeutralScalar(32); + const rcc::LowLevelType I64 = *rcc::LowLevelType::makeCategoryNeutralScalar(64); + const rcc::LowLevelType F64 = *rcc::LowLevelType::makeCategoryNeutralScalar(64); + const rcc::LowLevelType P0 = *rcc::LowLevelType::makePointer(0, 64); + const rcc::LowLevelType P1 = *rcc::LowLevelType::makePointer(1, 64); const rcc::Register Dst32 = createVirtualRegister(**Function, I32); const rcc::Register Dst64 = createVirtualRegister(**Function, I64); const rcc::Register Src32 = createVirtualRegister(**Function, I32); @@ -555,7 +555,7 @@ void testInstructionMemorySemantics(TestContext &Context) { createInstruction(**Function, rcc::GenericOpcode::G_LOAD, std::move(OversizedLoadOperands)); addMemOperand(**Function, OversizedLoad, memoryDescription({rcc::MemoryAccessFlag::Load}, 8)); Context.expect(!Set->validateInstruction(OversizedLoad, (*Function)->registerInfo()), - "G_LOAD must reject an MMO larger than its result LLT"); + "G_LOAD must reject an MMO larger than its result LowLevelType"); std::vector<rcc::MachineOperand> WrongAddressSpaceOperands; WrongAddressSpaceOperands.push_back(registerOperand(Dst64, true)); @@ -648,18 +648,6 @@ void testInstructionMemorySemantics(TestContext &Context) { Context.expect(Set->validateInstruction(FloatingAtomic, (*Function)->registerInfo()).has_value(), "floating atomic RMW must accept a scalar floating value and RMW MMO"); - std::vector<rcc::MachineOperand> WrongFloatingAtomicOperands; - WrongFloatingAtomicOperands.push_back(registerOperand(Dst64, true)); - WrongFloatingAtomicOperands.push_back(registerOperand(Address0, false)); - WrongFloatingAtomicOperands.push_back(registerOperand(Src64, false)); - rcc::MachineInstr &WrongFloatingAtomic = createInstruction( - **Function, rcc::GenericOpcode::G_ATOMICRMW_FADD, std::move(WrongFloatingAtomicOperands)); - addMemOperand(**Function, WrongFloatingAtomic, - memoryDescription({rcc::MemoryAccessFlag::Load, rcc::MemoryAccessFlag::Store}, 8, 0, - rcc::AtomicOperation::ReadModifyWrite)); - Context.expect(!Set->validateInstruction(WrongFloatingAtomic, (*Function)->registerInfo()), - "floating atomic RMW must reject integer value registers"); - std::vector<rcc::MachineOperand> PrefetchOperands; PrefetchOperands.push_back(registerOperand(Address0, false)); PrefetchOperands.push_back(rcc::MachineOperand::immediate(0)); diff --git a/backend/unittests/CodeGen/GlobalISel/GISelMITest.h b/backend/unittests/CodeGen/GlobalISel/GISelMITest.h index 5b16535..20e8854 100644 --- a/backend/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/backend/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -58,8 +58,8 @@ struct FunctionFixture final { [[nodiscard]] inline rcc::Register createRegister(TestContext &Context, rcc::MachineFunction &Function, std::uint32_t Bits) { - auto Type = rcc::LLT::makeInteger(Bits); - Context.expect(Type.has_value(), "integer LLT construction must succeed"); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(Bits); + Context.expect(Type.has_value(), "integer LowLevelType construction must succeed"); if (!Type) return {}; auto Reg = Function.registerInfo().createVirtualRegister(*Type); @@ -69,8 +69,8 @@ createRegister(TestContext &Context, rcc::MachineFunction &Function, std::uint32 [[nodiscard]] inline rcc::Register createFloatRegister(TestContext &Context, rcc::MachineFunction &Function) { - auto Type = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); - Context.expect(Type.has_value(), "floating LLT construction must succeed"); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); + Context.expect(Type.has_value(), "floating LowLevelType construction must succeed"); if (!Type) return {}; auto Reg = Function.registerInfo().createVirtualRegister(*Type); diff --git a/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp b/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp index 30c2b89..6d9fa3c 100644 --- a/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp +++ b/backend/unittests/CodeGen/GlobalISel/InstructionSelectTest.cpp @@ -252,9 +252,9 @@ void testExtendedRV64GCPipeline(TestContext &Context) { "extended pipeline fixture must be complete"); if (!Target || !Fixture.Function || Fixture.Entry == nullptr) return; - auto I1 = rcc::LLT::makeInteger(1); - auto I64 = rcc::LLT::makeInteger(64); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); if (!I1 || !I64 || !Pointer) return; const rcc::Register Left = createRegister(Context, *Fixture.Function, 64); diff --git a/backend/unittests/CodeGen/InstructionDescriptorTest.cpp b/backend/unittests/CodeGen/InstructionDescriptorTest.cpp index 687e723..d263725 100644 --- a/backend/unittests/CodeGen/InstructionDescriptorTest.cpp +++ b/backend/unittests/CodeGen/InstructionDescriptorTest.cpp @@ -197,7 +197,7 @@ void testOperandValidation(TestContext &Context) { if (!Function) return; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = (*Function)->registerInfo().createVirtualRegister(*I64); auto Source = (*Function)->registerInfo().createVirtualRegister(*I64); Context.expect(Destination && Source, "descriptor test virtual registers must be allocated"); @@ -261,7 +261,7 @@ void testInstructionValidation(TestContext &Context) { if (!InstructionSet || !Function) return; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = (*Function)->registerInfo().createVirtualRegister(*I64); Context.expect(Reg.has_value(), "instruction validation register must be allocated"); if (!Reg) diff --git a/backend/unittests/CodeGen/LiveTestSupport.h b/backend/unittests/CodeGen/LiveTestSupport.h index 071e572..f6a3566 100644 --- a/backend/unittests/CodeGen/LiveTestSupport.h +++ b/backend/unittests/CodeGen/LiveTestSupport.h @@ -152,7 +152,7 @@ createFunction(std::string Name, std::uint64_t ID, std::size_t BlockCount) { } [[nodiscard]] inline rcc::Expected<rcc::Register> createVReg(rcc::MachineFunction &Function) { - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto Reg = Function.registerInfo().createVirtualRegister(*Type); diff --git a/backend/unittests/CodeGen/MachineAnalysesTest.cpp b/backend/unittests/CodeGen/MachineAnalysesTest.cpp index 997d031..53cd847 100644 --- a/backend/unittests/CodeGen/MachineAnalysesTest.cpp +++ b/backend/unittests/CodeGen/MachineAnalysesTest.cpp @@ -228,8 +228,8 @@ void testMemoryDependence(TestContext &Context, const rcc::TargetDescription &Ta } auto Block = appendBlock(**Function); auto OtherBlock = appendBlock(**Function); - auto I64 = rcc::LLT::makeInteger(64); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); auto Value = I64 ? (*Function)->registerInfo().createVirtualRegister(*I64) : rcc::Expected<rcc::Register>{std::unexpected(I64.error())}; auto Address = Pointer ? (*Function)->registerInfo().createVirtualRegister(*Pointer) @@ -397,7 +397,7 @@ void testCFGUpdaterPHIs(TestContext &Context, const rcc::TargetDescription &Targ return; } - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = I64 ? (*Function)->registerInfo().createVirtualRegister(*I64) : rcc::Expected<rcc::Register>{std::unexpected(I64.error())}; auto SourceValue = I64 ? (*Function)->registerInfo().createVirtualRegister(*I64) @@ -475,7 +475,7 @@ void testCFGUpdaterFailureAtomicity(TestContext &Context, const rcc::TargetDescr if (!SplitUpdater.addSuccessor(**Source, **Merge, rcc::BranchProbability::one())) return; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = I64 ? (*SplitFunction)->registerInfo().createVirtualRegister(*I64) : rcc::Expected<rcc::Register>{std::unexpected(I64.error())}; auto Value = I64 ? (*SplitFunction)->registerInfo().createVirtualRegister(*I64) diff --git a/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp b/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp index e5acc04..82bcce1 100644 --- a/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp +++ b/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp @@ -305,7 +305,7 @@ struct SourceFixture final { auto HistoricalInstruction = Function.createInstruction(rcc::Opcode::fromValue(NopOpcode)); Context.expect(HistoricalBlock && HistoricalInstruction, "source arena history must be created"); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Tombstone = Function.registerInfo().createVirtualRegister(*Type); Context.expect(Tombstone && Function.registerInfo().eraseVirtualRegister(*Tombstone).has_value(), "source vreg history must contain a tombstone"); diff --git a/backend/unittests/CodeGen/MachineIRBuilderTest.cpp b/backend/unittests/CodeGen/MachineIRBuilderTest.cpp index 44a0e32..17e9874 100644 --- a/backend/unittests/CodeGen/MachineIRBuilderTest.cpp +++ b/backend/unittests/CodeGen/MachineIRBuilderTest.cpp @@ -186,7 +186,7 @@ void testTransactionalBuild(TestContext &Context) { if (Block == nullptr) return; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = Function->registerInfo().createVirtualRegister(*Type); auto Source = Function->registerInfo().createVirtualRegister(*Type); Context.expect(Destination && Source, "builder virtual registers must be allocated"); @@ -331,7 +331,7 @@ void testImplicitAndMemoryValidation(TestContext &Context) { if (Block == nullptr || OtherBlock == nullptr) return; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = Function->registerInfo().createVirtualRegister(*Type); auto Source = Function->registerInfo().createVirtualRegister(*Type); Context.expect(Destination && Source, "implicit test virtual registers must be allocated"); @@ -497,7 +497,7 @@ void testStaleCursorsAndOwnedOperands(TestContext &Context) { if (Block == nullptr) return; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = Function->registerInfo().createVirtualRegister(*Type); auto Source = Function->registerInfo().createVirtualRegister(*Type); if (!Destination || !Source) diff --git a/backend/unittests/CodeGen/MachineIRCoreTest.cpp b/backend/unittests/CodeGen/MachineIRCoreTest.cpp index 6365e59..875eeb8 100644 --- a/backend/unittests/CodeGen/MachineIRCoreTest.cpp +++ b/backend/unittests/CodeGen/MachineIRCoreTest.cpp @@ -116,7 +116,8 @@ void testOperandKinds(TestContext &Context) { Context.expect(!rcc::APFloat::create(rcc::FloatSemantics::IEEEHalf, TooManyHalfWords), "floating immediate word-count mismatch must be rejected"); - auto Virtual = Function->registerInfo().createVirtualRegister(*rcc::LLT::makeInteger(32)); + auto Virtual = Function->registerInfo().createVirtualRegister( + *rcc::LowLevelType::makeCategoryNeutralScalar(32)); Context.expect(Virtual.has_value(), "operand test virtual register must be created"); if (!Virtual) return; @@ -205,7 +206,7 @@ void testRegisterInfoAndOperandMovement(TestContext &Context) { if (Block == nullptr) return; - auto I32 = rcc::LLT::makeInteger(32); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); Context.expect(I32.has_value(), "i32 construction for MRI test must succeed"); if (!I32) return; @@ -317,7 +318,7 @@ void testRegisterInfoAndOperandMovement(TestContext &Context) { Context.expect(V0Info && V0Info->get().Type == I32 && V0Info->get().Bank == rcc::RegisterBankID::fromValue(3) && V0Info->get().RegClass == rcc::RegisterClassID::fromValue(4), - "MRI virtual register properties must evolve without losing LLT"); + "MRI virtual register properties must evolve without losing LowLevelType"); Context.expect(MRI.addLiveIn(*PhysReg, *V0).has_value(), "MRI must record function physical live-ins"); diff --git a/backend/unittests/CodeGen/MachineOptimizationTest.cpp b/backend/unittests/CodeGen/MachineOptimizationTest.cpp index bb2c0e1..cffd4e1 100644 --- a/backend/unittests/CodeGen/MachineOptimizationTest.cpp +++ b/backend/unittests/CodeGen/MachineOptimizationTest.cpp @@ -169,10 +169,10 @@ void setPostRAProperties(rcc::MachineFunction &Function) { } [[nodiscard]] rcc::Register makeGPR(TestContext &Context, rcc::MachineFunction &Function) { - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Type ? Function.registerInfo().createVirtualRegister(*Type) - : rcc::Expected<rcc::Register>(std::unexpected( - rcc::Error(rcc::ErrorCode::InternalError, "test LLT creation failed"))); + : rcc::Expected<rcc::Register>(std::unexpected(rcc::Error( + rcc::ErrorCode::InternalError, "test LowLevelType creation failed"))); Context.expect(Reg.has_value(), "optimization virtual register creation must succeed"); if (!Reg) return {}; diff --git a/backend/unittests/CodeGen/MachineSchedulingTest.cpp b/backend/unittests/CodeGen/MachineSchedulingTest.cpp index 5162fb8..a3d1de9 100644 --- a/backend/unittests/CodeGen/MachineSchedulingTest.cpp +++ b/backend/unittests/CodeGen/MachineSchedulingTest.cpp @@ -178,10 +178,10 @@ makeSchedulingModel(const rcc::TargetSchedulingHooks *Hooks = nullptr) { } [[nodiscard]] rcc::Register makeGPR(TestContext &Context, rcc::MachineFunction &Function) { - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Type ? Function.registerInfo().createVirtualRegister(*Type) - : rcc::Expected<rcc::Register>(std::unexpected( - rcc::Error(rcc::ErrorCode::InternalError, "test LLT creation failed"))); + : rcc::Expected<rcc::Register>(std::unexpected(rcc::Error( + rcc::ErrorCode::InternalError, "test LowLevelType creation failed"))); Context.expect(Reg.has_value(), "scheduler virtual register creation must succeed"); if (!Reg) return {}; diff --git a/backend/unittests/CodeGen/MachineValueTypesTest.cpp b/backend/unittests/CodeGen/MachineValueTypesTest.cpp index 819d6cb..315d56e 100644 --- a/backend/unittests/CodeGen/MachineValueTypesTest.cpp +++ b/backend/unittests/CodeGen/MachineValueTypesTest.cpp @@ -184,9 +184,9 @@ void testMachineMemOperand(TestContext &Context) { "failure ordering stronger than success must be rejected"); auto BadAddressSpace = makeBasicLoadDescription(); - BadAddressSpace.AddressSpace = rcc::LLT::MaxAddressSpace + 1; + BadAddressSpace.AddressSpace = rcc::LowLevelType::MaxAddressSpace + 1; Context.expect(!rcc::MachineMemOperand::create(BadAddressSpace), - "MMO address space wider than LLT encoding must be rejected"); + "MMO address space wider than LowLevelType encoding must be rejected"); auto EmptySymbol = makeBasicLoadDescription(); EmptySymbol.Base = rcc::MemoryBase::externalSymbol(""); diff --git a/backend/unittests/CodeGen/MachineVerifierTargetTest.cpp b/backend/unittests/CodeGen/MachineVerifierTargetTest.cpp index 3eb926d..3cc2b56 100644 --- a/backend/unittests/CodeGen/MachineVerifierTargetTest.cpp +++ b/backend/unittests/CodeGen/MachineVerifierTargetTest.cpp @@ -186,7 +186,7 @@ void testValidTargetFacts(TestContext &Context, const rcc::TargetDescription &Ta if (!Fixture.Function) return; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); if (!Reg) return; @@ -233,7 +233,7 @@ void testSubRegisterProjection(TestContext &Context, const rcc::TargetDescriptio if (!Fixture.Function) return; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); if (!Reg) return; @@ -282,7 +282,7 @@ void testUnknownAndMalformedTargetFacts(TestContext &Context, } { auto Fixture = createFunction(Context, "unknown_bank", 5); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Fixture.Function || !Type) return; auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); @@ -295,7 +295,7 @@ void testUnknownAndMalformedTargetFacts(TestContext &Context, } { auto Fixture = createFunction(Context, "wide_bank_value", 6); - auto Type = rcc::LLT::makeInteger(128); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(128); if (!Fixture.Function || !Type) return; auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); @@ -325,7 +325,7 @@ void testUnknownAndMalformedTargetFacts(TestContext &Context, } { auto Fixture = createFunction(Context, "bad_allocation_hint", 9); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); Context.expect(Reg && classify(Fixture.Function->registerInfo(), *Reg, @@ -340,7 +340,7 @@ void testUnknownAndMalformedTargetFacts(TestContext &Context, } { auto Fixture = createFunction(Context, "reserved_allocation_hint", 14); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); const auto G0 = phys(rcc::test::TestRegister::G0); Context.expect(Reg && @@ -355,7 +355,7 @@ void testUnknownAndMalformedTargetFacts(TestContext &Context, } { auto Fixture = createFunction(Context, "incompatible_function_livein", 15); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Reg = Fixture.Function->registerInfo().createVirtualRegister(*Type); Context.expect( Reg && @@ -416,7 +416,7 @@ void testRegMaskEarlyClobberAndTies(TestContext &Context, const rcc::TargetDescr } { auto Fixture = createFunction(Context, "incompatible_tie", 12); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto GPR = Fixture.Function->registerInfo().createVirtualRegister(*Type); auto FPR = Fixture.Function->registerInfo().createVirtualRegister(*Type); if (!GPR || !FPR) diff --git a/backend/unittests/CodeGen/MachineVerifierTest.cpp b/backend/unittests/CodeGen/MachineVerifierTest.cpp index c8c512f..5327148 100644 --- a/backend/unittests/CodeGen/MachineVerifierTest.cpp +++ b/backend/unittests/CodeGen/MachineVerifierTest.cpp @@ -196,7 +196,7 @@ buildNoOperand(TestContext &Context, rcc::MachineIRBuilder &Builder, std::uint32 if (Entry == nullptr || Exit == nullptr) return false; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Value = Function.registerInfo().createVirtualRegister(*Type); Context.expect(Value.has_value(), "typed verifier virtual register must be allocated"); if (!Value) @@ -338,7 +338,7 @@ createPhiTestFunction(TestContext &Context, const rcc::TargetDescription &Target return nullptr; } - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Destination = Type ? Function->registerInfo().createVirtualRegister(*Type) : rcc::Expected<rcc::Register>{std::unexpected(Type.error())}; auto LeftValue = Type ? Function->registerInfo().createVirtualRegister(*Type) @@ -411,7 +411,7 @@ void testPropertyFailures(TestContext &Context) { auto Target = createTarget(); if (!Target) return; - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto SSA = createFunction(Context, "ssa", 6); rcc::MachineBasicBlock *SSABlock = SSA ? createBlock(Context, *SSA) : nullptr; @@ -503,7 +503,7 @@ void testPropertyFailures(TestContext &Context) { void testSelectedStateAndPseudoDeadline(TestContext &Context) { auto Target = createTarget(); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Target) return; diff --git a/backend/unittests/CodeGen/PHIEliminationTest.cpp b/backend/unittests/CodeGen/PHIEliminationTest.cpp index 9bc9a57..bbc834f 100644 --- a/backend/unittests/CodeGen/PHIEliminationTest.cpp +++ b/backend/unittests/CodeGen/PHIEliminationTest.cpp @@ -90,7 +90,7 @@ void testParallelPHIsAndPlacement(TestContext &Context, const rcc::TargetDescrip auto Fixture = createFunction(Context, "parallel_phis", 1, 3); if (!Fixture.Function || Fixture.Blocks.size() != 3) return; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!I64) return; auto &Function = *Fixture.Function; @@ -209,7 +209,7 @@ void testParallelPHIsAndPlacement(TestContext &Context, const rcc::TargetDescrip Context.expect(FreshInfo.has_value(), "fresh PHI vreg must remain registered"); if (!FreshInfo) return; - Context.expect(FreshInfo->get().Type == I64, "fresh PHI vreg must clone its LLT"); + Context.expect(FreshInfo->get().Type == I64, "fresh PHI vreg must clone its LowLevelType"); Context.expect(FreshInfo->get().Bank == rcc::test::TestRegisterBank::GPR, "fresh PHI vreg must clone its register bank"); Context.expect(FreshInfo->get().RegClass == rcc::test::TestRegisterClass::GPR64, @@ -241,7 +241,7 @@ void testCriticalEdgeAndPhysicalLiveIn(TestContext &Context, const rcc::TargetDe auto Fixture = createFunction(Context, "critical_edge", 2, 4); if (!Fixture.Function || Fixture.Blocks.size() != 4) return; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!I64) return; auto &Function = *Fixture.Function; @@ -343,7 +343,7 @@ void testUndefAndFailureAtomicity(TestContext &Context, const rcc::TargetDescrip auto Fixture = createFunction(Context, "undef_phi", ID, 2); if (!Fixture.Function || Fixture.Blocks.size() != 2) return Fixture; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!I64) return Fixture; auto Source = createVReg(*Fixture.Function, *I64, rcc::test::TestRegisterBank::GPR, @@ -406,9 +406,9 @@ void testUndefAndFailureAtomicity(TestContext &Context, const rcc::TargetDescrip } void testMalformedPHIs(TestContext &Context, const rcc::TargetDescription &Target) { - auto BuildBadPhi = [&](std::uint64_t ID, rcc::LLT DestinationType, + auto BuildBadPhi = [&](std::uint64_t ID, rcc::LowLevelType DestinationType, rcc::RegisterBankID DestinationBank, rcc::RegisterClassID DestinationClass, - rcc::LLT SourceType, rcc::RegisterBankID SourceBank, + rcc::LowLevelType SourceType, rcc::RegisterBankID SourceBank, rcc::RegisterClassID SourceClass, rcc::SubRegIndex SourceSubReg = {}) { auto Fixture = createFunction(Context, "bad_phi", ID, 2); if (!Fixture.Function || Fixture.Blocks.size() != 2) @@ -438,8 +438,8 @@ void testMalformedPHIs(TestContext &Context, const rcc::TargetDescription &Targe return Fixture; }; - auto I64 = rcc::LLT::makeInteger(64); - auto I32 = rcc::LLT::makeInteger(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); if (!I64 || !I32) return; auto BadType = diff --git a/backend/unittests/CodeGen/RegisterAllocationTest.cpp b/backend/unittests/CodeGen/RegisterAllocationTest.cpp index 7dd0dd0..443d00a 100644 --- a/backend/unittests/CodeGen/RegisterAllocationTest.cpp +++ b/backend/unittests/CodeGen/RegisterAllocationTest.cpp @@ -352,7 +352,7 @@ struct FunctionFixture final { [[nodiscard]] rcc::Expected<rcc::Register> createVReg(rcc::MachineFunction &Function, rcc::RegisterClassID Class = rcc::test::TestRegisterClass::GPR64) { - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto Reg = Function.registerInfo().createVirtualRegister(*Type); diff --git a/backend/unittests/CodeGen/RegisterAllocationTestSupport.h b/backend/unittests/CodeGen/RegisterAllocationTestSupport.h index d93b14e..7f0a641 100644 --- a/backend/unittests/CodeGen/RegisterAllocationTestSupport.h +++ b/backend/unittests/CodeGen/RegisterAllocationTestSupport.h @@ -201,7 +201,7 @@ struct FunctionFixture final { [[nodiscard]] inline Expected<Register> createVReg(MachineFunction &Function, RegisterClassID Class = TestRegisterClass::GPR64) { - auto Type = LLT::makeInteger(64); + auto Type = LowLevelType::makeCategoryNeutralScalar(64); if (!Type) return std::unexpected(Type.error()); auto Reg = Function.registerInfo().createVirtualRegister(*Type); diff --git a/backend/unittests/CodeGen/SSAExitTestSupport.h b/backend/unittests/CodeGen/SSAExitTestSupport.h index 5729293..cf77d36 100644 --- a/backend/unittests/CodeGen/SSAExitTestSupport.h +++ b/backend/unittests/CodeGen/SSAExitTestSupport.h @@ -360,7 +360,7 @@ struct FunctionFixture final { } [[nodiscard]] inline rcc::Expected<rcc::Register> -createVReg(rcc::MachineFunction &Function, rcc::LLT Type, rcc::RegisterBankID Bank, +createVReg(rcc::MachineFunction &Function, rcc::LowLevelType Type, rcc::RegisterBankID Bank, rcc::RegisterClassID Class, std::uint8_t TargetFlags = 0, std::optional<rcc::PhysicalRegister> Hint = std::nullopt) { auto Reg = Function.registerInfo().createVirtualRegister(Type); diff --git a/backend/unittests/CodeGen/TargetCallLoweringTest.cpp b/backend/unittests/CodeGen/TargetCallLoweringTest.cpp index c5170d0..22a2b0c 100644 --- a/backend/unittests/CodeGen/TargetCallLoweringTest.cpp +++ b/backend/unittests/CodeGen/TargetCallLoweringTest.cpp @@ -42,8 +42,8 @@ private: return *Value; } -[[nodiscard]] rcc::LLT integer(std::uint32_t Bits) { - const auto Type = rcc::LLT::makeInteger(Bits); +[[nodiscard]] rcc::LowLevelType integer(std::uint32_t Bits) { + const auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(Bits); if (!Type) std::terminate(); return *Type; @@ -207,7 +207,7 @@ void testPlanValidation(TestContext &Context) { auto BadByVal = emptyPlanDescription(rcc::CallLoweringPlanKind::Call); auto ByValAssignment = registerAssignment(); - ByValAssignment.ValueType = *rcc::LLT::makePointer(0, 64); + ByValAssignment.ValueType = *rcc::LowLevelType::makePointer(0, 64); ByValAssignment.LocationType = ByValAssignment.ValueType; ByValAssignment.CustomFlags.set(rcc::CCAssignmentFlag::ByVal); BadByVal.ArgumentAssignments.push_back(ByValAssignment); @@ -219,7 +219,7 @@ void testPlanValidation(TestContext &Context) { auto OverlappingByVal = emptyPlanDescription(rcc::CallLoweringPlanKind::Call); OverlappingByVal.CallFrame.SizeBytes = 32; auto FirstByVal = registerAssignment(); - FirstByVal.ValueType = *rcc::LLT::makePointer(0, 64); + FirstByVal.ValueType = *rcc::LowLevelType::makePointer(0, 64); FirstByVal.LocationType = FirstByVal.ValueType; FirstByVal.CustomFlags.set(rcc::CCAssignmentFlag::ByVal); auto SecondByVal = FirstByVal; diff --git a/backend/unittests/CodeGen/TargetRegisterInfoTest.cpp b/backend/unittests/CodeGen/TargetRegisterInfoTest.cpp index 2c44237..bb9a0fc 100644 --- a/backend/unittests/CodeGen/TargetRegisterInfoTest.cpp +++ b/backend/unittests/CodeGen/TargetRegisterInfoTest.cpp @@ -250,7 +250,7 @@ void testTargetDescriptionConstraints(TestContext &Context) { rcc::test::TestRegisterBank::GPR)); auto Function = rcc::MachineFunction::create("constraints", rcc::MachineFunctionStableID::fromValue(1)); - auto Type = rcc::LLT::makeInteger(64); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!SubclassTarget || !Function || !Type) return; @@ -301,7 +301,7 @@ void testTargetDescriptionConstraints(TestContext &Context) { (*Function)->registerInfo()), "physical register operands must reject nonzero subregister indices"); - auto WideType = rcc::LLT::makeInteger(128); + auto WideType = rcc::LowLevelType::makeCategoryNeutralScalar(128); if (!WideType) return; auto WideReg = (*Function)->registerInfo().createVirtualRegister(*WideType); diff --git a/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp b/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp index e3ad4eb..d23a2eb 100644 --- a/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp +++ b/backend/unittests/CodeGen/TwoAddressInstructionPassTest.cpp @@ -19,8 +19,8 @@ void testTwoAddressAndSubregisterPseudos(TestContext &Context, const rcc::Target auto Fixture = createFunction(Context, "two_address", 5, 1); if (!Fixture.Function || Fixture.Blocks.empty()) return; - auto I64 = rcc::LLT::makeInteger(64); - auto I32 = rcc::LLT::makeInteger(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); if (!I64 || !I32) return; auto &Function = *Fixture.Function; diff --git a/backend/unittests/MIR/MIParserTest.cpp b/backend/unittests/MIR/MIParserTest.cpp index c35dc74..4ed39ae 100644 --- a/backend/unittests/MIR/MIParserTest.cpp +++ b/backend/unittests/MIR/MIParserTest.cpp @@ -265,8 +265,8 @@ bb.1."exit block" (landing-pad, bbsections Cold): Context.expect(Registers.size() == 5 && Registers[0].RegClass == rcc::test::TestRegisterClass::GPR64 && Registers[1].RegClass == rcc::test::TestRegisterClass::GPR64 && - Registers[2].Type == *rcc::LLT::makeAnyScalar(128) && - Registers[3].Type == *rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble) && + Registers[2].Type == *rcc::LowLevelType::makeCategoryNeutralScalar(128) && + Registers[3].Type == *rcc::LowLevelType::makeCategoryNeutralScalar(64) && Registers[4].RegClass == rcc::test::TestRegisterClass::GPR64, "textual virtual registers must map deterministically to classed MachineIR vregs"); @@ -385,7 +385,7 @@ void testAddressSpacePointerWidthResolver(TestContext &Context) { "bb.0:\n %0:_(p1) = TEST_COPY $g0\n", ParserContext, ParserOptions); auto Parsed = Parser.parse(); const auto Registers = Function->registerInfo().virtualRegisters(); - auto ExpectedType = rcc::LLT::makePointer(1, 32); + auto ExpectedType = rcc::LowLevelType::makePointer(1, 32); Context.expect(Parsed.has_value() && ExpectedType.has_value() && Registers.size() == 1 && Registers.front().Type == *ExpectedType, "MI parser must use the address-space-specific pointer-width resolver"); @@ -396,35 +396,6 @@ void testAddressSpacePointerWidthResolver(TestContext &Context) { } } -void testUnserializableLowLevelType(TestContext &Context) { - auto Target = createTarget(); - auto Function = createFunction(Context, 4); - Context.expect(Target.has_value(), "unserializable-type target must be valid"); - if (!Target || !Function) - return; - - rcc::mir::MIParserOptions ParserOptions; - ParserOptions.VerifyAfterParse = false; - rcc::mir::MIParser Parser(*Function, *Target, "unserializable-type.mir", - "bb.0:\n %0:gpr64(f64) = TEST_COPY $g0\n", {}, ParserOptions); - auto Parsed = Parser.parse(); - auto Register = rcc::Register::makeVirtual(0); - auto UnsupportedType = rcc::LLT::makeFloat(rcc::FloatSemantics::Float8E5M2); - Context.expect(Parsed.has_value() && Register.has_value() && UnsupportedType.has_value(), - "unserializable-type test setup must parse a typed virtual register"); - if (!Parsed || !Register || !UnsupportedType) - return; - auto SetType = Function->registerInfo().setType(*Register, *UnsupportedType); - Context.expect(SetType.has_value(), "test setup must assign an extended floating low-level type"); - if (!SetType) - return; - - auto Printed = rcc::mir::printMachineFunctionBody(*Function, *Target); - Context.expect(!Printed && Printed.error().message().find("cannot spell this floating") != - std::string_view::npos, - "printer must reject extended low-level types absent from fixed LLVM MIR grammar"); -} - void expectParseError(TestContext &Context, const rcc::TargetDescription &Target, std::string Body, std::string_view Message); @@ -525,7 +496,7 @@ void testLLVMInlineAsmAndConstantMemorySyntax(TestContext &Context) { const auto *ExtraInfo = InlineAsm->operandAt(1)->getIf<std::int64_t>(); const rcc::MachineInstr *Load = InlineAsm->next(); const rcc::MachineMemOperandDesc &Memory = Load->memOperands().front()->description(); - const auto MemoryType = rcc::LLT::makeAnyScalar(64); + const auto MemoryType = rcc::LowLevelType::makeCategoryNeutralScalar(64); Context.expect(ExtraInfo != nullptr && *ExtraInfo == 13, "inline-asm extra-info names must aggregate into the LLVM bit field"); Context.expect(Memory.Base.kind() == rcc::MemoryBase::Kind::IRConstant && @@ -629,7 +600,6 @@ int main() { TestContext Context; testTwoPassBodyParsing(Context); testAddressSpacePointerWidthResolver(Context); - testUnserializableLowLevelType(Context); testCompatibleRegisterClassAndBankAnnotations(Context); testTypedIntegerTruncation(Context); testLLVMInlineAsmAndConstantMemorySyntax(Context); diff --git a/backend/unittests/MIR/MIRDocumentTest.cpp b/backend/unittests/MIR/MIRDocumentTest.cpp index 7f1dfc3..6d84580 100644 --- a/backend/unittests/MIR/MIRDocumentTest.cpp +++ b/backend/unittests/MIR/MIRDocumentTest.cpp @@ -558,7 +558,7 @@ void testHeterogeneousPointerLayout(TestContext &Context) { } const rcc::MachineFunction *Function = Parsed.document()->unit().function("pointer_layout"); - auto PointerType = rcc::LLT::makePointer(1, 32); + auto PointerType = rcc::LowLevelType::makePointer(1, 32); const rcc::MachineConstantPoolEntry *Constant = Function == nullptr ? nullptr : Function->constantPool().entry(rcc::ConstantPoolIndex::fromValue(0)); @@ -584,7 +584,7 @@ void testHeterogeneousPointerLayout(TestContext &Context) { : OverriddenFunction->constantPool().entry(rcc::ConstantPoolIndex::fromValue(0)); const rcc::MachineConstantPoolEntryDesc *OverriddenConstantDescription = OverriddenConstant == nullptr ? nullptr : OverriddenConstant->description(); - const auto OverriddenPointerType = rcc::LLT::makePointer(1, 64); + const auto OverriddenPointerType = rcc::LowLevelType::makePointer(1, 64); Context.expect(Overridden.succeeded() && OverriddenFunction != nullptr && OverriddenPointerType.has_value() && OverriddenFunction->registerInfo().virtualRegisters().size() == 1 && diff --git a/backend/unittests/Target/RISCVCallLoweringTest.cpp b/backend/unittests/Target/RISCVCallLoweringTest.cpp index eee10ab..738aeb1 100644 --- a/backend/unittests/Target/RISCVCallLoweringTest.cpp +++ b/backend/unittests/Target/RISCVCallLoweringTest.cpp @@ -61,29 +61,30 @@ private: return *Value; } -[[nodiscard]] rcc::LLT integer(std::uint32_t Bits) { - const auto Type = rcc::LLT::makeInteger(Bits); +[[nodiscard]] rcc::LowLevelType integer(std::uint32_t Bits) { + const auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(Bits); if (!Type) std::terminate(); return *Type; } -[[nodiscard]] rcc::LLT anyScalar(std::uint32_t Bits) { - const auto Type = rcc::LLT::makeAnyScalar(Bits); +[[nodiscard]] rcc::LowLevelType anyScalar(std::uint32_t Bits) { + const auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(Bits); if (!Type) std::terminate(); return *Type; } -[[nodiscard]] rcc::LLT floating(rcc::FloatSemantics Semantics) { - const auto Type = rcc::LLT::makeFloat(Semantics); +[[nodiscard]] rcc::LowLevelType floating(rcc::FloatSemantics Semantics) { + const std::uint32_t Bits = Semantics == rcc::FloatSemantics::IEEESingle ? 32 : 64; + const auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(Bits); if (!Type) std::terminate(); return *Type; } -[[nodiscard]] rcc::LLT pointer() { - const auto Type = rcc::LLT::makePointer(0, 64); +[[nodiscard]] rcc::LowLevelType pointer() { + const auto Type = rcc::LowLevelType::makePointer(0, 64); if (!Type) std::terminate(); return *Type; @@ -128,13 +129,16 @@ private: return rcc::Register::fromPhysical(physical(rcc::riscv::PhysicalRegisterID::X5)); } -[[nodiscard]] rcc::ABIValue -abiValue(rcc::LLT Type, std::uint32_t OriginalValue, rcc::Register Value = planningRegister(), - rcc::ABIExtensionKind Extension = rcc::ABIExtensionKind::None) { +[[nodiscard]] rcc::ABIValue abiValue(rcc::LowLevelType Type, std::uint32_t OriginalValue, + rcc::Register Value = planningRegister(), + rcc::ABIExtensionKind Extension = rcc::ABIExtensionKind::None, + std::optional<rcc::ABIValueCategory> Category = std::nullopt) { const std::uint64_t Size = std::max<std::uint64_t>(1, (Type.scalarBitWidth() + 7U) / 8U); return { .Value = Value, .Type = Type, + .Category = Category.value_or(Type.isPointer() ? rcc::ABIValueCategory::Pointer + : rcc::ABIValueCategory::Integer), .OriginalValue = OriginalValue, .FragmentIndex = 0, .FragmentCount = 1, @@ -147,6 +151,13 @@ abiValue(rcc::LLT Type, std::uint32_t OriginalValue, rcc::Register Value = plann }; } +[[nodiscard]] rcc::ABIValue floatingABIValue(rcc::FloatSemantics Semantics, + std::uint32_t OriginalValue, + rcc::Register Value = planningRegister()) { + return abiValue(floating(Semantics), OriginalValue, Value, rcc::ABIExtensionKind::None, + rcc::ABIValueCategory::FloatingPoint); +} + [[nodiscard]] std::vector<rcc::ABIValue> integerValues(std::size_t Count) { std::vector<rcc::ABIValue> Values; Values.reserve(Count); @@ -160,7 +171,7 @@ abiValue(rcc::LLT Type, std::uint32_t OriginalValue, rcc::Register Value = plann Values.reserve(Count); for (std::size_t Index = 0; Index < Count; ++Index) { Values.push_back( - abiValue(floating(rcc::FloatSemantics::IEEEDouble), static_cast<std::uint32_t>(Index))); + floatingABIValue(rcc::FloatSemantics::IEEEDouble, static_cast<std::uint32_t>(Index))); } return Values; } @@ -230,8 +241,8 @@ void testIntegerAndFloatingAssignments(TestContext &Context) { FloatAssignments[16].StackOffsetBytes == 0, "LP64D floating arguments must fall back from fa0-fa7 to a0-a7 and then stack"); - auto Single = callRequest({abiValue(floating(rcc::FloatSemantics::IEEESingle), 0)}, 1); - Single.Results = {abiValue(floating(rcc::FloatSemantics::IEEESingle), 0)}; + auto Single = callRequest({floatingABIValue(rcc::FloatSemantics::IEEESingle, 0)}, 1); + Single.Results = {floatingABIValue(rcc::FloatSemantics::IEEESingle, 0)}; auto SinglePlan = CallLowering.planCall(Single); Context.expect(SinglePlan && SinglePlan->argumentAssignments().size() == 1 && SinglePlan->returnAssignments().size() == 1 && @@ -241,7 +252,7 @@ void testIntegerAndFloatingAssignments(TestContext &Context) { physical(rcc::riscv::PhysicalRegisterID::F10_F)), "LP64D f32 arguments and returns must use the FPR32 physical-register view"); - auto FloatFragment = abiValue(floating(rcc::FloatSemantics::IEEEDouble), 0); + auto FloatFragment = floatingABIValue(rcc::FloatSemantics::IEEEDouble, 0); FloatFragment.FragmentCount = 2; FloatFragment.OriginalAlignment = align(16); auto IntegerFragment = abiValue(integer(64), 0); @@ -265,9 +276,9 @@ void testIntegerAndFloatingAssignments(TestContext &Context) { GenericScalarPlan->returnAssignments()[0].ValueType == anyScalar(64), "LLVM generic scalar LLTs must use integer ABI transport without type loss"); - auto LP64Float = callRequest({abiValue(floating(rcc::FloatSemantics::IEEEDouble), 0)}, 1); + auto LP64Float = callRequest({floatingABIValue(rcc::FloatSemantics::IEEEDouble, 0)}, 1); LP64Float.Convention = rcc::riscv::callingConventionID(rcc::riscv::CallingConvention::LP64); - LP64Float.Results = {abiValue(floating(rcc::FloatSemantics::IEEEDouble), 0)}; + LP64Float.Results = {floatingABIValue(rcc::FloatSemantics::IEEEDouble, 0)}; auto LP64Plan = CallLowering.planCall(LP64Float); const auto LP64Mask = rcc::riscv::createCallPreservedMask(rcc::riscv::CallingConvention::LP64); Context.expect( @@ -295,8 +306,8 @@ void testIntegerAndFloatingAssignments(TestContext &Context) { } void testVariadicAssignments(TestContext &Context) { - auto FixedFloat = abiValue(floating(rcc::FloatSemantics::IEEEDouble), 0); - auto VariableFloat = abiValue(floating(rcc::FloatSemantics::IEEEDouble), 1); + auto FixedFloat = floatingABIValue(rcc::FloatSemantics::IEEEDouble, 0); + auto VariableFloat = floatingABIValue(rcc::FloatSemantics::IEEEDouble, 1); auto Request = callRequest({FixedFloat, VariableFloat}, 1, true); auto Plan = CallLowering.planCall(Request); Context.expect( @@ -385,8 +396,7 @@ void testSpecialArgumentsAndReturns(TestContext &Context) { rcc::ReturnLoweringRequest Return; Return.Convention = convention(); - Return.Values = {abiValue(integer(64), 0), - abiValue(floating(rcc::FloatSemantics::IEEEDouble), 1)}; + Return.Values = {abiValue(integer(64), 0), floatingABIValue(rcc::FloatSemantics::IEEEDouble, 1)}; auto ReturnPlan = CallLowering.planReturn(Return); Context.expect(ReturnPlan && ReturnPlan->returnAssignments().size() == 2 && isLocation(ReturnPlan->returnAssignments()[0], returnGPR(0)) && @@ -455,7 +465,8 @@ void testTailCalls(TestContext &Context) { return std::move(*Function); } -[[nodiscard]] rcc::Register virtualRegister(rcc::MachineFunction &Function, rcc::LLT Type) { +[[nodiscard]] rcc::Register virtualRegister(rcc::MachineFunction &Function, + rcc::LowLevelType Type) { auto Register = Function.registerInfo().createVirtualRegister(Type); if (!Register) std::terminate(); @@ -500,12 +511,12 @@ void testOrdinaryAndIndirectEmission(TestContext &Context) { if (!Target || !Function || Block == nullptr) return; - const rcc::LLT I64 = integer(64); - const rcc::LLT F64 = floating(rcc::FloatSemantics::IEEEDouble); + const rcc::LowLevelType I64 = integer(64); + const rcc::LowLevelType F64 = floating(rcc::FloatSemantics::IEEEDouble); const rcc::Register Argument = virtualRegister(*Function, I64); const rcc::Register Result = virtualRegister(*Function, F64); auto Request = callRequest({abiValue(I64, 0, Argument)}, 1); - Request.Results = {abiValue(F64, 0, Result)}; + Request.Results = {floatingABIValue(rcc::FloatSemantics::IEEEDouble, 0, Result)}; rcc::MachineIRBuilder Builder(*Function, *Target); Context.expect(Builder.setInsertPoint(*Block).has_value(), diff --git a/backend/unittests/Target/RISCVCodeGenTest.cpp b/backend/unittests/Target/RISCVCodeGenTest.cpp index 1bc3361..7392f3b 100644 --- a/backend/unittests/Target/RISCVCodeGenTest.cpp +++ b/backend/unittests/Target/RISCVCodeGenTest.cpp @@ -66,7 +66,7 @@ struct InstructionFixture final { auto Block = (*Function)->createBasicBlock(); if (!Block || !(*Function)->appendBlock(**Block)) return {}; - auto Type = rcc::LLT::makeInteger(Bits); + auto Type = rcc::LowLevelType::makeCategoryNeutralScalar(Bits); if (!Type) return {}; auto Left = (*Function)->registerInfo().createVirtualRegister(*Type); @@ -87,29 +87,28 @@ struct InstructionFixture final { } [[nodiscard]] bool constrainRegister(rcc::MachineFunction &Function, rcc::Register Reg, - rcc::LLT Type) { - const auto Bank = Type.isFloat() ? rcc::RegisterBankID::fromValue( - static_cast<std::uint32_t>(rcc::riscv::RegisterBank::FPR)) - : rcc::RegisterBankID::fromValue( - static_cast<std::uint32_t>(rcc::riscv::RegisterBank::GPR)); - const auto Class = Type.isFloat() - ? rcc::RegisterClassID::fromValue(static_cast<std::uint32_t>( - Type.scalarBitWidth() == 32 ? rcc::riscv::RegisterClass::FPR32 - : rcc::riscv::RegisterClass::FPR64)) - : rcc::RegisterClassID::fromValue( - static_cast<std::uint32_t>(rcc::riscv::RegisterClass::GPR)); + rcc::LowLevelType Type, bool Floating = false) { + const auto Bank = rcc::RegisterBankID::fromValue(static_cast<std::uint32_t>( + Floating ? rcc::riscv::RegisterBank::FPR : rcc::riscv::RegisterBank::GPR)); + const auto Class = rcc::RegisterClassID::fromValue(static_cast<std::uint32_t>( + Floating ? (Type.scalarBitWidth() == 32 ? rcc::riscv::RegisterClass::FPR32 + : rcc::riscv::RegisterClass::FPR64) + : rcc::riscv::RegisterClass::GPR)); return Function.registerInfo().setRegisterBank(Reg, Bank).has_value() && Function.registerInfo().setRegisterClass(Reg, Class).has_value(); } -[[nodiscard]] bool constrainVirtualRegisters(rcc::MachineFunction &Function) { +[[nodiscard]] bool constrainVirtualRegisters(rcc::MachineFunction &Function, + bool FloatingValues = false) { const auto Registers = Function.registerInfo().virtualRegisters(); for (std::size_t Index = 0; Index < Registers.size(); ++Index) { const rcc::VirtualRegisterInfo &Info = Registers[Index]; if (Info.IsTombstone) continue; auto Reg = rcc::Register::makeVirtual(Index); - if (!Reg || !Info.Type || !constrainRegister(Function, *Reg, *Info.Type)) + if (!Reg || !Info.Type || + !constrainRegister(Function, *Reg, *Info.Type, + FloatingValues && Info.Type->scalarBitWidth() != 1)) return false; } return true; @@ -128,8 +127,10 @@ struct InstructionFixture final { [[nodiscard]] std::unique_ptr<rcc::MachineFunction> createUnaryFunction(TestContext &Context, const rcc::TargetDescription &Target, - rcc::GenericOpcode Generic, rcc::LLT DestinationType, rcc::LLT SourceType, - rcc::Register *DestinationOut = nullptr, rcc::Register *SourceOut = nullptr) { + rcc::GenericOpcode Generic, rcc::LowLevelType DestinationType, + rcc::LowLevelType SourceType, bool FloatingDestination = false, + bool FloatingSource = false, rcc::Register *DestinationOut = nullptr, + rcc::Register *SourceOut = nullptr) { auto Function = rcc::MachineFunction::create( "riscv_unary", rcc::MachineFunctionStableID::fromValue(200 + static_cast<std::uint32_t>(Generic))); @@ -143,8 +144,8 @@ createUnaryFunction(TestContext &Context, const rcc::TargetDescription &Target, auto Source = (*Function)->registerInfo().createVirtualRegister(SourceType); if (!Destination || !Source) return nullptr; - if (!constrainRegister(**Function, *Destination, DestinationType) || - !constrainRegister(**Function, *Source, SourceType)) + if (!constrainRegister(**Function, *Destination, DestinationType, FloatingDestination) || + !constrainRegister(**Function, *Source, SourceType, FloatingSource)) return nullptr; rcc::MachineIRBuilder Builder(**Function, Target); if (!Builder.setInsertPoint(**Block)) @@ -161,7 +162,7 @@ createUnaryFunction(TestContext &Context, const rcc::TargetDescription &Target, [[nodiscard]] std::unique_ptr<rcc::MachineFunction> createCompareFunction(TestContext &Context, const rcc::TargetDescription &Target, - rcc::GenericOpcode Generic, rcc::LLT ValueType, bool Floating, + rcc::GenericOpcode Generic, rcc::LowLevelType ValueType, bool Floating, rcc::IntegerPredicate IntegerCondition, rcc::FloatingPredicate FloatingCondition) { auto Function = rcc::MachineFunction::create( @@ -173,15 +174,15 @@ createCompareFunction(TestContext &Context, const rcc::TargetDescription &Target auto Block = (*Function)->createBasicBlock(); if (!Block || !(*Function)->appendBlock(**Block)) return nullptr; - auto ResultType = rcc::LLT::makeInteger(1); + auto ResultType = rcc::LowLevelType::makeCategoryNeutralScalar(1); if (!ResultType) return nullptr; auto Result = (*Function)->registerInfo().createVirtualRegister(*ResultType); auto Left = (*Function)->registerInfo().createVirtualRegister(ValueType); auto Right = (*Function)->registerInfo().createVirtualRegister(ValueType); if (!Result || !Left || !Right || !constrainRegister(**Function, *Result, *ResultType) || - !constrainRegister(**Function, *Left, ValueType) || - !constrainRegister(**Function, *Right, ValueType)) + !constrainRegister(**Function, *Left, ValueType, Floating) || + !constrainRegister(**Function, *Right, ValueType, Floating)) return nullptr; rcc::MachineIRBuilder Builder(**Function, Target); if (!Builder.setInsertPoint(**Block)) @@ -202,7 +203,7 @@ createCompareFunction(TestContext &Context, const rcc::TargetDescription &Target [[nodiscard]] std::unique_ptr<rcc::MachineFunction> createFloatBinaryFunction(TestContext &Context, const rcc::TargetDescription &Target, - rcc::GenericOpcode Generic, rcc::LLT Type) { + rcc::GenericOpcode Generic, rcc::LowLevelType Type) { auto Function = rcc::MachineFunction::create( "riscv_float_binary", rcc::MachineFunctionStableID::fromValue(700 + static_cast<std::uint32_t>(Generic))); @@ -215,8 +216,9 @@ createFloatBinaryFunction(TestContext &Context, const rcc::TargetDescription &Ta auto Left = (*Function)->registerInfo().createVirtualRegister(Type); auto Right = (*Function)->registerInfo().createVirtualRegister(Type); auto Result = (*Function)->registerInfo().createVirtualRegister(Type); - if (!Left || !Right || !Result || !constrainRegister(**Function, *Left, Type) || - !constrainRegister(**Function, *Right, Type) || !constrainRegister(**Function, *Result, Type)) + if (!Left || !Right || !Result || !constrainRegister(**Function, *Left, Type, true) || + !constrainRegister(**Function, *Right, Type, true) || + !constrainRegister(**Function, *Result, Type, true)) return nullptr; rcc::MachineIRBuilder Builder(**Function, Target); if (!Builder.setInsertPoint(**Block)) @@ -230,7 +232,8 @@ createFloatBinaryFunction(TestContext &Context, const rcc::TargetDescription &Ta [[nodiscard]] std::unique_ptr<rcc::MachineFunction> createRegisterOnlyFunction( TestContext &Context, const rcc::TargetDescription &Target, rcc::GenericOpcode Generic, - std::initializer_list<rcc::LLT> DefinitionTypes, std::initializer_list<rcc::LLT> UseTypes) { + std::initializer_list<rcc::LowLevelType> DefinitionTypes, + std::initializer_list<rcc::LowLevelType> UseTypes, bool FloatingValues = false) { auto Function = rcc::MachineFunction::create( "riscv_register_only", rcc::MachineFunctionStableID::fromValue(1000 + static_cast<std::uint32_t>(Generic))); @@ -246,17 +249,17 @@ createFloatBinaryFunction(TestContext &Context, const rcc::TargetDescription &Ta auto Pending = Builder.buildInstr(rcc::opcode(Generic)); if (!Pending) return nullptr; - for (rcc::LLT Type : DefinitionTypes) { + for (rcc::LowLevelType Type : DefinitionTypes) { auto Reg = (*Function)->registerInfo().createVirtualRegister(Type); if (!Reg || !Pending->addDef(*Reg)) return nullptr; } - for (rcc::LLT Type : UseTypes) { + for (rcc::LowLevelType Type : UseTypes) { auto Reg = (*Function)->registerInfo().createVirtualRegister(Type); if (!Reg || !Pending->addUse(*Reg)) return nullptr; } - if (!Pending->build() || !constrainVirtualRegisters(**Function)) + if (!Pending->build() || !constrainVirtualRegisters(**Function, FloatingValues)) return nullptr; return std::move(*Function); } @@ -304,8 +307,8 @@ void testClassification(TestContext &Context) { Context.expect(FloatBlock.has_value(), "floating constant block creation must succeed"); if (!FloatBlock || !(*FloatFunction)->appendBlock(**FloatBlock)) return; - auto F32 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEESingle); - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); + auto F32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); Context.expect(F32.has_value() && F64.has_value(), "RV64GC floating constant types must be constructible"); if (!F32 || !F64) @@ -442,8 +445,8 @@ void testNarrowIntegerSelection(TestContext &Context) { "narrow integer selection must satisfy target descriptors"); } - auto I7 = rcc::LLT::makeInteger(7); - auto I24 = rcc::LLT::makeInteger(24); + auto I7 = rcc::LowLevelType::makeCategoryNeutralScalar(7); + auto I24 = rcc::LowLevelType::makeCategoryNeutralScalar(24); if (!I7 || !I24) return; auto Compare = createCompareFunction(Context, *Target, rcc::GenericOpcode::G_ICMP, *I7, false, @@ -494,11 +497,11 @@ void testScalarSelection(TestContext &Context) { if (!Target) return; - auto I32 = rcc::LLT::makeInteger(32); - auto I64 = rcc::LLT::makeInteger(64); - auto F32 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEESingle); - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); - auto I1 = rcc::LLT::makeInteger(1); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto F32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); Context.expect(I32 && I64 && F32 && F64 && I1, "scalar test types must be constructible"); if (!I32 || !I64 || !F32 || !F64 || !I1) return; @@ -546,11 +549,14 @@ void testScalarSelection(TestContext &Context) { } } - auto FPExt = createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_FPEXT, *F64, *F32); - auto FPTrunc = createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_FPTRUNC, *F32, *F64); - auto FPToSI = createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_FPTOSI, *I64, *F32); - auto SIToFP = createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_SITOFP, *F64, *I32); - auto Bitcast = createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_BITCAST, *I32, *F32); + auto FPExt = + createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_FPEXT, *F64, *F32, true, true); + auto FPTrunc = + createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_FPTRUNC, *F32, *F64, true, true); + auto FPToSI = + createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_FPTOSI, *I64, *F32, false, true); + auto SIToFP = + createUnaryFunction(Context, *Target, rcc::GenericOpcode::G_SITOFP, *F64, *I32, true, false); if (FPExt) { auto *Instruction = FPExt->firstBlock()->firstInstruction(); Context.expect((*GISel.Selector).select(*Instruction, *FPExt, *Target).has_value(), @@ -583,14 +589,6 @@ void testScalarSelection(TestContext &Context) { rcc::riscv::InstructionOpcode::FCVT_D_W)), "sitofp must select FCVT.D.W"); } - if (Bitcast) { - auto *Instruction = Bitcast->firstBlock()->firstInstruction(); - Context.expect((*GISel.Selector).select(*Instruction, *Bitcast, *Target).has_value(), - "float-to-integer bitcast must select"); - Context.expect(Instruction->opcode() == rcc::Opcode::fromValue(static_cast<std::uint32_t>( - rcc::riscv::InstructionOpcode::FMV_X_W)), - "float-to-integer bitcast must select FMV.X.W"); - } } void testComparisonsAndControl(TestContext &Context) { @@ -598,9 +596,9 @@ void testComparisonsAndControl(TestContext &Context) { Context.expect(Target.has_value(), "RV64GC target must be available for comparison selection"); if (!Target) return; - auto I64 = rcc::LLT::makeInteger(64); - auto F32 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEESingle); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto F32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); if (!I64 || !F32 || !Pointer) return; @@ -739,10 +737,10 @@ void testCompositeScalarSelection(TestContext &Context) { Context.expect(Target.has_value(), "RV64GC target must be available for composite selection"); if (!Target) return; - auto I1 = rcc::LLT::makeInteger(1); - auto I32 = rcc::LLT::makeInteger(32); - auto I64 = rcc::LLT::makeInteger(64); - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!I1 || !I32 || !I64 || !F64) return; @@ -757,9 +755,9 @@ void testCompositeScalarSelection(TestContext &Context) { auto IntegerSelect = createRegisterOnlyFunction(Context, *Target, rcc::GenericOpcode::G_SELECT, {*I64}, {*I1, *I64, *I64}); auto FloatSelect = createRegisterOnlyFunction(Context, *Target, rcc::GenericOpcode::G_SELECT, - {*F64}, {*I1, *F64, *F64}); + {*F64}, {*I1, *F64, *F64}, true); auto CopySign = createRegisterOnlyFunction(Context, *Target, rcc::GenericOpcode::G_FCOPYSIGN, - {*F64}, {*F64, *F64}); + {*F64}, {*F64, *F64}, true); const std::array Functions{DivRem.get(), MultiplyHigh.get(), Minimum.get(), Absolute.get(), IntegerSelect.get(), FloatSelect.get(), CopySign.get()}; for (rcc::MachineFunction *Function : Functions) { @@ -805,16 +803,16 @@ void testOverflowSelection(TestContext &Context) { auto Target = rcc::riscv::createTargetDescription(); if (!Target) return; - auto I1 = rcc::LLT::makeInteger(1); - auto I32 = rcc::LLT::makeInteger(32); - auto I64 = rcc::LLT::makeInteger(64); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!I1 || !I32 || !I64) return; const std::array Opcodes{rcc::GenericOpcode::G_UADDO, rcc::GenericOpcode::G_USUBO, rcc::GenericOpcode::G_SADDO, rcc::GenericOpcode::G_SSUBO, rcc::GenericOpcode::G_UMULO, rcc::GenericOpcode::G_SMULO}; for (rcc::GenericOpcode Generic : Opcodes) { - const rcc::LLT Type = Generic == rcc::GenericOpcode::G_UMULO ? *I32 : *I64; + const rcc::LowLevelType Type = Generic == rcc::GenericOpcode::G_UMULO ? *I32 : *I64; auto Function = createRegisterOnlyFunction(Context, *Target, Generic, {Type, *I1}, {Type, Type}); Context.expect(Function != nullptr, "overflow fixture must be complete"); @@ -851,10 +849,10 @@ void testAtomicCompareExchangeLegalization(TestContext &Context) { if (!Target || !Function) return; auto Block = (*Function)->createBasicBlock(); - auto I1 = rcc::LLT::makeAnyScalar(1); - auto I8 = rcc::LLT::makeAnyScalar(8); - auto I64 = rcc::LLT::makeAnyScalar(64); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); + auto I8 = rcc::LowLevelType::makeCategoryNeutralScalar(8); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); auto Size = rcc::MemorySize::fixed(1); auto Align = rcc::Alignment::create(1); if (!Block || !(*Function)->appendBlock(**Block) || !I1 || !I8 || !I64 || !Pointer || !Size || @@ -1003,8 +1001,8 @@ void testConstantExtensionPreservesLiveSource(TestContext &Context) { auto Target = rcc::riscv::createTargetDescription(); auto Function = rcc::MachineFunction::create("riscv_live_constant_extension", rcc::MachineFunctionStableID::fromValue(1300)); - auto I32 = rcc::LLT::makeAnyScalar(32); - auto I64 = rcc::LLT::makeAnyScalar(64); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Target || !Function || !I32 || !I64) return; auto Block = (*Function)->createBasicBlock(); @@ -1048,8 +1046,8 @@ void testConstantExtensionPreservesLiveSource(TestContext &Context) { void testIntegerCompareReusesConstantExtension(TestContext &Context) { auto Target = rcc::riscv::createTargetDescription(); - auto I32 = rcc::LLT::makeAnyScalar(32); - auto I64 = rcc::LLT::makeAnyScalar(64); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Target || !I32 || !I64) return; auto Function = @@ -1109,9 +1107,9 @@ void testNarrowAnyExtBinaryArtifacts(TestContext &Context) { auto Target = rcc::riscv::createTargetDescription(); auto Function = rcc::MachineFunction::create("riscv_narrow_binary_artifacts", rcc::MachineFunctionStableID::fromValue(1301)); - auto I1 = rcc::LLT::makeAnyScalar(1); - auto I32 = rcc::LLT::makeAnyScalar(32); - auto I64 = rcc::LLT::makeAnyScalar(64); + auto I1 = rcc::LowLevelType::makeCategoryNeutralScalar(1); + auto I32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Target || !Function || !I1 || !I32 || !I64) return; auto Block = (*Function)->createBasicBlock(); @@ -1240,8 +1238,8 @@ void testAtomicSelection(TestContext &Context) { auto Target = rcc::riscv::createTargetDescription(); if (!Target) return; - auto I64 = rcc::LLT::makeInteger(64); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); auto Size = rcc::MemorySize::fixed(8); auto Align = rcc::Alignment::create(8); if (!I64 || !Pointer || !Size || !Align) @@ -1397,8 +1395,8 @@ void testUnsupportedTypes(TestContext &Context) { (*GISel.Selector).canSelect(*WideInteger.Instruction, *WideInteger.Function, *Target); Context.expect(!Selection && Selection.error().code() == rcc::ErrorCode::Unsupported, "i128 arithmetic must produce an Unsupported diagnostic"); - Context.expect(!Selection && Selection.error().message().find("i128") != std::string::npos, - "unsupported type diagnostics must name the rejected LLT"); + Context.expect(!Selection && Selection.error().message().find("s128") != std::string::npos, + "unsupported type diagnostics must name the rejected LowLevelType"); } auto Function = rcc::MachineFunction::create("unsupported_type", rcc::MachineFunctionStableID::fromValue(100)); @@ -1407,7 +1405,7 @@ void testUnsupportedTypes(TestContext &Context) { auto Block = (*Function)->createBasicBlock(); if (!Block || !(*Function)->appendBlock(**Block)) return; - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!F64) return; auto Result = (*Function)->registerInfo().createVirtualRegister(*F64); @@ -1447,7 +1445,7 @@ void testVACopyLegalization(TestContext &Context) { if (!Function) return; auto Block = (*Function)->createBasicBlock(); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); if (!Block || !Pointer || !(*Function)->appendBlock(**Block)) return; auto Destination = (*Function)->registerInfo().createVirtualRegister(*Pointer); @@ -1522,8 +1520,8 @@ void testVAArgLegalization(TestContext &Context) { if (!Function) return; auto Block = (*Function)->createBasicBlock(); - auto Pointer = rcc::LLT::makePointer(0, 64); - auto I64 = rcc::LLT::makeInteger(64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Block || !Pointer || !I64 || !(*Function)->appendBlock(**Block)) return; auto Destination = (*Function)->registerInfo().createVirtualRegister(*I64); @@ -1611,8 +1609,8 @@ void testFrameIndexLegalization(TestContext &Context) { if (!Function) return; auto Block = (*Function)->createBasicBlock(); - auto Pointer = rcc::LLT::makePointer(0, 64); - auto OtherAddressSpace = rcc::LLT::makePointer(1, 64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); + auto OtherAddressSpace = rcc::LowLevelType::makePointer(1, 64); rcc::StackObjectDesc StackSlot; StackSlot.Size = 8; StackSlot.Align = *rcc::Alignment::create(8); @@ -1653,9 +1651,9 @@ void testPointerArithmeticLegalization(TestContext &Context) { Context.expect(Target.has_value(), "RV64GC target must be available for pointer legalization"); if (!Target) return; - auto Pointer = rcc::LLT::makePointer(0, 64); - auto S64 = rcc::LLT::makeAnyScalar(64); - auto S32 = rcc::LLT::makeAnyScalar(32); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); + auto S64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto S32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); if (!Pointer || !S64 || !S32) return; auto Legal = createRegisterOnlyFunction(Context, *Target, rcc::GenericOpcode::G_PTR_ADD, @@ -1686,8 +1684,8 @@ void testMemoryOffsetSelection(TestContext &Context) { auto Block = (*Function)->createBasicBlock(); if (!Block || !(*Function)->appendBlock(**Block)) return; - auto I64 = rcc::LLT::makeInteger(64); - auto Pointer = rcc::LLT::makePointer(0, 64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto Pointer = rcc::LowLevelType::makePointer(0, 64); if (!I64 || !Pointer) return; auto Result = (*Function)->registerInfo().createVirtualRegister(*I64); diff --git a/backend/unittests/Target/RISCVLateCodeGenTest.cpp b/backend/unittests/Target/RISCVLateCodeGenTest.cpp index 89da994..0deebc6 100644 --- a/backend/unittests/Target/RISCVLateCodeGenTest.cpp +++ b/backend/unittests/Target/RISCVLateCodeGenTest.cpp @@ -727,7 +727,7 @@ void testRISCVMemoryFoldingBoundary(TestContext &Context, const rcc::TargetDescr if (!Function) return; rcc::MachineBasicBlock *Block = appendBlock(Context, *Function); - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto Align = rcc::Alignment::create(8); if (Block == nullptr || !I64 || !Align) return; @@ -995,8 +995,8 @@ void testPseudoPreparation(TestContext &Context, const rcc::TargetDescription &T if (!Function) return; rcc::MachineBasicBlock *Block = appendBlock(Context, *Function); - auto I64 = rcc::LLT::makeInteger(64); - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (Block == nullptr || !I64 || !F64) return; auto Source = Function->registerInfo().createVirtualRegister(*I64); diff --git a/backend/unittests/Target/RISCVRegisterAllocationTest.cpp b/backend/unittests/Target/RISCVRegisterAllocationTest.cpp index 6daf58a..29bc756 100644 --- a/backend/unittests/Target/RISCVRegisterAllocationTest.cpp +++ b/backend/unittests/Target/RISCVRegisterAllocationTest.cpp @@ -84,7 +84,8 @@ struct FunctionFixture final { return FunctionFixture{std::move(*Function), *Block}; } -[[nodiscard]] rcc::Expected<rcc::Register> createVReg(rcc::MachineFunction &Function, rcc::LLT Type, +[[nodiscard]] rcc::Expected<rcc::Register> createVReg(rcc::MachineFunction &Function, + rcc::LowLevelType Type, rcc::riscv::RegisterBank Bank, rcc::riscv::RegisterClass Class) { auto Reg = Function.registerInfo().createVirtualRegister(Type); @@ -304,7 +305,7 @@ void testTargetHooks(TestContext &Context, const rcc::TargetDescription &Target) void testRematerialization(TestContext &Context, const rcc::TargetDescription &Target) { auto Fixture = createFunction("riscv-rematerialization", 2); - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Fixture || !I64) return; auto Original = createVReg(*Fixture->Function, *I64, rcc::riscv::RegisterBank::GPR, @@ -335,7 +336,7 @@ void testRematerialization(TestContext &Context, const rcc::TargetDescription &T [[nodiscard]] rcc::Expected<FunctionFixture> createSimpleAllocationFunction(const rcc::TargetDescription &Target, std::uint64_t ID) { auto Fixture = createFunction("riscv-ra-" + std::to_string(ID), ID); - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Fixture) return std::unexpected(Fixture.error()); if (!I64) @@ -448,7 +449,7 @@ void testFunctionReservedRegisters(TestContext &Context, const rcc::TargetDescri [[nodiscard]] rcc::Expected<FunctionFixture> createPressureFunction(const rcc::TargetDescription &Target, std::uint64_t ID) { auto Fixture = createFunction("riscv-pressure-" + std::to_string(ID), ID); - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); if (!Fixture) return std::unexpected(Fixture.error()); if (!I64) diff --git a/backend/unittests/Target/RISCVSSAExitTest.cpp b/backend/unittests/Target/RISCVSSAExitTest.cpp index 54a5911..1912666 100644 --- a/backend/unittests/Target/RISCVSSAExitTest.cpp +++ b/backend/unittests/Target/RISCVSSAExitTest.cpp @@ -54,7 +54,8 @@ private: return rcc::RegisterClassID::fromValue(static_cast<std::uint32_t>(Class)); } -[[nodiscard]] rcc::Expected<rcc::Register> createVReg(rcc::MachineFunction &Function, rcc::LLT Type, +[[nodiscard]] rcc::Expected<rcc::Register> createVReg(rcc::MachineFunction &Function, + rcc::LowLevelType Type, rcc::riscv::RegisterBank Bank, rcc::riscv::RegisterClass Class) { auto Reg = Function.registerInfo().createVirtualRegister(Type); @@ -219,9 +220,9 @@ void testBehaviorAndCopyLegality(TestContext &Context, const rcc::TargetDescript Context.expect(Rewritten && *Rewritten && blockOperand(*Jump, 1)->Block == *Third, "RV64GC branch target rewriting must update direct JAL operands"); - auto I64 = rcc::LLT::makeInteger(64); - auto F64 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEEDouble); - auto F32 = rcc::LLT::makeFloat(rcc::FloatSemantics::IEEESingle); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto F64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); + auto F32 = rcc::LowLevelType::makeCategoryNeutralScalar(32); if (!I64 || !F64 || !F32) return; auto GPR = @@ -318,7 +319,7 @@ void testRV64GCCriticalEdge(TestContext &Context, const rcc::TargetDescription & auto Merge = appendBlock(**Function); if (!From || !Side || !Other || !Merge) return; - auto I64 = rcc::LLT::makeInteger(64); + auto I64 = rcc::LowLevelType::makeCategoryNeutralScalar(64); auto X0 = rcc::riscv::physicalRegister(rcc::riscv::PhysicalRegisterID::X0); if (!I64 || !X0) return; diff --git a/backend/utils/TableGen/Common/CodeGenInstruction.cpp b/backend/utils/TableGen/Common/CodeGenInstruction.cpp index d06fbfc..cabe8d4 100644 --- a/backend/utils/TableGen/Common/CodeGenInstruction.cpp +++ b/backend/utils/TableGen/Common/CodeGenInstruction.cpp @@ -76,7 +76,7 @@ memoryRoleEnumerator(std::string_view Value) noexcept { [[nodiscard]] std::optional<std::string_view> instructionFlagEnumerator(std::string_view Value) noexcept { - static constexpr std::array<std::pair<std::string_view, std::string_view>, 23> Flags = {{ + static constexpr std::array<std::pair<std::string_view, std::string_view>, 24> Flags = {{ {"terminator", "Terminator"}, {"branch", "Branch"}, {"indirect_branch", "IndirectBranch"}, @@ -96,6 +96,7 @@ instructionFlagEnumerator(std::string_view Value) noexcept { {"not_duplicable", "NotDuplicable"}, {"convergent", "Convergent"}, {"unmodeled_side_effects", "UnmodeledSideEffects"}, + {"may_raise_fp_exception", "MayRaiseFPException"}, {"phi", "Phi"}, {"fake_use", "FakeUse"}, {"generic", "Generic"}, |
