From aa69e15c6909c3b162b15f5326f0a72ba9bb7163 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Thu, 13 Aug 2026 23:55:38 +0800 Subject: [CodeGen] Unify scalar low-level types --- .../lib/Target/RISCV/GISel/RISCVCallLowering.cpp | 72 ++-- .../RISCV/GISel/RISCVInstructionSelector.cpp | 261 ++++++------ .../lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp | 452 ++++++++++----------- .../Target/RISCV/GISel/RISCVRegisterBankInfo.cpp | 15 +- backend/lib/Target/RISCV/RISCV.rccdesc | 88 ++-- backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp | 5 +- 6 files changed, 457 insertions(+), 436 deletions(-) (limited to 'backend/lib/Target') 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(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 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(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 registerAssignment(const ABIValue &Value, - std::size_t ValueIndex, - PhysicalRegister Location, LLT LocationType, - bool IsVariadic, bool IsBitcast) { +[[nodiscard]] Expected +registerAssignment(const ABIValue &Value, std::size_t ValueIndex, PhysicalRegister Location, + LowLevelType LocationType, bool IsVariadic, bool IsBitcast) { auto Align = alignment(std::min(Value.OriginalAlignment.bytes(), ABIStackAlignmentBytes)); if (!Align) @@ -254,8 +257,8 @@ struct AssignmentState final { } [[nodiscard]] Expected 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 assignArguments(std::span 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 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 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 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 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 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 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 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 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 registerType(const MachineFunction &Function, - const MachineOperand &Operand) { +[[nodiscard]] std::optional registerType(const MachineFunction &Function, + const MachineOperand &Operand) { const Register *Reg = Operand.getIf(); if (Reg == nullptr || !Reg->isVirtual()) return std::nullopt; @@ -42,43 +42,59 @@ namespace { return Info->get().Type; } -[[nodiscard]] std::optional resultType(const MachineFunction &Function, - const MachineInstr &Instruction) { +[[nodiscard]] std::optional resultType(const MachineFunction &Function, + const MachineInstr &Instruction) { const MachineOperand *Result = Instruction.operandAt(0); return Result == nullptr ? std::nullopt : registerType(Function, *Result); } -[[nodiscard]] std::optional operandType(const MachineFunction &Function, - const MachineInstr &Instruction, std::size_t Index) { +[[nodiscard]] std::optional +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 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(RegisterBank::FPR)); +} + +[[nodiscard]] Expected 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 Type = resultType(Function, Instruction); - const std::optional Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); + const std::optional Type = resultType(Function, Instruction); + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional Right = operandType(Function, Instruction, 2); return Type && Left && Right && isScalarGPRType(*Type) && Type->scalarBitWidth() == 64 && *Left == *Type && *Right == *Type ? Expected{} @@ -158,9 +174,9 @@ public: if (!isGenericOpcode(Instruction.opcode())) return {}; const GenericOpcode Generic = static_cast(Instruction.opcode().value()); - const std::optional Type = resultType(Function, Instruction); + const std::optional 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(); - const std::optional 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(Instruction.opcode().value()); - const std::optional Type = resultType(Function, Instruction); + const std::optional 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 createTemporary(MachineFunction &Function, LLT Type, - const TargetDescription &Target) const { + [[nodiscard]] Expected + createTemporary(MachineFunction &Function, LowLevelType Type, const TargetDescription &Target, + std::optional 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 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 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 selectDivRem(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, bool Signed) const { + std::optional 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 selectMultiplyHigh(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, bool Signed) const { + std::optional 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 selectIntegerMinMax(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, + std::optional 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 selectValue(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type) const { + std::optional 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 selectAbsoluteValue(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type) const { + std::optional Type) const { const MachineOperand *DestinationOperand = Instruction.operandAt(0); const MachineOperand *SourceOperand = Instruction.operandAt(1); const Register *Destination = @@ -1059,12 +1082,13 @@ private: [[nodiscard]] Expected> 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 selectOverflow(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, + std::optional 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 selectExtendedOverflow(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, + std::optional 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 selectAtomicRMW(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, + std::optional 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 Type) const { - const std::optional SourceType = operandType(Function, Instruction, 1); + std::optional Type) const { + const std::optional 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 selectSignExtendInRegister(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type) const { + std::optional 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(); const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf(); const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf(); - const std::optional LeftType = operandType(Function, Instruction, 2); + const std::optional 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(); const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf(); const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf(); - const std::optional FloatType = operandType(Function, Instruction, 2); - const std::optional ResultType = resultType(Function, Instruction); + const std::optional FloatType = operandType(Function, Instruction, 2); + const std::optional 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 selectFloatToInteger(MachineInstr &Instruction, MachineFunction &Function, - std::optional Type, bool Unsigned) const { - const std::optional Source = operandType(Function, Instruction, 1); + std::optional Type, + bool Unsigned) const { + const std::optional 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 selectIntegerToFloat(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type, bool Unsigned) const { - const std::optional Source = operandType(Function, Instruction, 1); + std::optional Type, + bool Unsigned) const { + const std::optional Source = operandType(Function, Instruction, 1); const MachineOperand *SourceOperand = Instruction.operandAt(1); const Register *SourceRegister = SourceOperand == nullptr ? nullptr : SourceOperand->getIf(); @@ -2003,12 +2029,12 @@ private: } [[nodiscard]] Expected selectFloatingMinMax(MachineInstr &Instruction, - std::optional Type, + std::optional 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 selectBitcast(MachineInstr &Instruction, - MachineFunction &Function) const { - const std::optional DestinationType = resultType(Function, Instruction); - const std::optional 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 selectIntegerBinary(MachineInstr &Instruction, - std::optional Type, + std::optional 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 selectNormalizedIntegerBinary(MachineInstr &Instruction, MachineFunction &Function, - const TargetDescription &Target, std::optional Type, + const TargetDescription &Target, std::optional 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 selectLoad(MachineInstr &Instruction, - std::optional Type) const { + [[nodiscard]] Expected selectLoad(MachineInstr &Instruction, MachineFunction &Function, + std::optional 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(); + 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 selectExtLoad(MachineInstr &Instruction, std::optional Type, - bool Signed) const { + [[nodiscard]] Expected selectExtLoad(MachineInstr &Instruction, + std::optional 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 selectStore(MachineInstr &Instruction, MachineFunction &Function) const { const MachineOperand *Value = Instruction.operandAt(0); - const std::optional Type = + const std::optional 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(); + 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 selectIntegerConstant(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type) const { + std::optional 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 selectFloatingConstant(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, - std::optional Type) const { - if (!Type || !isRVFloatType(*Type)) + std::optional 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(); - const std::optional 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 selectRoundingBinary(MachineInstr &Instruction, - std::optional Type, + std::optional 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 selectRoundingTernary(MachineInstr &Instruction, - std::optional Type, + std::optional Type, InstructionOpcode Single, InstructionOpcode Double) const { return selectRoundingBinary(Instruction, Type, Single, Double); } [[nodiscard]] Expected selectRoundingUnary(MachineInstr &Instruction, - std::optional Type, + std::optional Type, InstructionOpcode Single, InstructionOpcode Double) const { return selectRoundingBinary(Instruction, Type, Single, Double); } [[nodiscard]] Expected selectSignInjection(MachineInstr &Instruction, - std::optional Type, + std::optional 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 registerType(const MachineFunction &Function, Register Reg) { +[[nodiscard]] std::optional 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 registerType(const MachineFunction &Function, - const MachineOperand &Operand) { +[[nodiscard]] std::optional registerType(const MachineFunction &Function, + const MachineOperand &Operand) { const Register *Reg = Operand.getIf(); return Reg == nullptr ? std::nullopt : registerType(Function, *Reg); } -[[nodiscard]] std::optional resultType(const MachineFunction &Function, - const MachineInstr &Instruction) { +[[nodiscard]] std::optional resultType(const MachineFunction &Function, + const MachineInstr &Instruction) { const MachineOperand *Result = Instruction.operandAt(0); return Result == nullptr ? std::nullopt : registerType(Function, *Result); } -[[nodiscard]] std::optional operandType(const MachineFunction &Function, - const MachineInstr &Instruction, std::size_t Index) { +[[nodiscard]] std::optional +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 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 buildBinaryBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - GenericOpcode Generic, LLT Type, Register Left, - Register Right); + GenericOpcode Generic, LowLevelType Type, + Register Left, Register Right); [[nodiscard]] Expected buildUnaryBefore(MachineIRBuilder &Builder, MachineInstr &Anchor, - GenericOpcode Generic, LLT Type, Register Source); + GenericOpcode Generic, LowLevelType Type, + Register Source); [[nodiscard]] Expected eraseInstruction(MachineInstr &Instruction); @@ -462,7 +462,7 @@ narrowAnyExtBinaryPlan(const MachineInstr &Extension, const MachineFunction &Fun const Register *Narrow = NarrowOperand == nullptr ? nullptr : NarrowOperand->getIf(); const MachineOperand *WideOperand = Truncation->operandAt(1); const Register *Wide = WideOperand == nullptr ? nullptr : WideOperand->getIf(); - const std::optional WideType = + const std::optional 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 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 lowerAtomicCompareExchange(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional OriginalType = resultType(Function, Instruction); + const std::optional 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(); const Register *NewValue = NewValueOperand == nullptr ? nullptr : NewValueOperand->getIf(); - const std::optional ValueType = resultType(Function, Instruction); + const std::optional 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 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(); - const std::optional ExtendedType = + const std::optional 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(); - const std::optional ExistingWideType = + const std::optional 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::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 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 Candidates, } [[nodiscard]] Expected 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 Candidates, } [[nodiscard]] Expected 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 Candidates, [[nodiscard]] Expected widenNarrowMultiply(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional Type = resultType(Function, Instruction); + const std::optional 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 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 Candidates, const TargetDescription &Target, CallingConvention Convention, const TargetCallLowering &CallLowering) { - const std::optional Type = resultType(Function, Instruction); + const std::optional 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 Candidates, return ABIValue{ .Value = Reg, .Type = Type, + .Category = ABIValueCategory::Integer, .OriginalValue = Number, .FragmentIndex = 0, .FragmentCount = 1, @@ -1488,7 +1490,7 @@ void eraseDeadArtifacts(std::span 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 Candidates, [[nodiscard]] Expected lowerMergeValues(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional DestinationType = resultType(Function, Instruction); + const std::optional 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 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 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 Candidates, Terms.push_back(*WideSource); continue; } - const std::optional SourceType = registerType(Function, *Operand); + const std::optional 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 Candidates, return makeUnexpected(ErrorCode::VerificationError, "RISC-V unmerge has invalid register operands"); const std::size_t OutputCount = Instruction.operandCount() - 1U; - const std::optional OutputType = operandType(Function, Instruction, 0); - const std::optional SourceType = operandType(Function, Instruction, OutputCount); + const std::optional OutputType = operandType(Function, Instruction, 0); + const std::optional 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 Candidates, const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf(); 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 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(); - const std::optional PartType = + const std::optional 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(); - const std::optional Type = + const std::optional 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 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 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 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 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 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(Definition->parent()); const Register Source = *Truncation->operandAt(1)->getIf(); - 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 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 lowerNarrowPhi(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target) { - const std::optional OriginalType = resultType(Function, Instruction); + const std::optional OriginalType = resultType(Function, Instruction); const MachineOperand *DestinationOperand = Instruction.operandAt(0); const Register *Destination = DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf(); 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 Result = resultType(Function, *Trunc); + const std::optional 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(LLT Type) noexcept { +[[nodiscard]] std::optional rv64ScalarLayout(LowLevelType Type) noexcept { if (Type.isPointer()) { return Type.addressSpace() == 0 && Type.scalarBitWidth() == 64 ? std::optional{{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 -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(); const Register *ListPointer = ListOperand == nullptr ? nullptr : ListOperand->getIf(); - const std::optional DestinationType = resultType(Function, Instruction); - const std::optional PointerType = operandType(Function, Instruction, 1); + const std::optional DestinationType = resultType(Function, Instruction); + const std::optional PointerType = operandType(Function, Instruction, 1); const auto AlignmentValue = AlignmentOperand == nullptr ? Expected(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(const MachineInstr &Instruction, @@ -3006,8 +3010,8 @@ struct VACopyPlan final { const Register *Destination = DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf(); const Register *Source = SourceOperand == nullptr ? nullptr : SourceOperand->getIf(); - const std::optional DestinationType = operandType(Function, Instruction, 1); - const std::optional SourceType = operandType(Function, Instruction, 2); + const std::optional DestinationType = operandType(Function, Instruction, 1); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In return LegalizationAction::Legal; const GenericOpcode Generic = static_cast(Instruction.opcode().value()); - const std::optional Type = resultType(Function, Instruction); + const std::optional Type = resultType(Function, Instruction); switch (Generic) { case GenericOpcode::G_INTRINSIC_W_SIDE_EFFECTS: return vacopyPlan(Instruction, Function) ? LegalizationAction::Custom @@ -3110,7 +3114,7 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_BR: return LegalizationAction::Legal; case GenericOpcode::G_BRCOND: { - const std::optional Condition = operandType(Function, Instruction, 0); + const std::optional Condition = operandType(Function, Instruction, 0); if (!Condition || !isScalarGPRType(*Condition)) return LegalizationAction::Unsupported; return canLowerNarrowBranchCondition(Instruction, Function) ? LegalizationAction::Custom @@ -3120,28 +3124,28 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In if (!Type) return LegalizationAction::Unsupported; for (std::size_t Index = 1; Index < Instruction.operandCount(); Index += 2) { - const std::optional Incoming = operandType(Function, Instruction, Index); + const std::optional 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 ValueType = registerType(Function, *Instruction.operandAt(0)); + if (const std::optional ValueType = + registerType(Function, *Instruction.operandAt(0)); ValueType) { - const std::optional AddressType = operandType(Function, Instruction, 1); + const std::optional AddressType = operandType(Function, Instruction, 1); if (!AddressType || !AddressType->isPointer() || AddressType->addressSpace() != 0 || AddressType->scalarBitWidth() != 64) { return LegalizationAction::Unsupported; @@ -3153,8 +3157,7 @@ Expected 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 RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SEXTLOAD: case GenericOpcode::G_ZEXTLOAD: { const auto Bytes = memoryAccessBytes(Instruction); - const std::optional AddressType = operandType(Function, Instruction, 1); + const std::optional AddressType = operandType(Function, Instruction, 1); return Type && Bytes && AddressType && isSupportedIntegerType(*Type) && AddressType->isPointer() && AddressType->addressSpace() == 0 && AddressType->scalarBitWidth() == 64 && @@ -3175,19 +3178,19 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_FPEXTLOAD: { const auto Bytes = memoryAccessBytes(Instruction); - const std::optional 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 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 ValueType = operandType(Function, Instruction, 0); - const std::optional AddressType = operandType(Function, Instruction, 1); + const std::optional ValueType = operandType(Function, Instruction, 0); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_LOAD: if (Type) { - const std::optional AddressType = operandType(Function, Instruction, 1); + const std::optional AddressType = operandType(Function, Instruction, 1); if (!AddressType || !AddressType->isPointer() || AddressType->addressSpace() != 0 || AddressType->scalarBitWidth() != 64) { return LegalizationAction::Unsupported; @@ -3208,8 +3211,8 @@ Expected 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 RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_FSUB: case GenericOpcode::G_FMUL: case GenericOpcode::G_FDIV: { - const std::optional Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); - return Type && Left && Right && isRVFloatType(*Type) && *Left == *Type && *Right == *Type + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional 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 First = operandType(Function, Instruction, 1); - const std::optional Second = operandType(Function, Instruction, 2); - const std::optional Third = operandType(Function, Instruction, 3); - return Type && First && Second && Third && isRVFloatType(*Type) && *First == *Type && - *Second == *Type && *Third == *Type + const std::optional First = operandType(Function, Instruction, 1); + const std::optional Second = operandType(Function, Instruction, 2); + const std::optional 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 Source = operandType(Function, Instruction, 1); - return Type && Source && isRVFloatType(*Type) && *Source == *Type + const std::optional Source = operandType(Function, Instruction, 1); + return Type && Source && isSupportedFloatingScalar(*Type) && *Source == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_FCOPYSIGN: { - const std::optional Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); - return Type && Left && Right && isRVFloatType(*Type) && *Left == *Type && *Right == *Type + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional Right = operandType(Function, Instruction, 2); + return Type && Left && Right && isSupportedFloatingScalar(*Type) && *Left == *Type && + *Right == *Type ? LegalizationAction::Legal : LegalizationAction::Unsupported; } @@ -3252,16 +3257,15 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In const MachineOperand *Immediate = Instruction.operandAt(1); const auto *Floating = Immediate == nullptr ? nullptr : Immediate->getIf(); - const std::optional 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 Source = operandType(Function, Instruction, 1); + const std::optional Source = operandType(Function, Instruction, 1); return Type && Source && *Type == *Source && isScalarGPRType(*Type) && Instruction.operandCount() == 3 ? LegalizationAction::Legal @@ -3269,38 +3273,35 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_FREEZE: case GenericOpcode::G_CONSTANT_FOLD_BARRIER: { - const std::optional Source = operandType(Function, Instruction, 1); - return Type && Source && *Type == *Source && - (isSupportedIntegerType(*Type) || isRVFloatType(*Type)) + const std::optional Source = operandType(Function, Instruction, 1); + return Type && Source && *Type == *Source && isSupportedIntegerType(*Type) ? LegalizationAction::Legal : LegalizationAction::Unsupported; } case GenericOpcode::G_PTRTOINT: { - const std::optional Source = operandType(Function, Instruction, 1); - return Type && Source && Type->isInteger() && Type->scalarBitWidth() == 64 && + const std::optional 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 Source = operandType(Function, Instruction, 1); + const std::optional 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 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 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 Source = operandType(Function, Instruction, 1); + const std::optional Source = operandType(Function, Instruction, 1); if (!Type || !Source) return LegalizationAction::Unsupported; if (!isScalarIntegerExtension(*Type, *Source)) { @@ -3309,8 +3310,7 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf(); 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 RISCVLegalizerInfo::classify(const MachineInstr &In return LegalizationAction::Legal; } case GenericOpcode::G_TRUNC: { - const std::optional 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 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 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 SmallType = operandType(Function, Instruction, SmallTypeIndex); - const std::optional BigType = operandType(Function, Instruction, BigTypeIndex); + const std::optional SmallType = + operandType(Function, Instruction, SmallTypeIndex); + const std::optional 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 Source = operandType(Function, Instruction, 1); + const std::optional Source = operandType(Function, Instruction, 1); const MachineOperand *WidthOperand = Instruction.operandAt(2); const auto Width = WidthOperand == nullptr @@ -3379,8 +3379,8 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In const MachineOperand *Predicate = Instruction.operandAt(1); const auto *IntegerPredicate = Predicate == nullptr ? nullptr : Predicate->getIf(); - const std::optional Left = operandType(Function, Instruction, 2); - const std::optional Right = operandType(Function, Instruction, 3); + const std::optional Left = operandType(Function, Instruction, 2); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In const MachineOperand *Predicate = Instruction.operandAt(1); const auto *FloatingPredicate = Predicate == nullptr ? nullptr : Predicate->getIf(); - const std::optional Left = operandType(Function, Instruction, 2); - const std::optional Right = operandType(Function, Instruction, 3); + const std::optional Left = operandType(Function, Instruction, 2); + const std::optional 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 Source = operandType(Function, Instruction, 1); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_FPTOSI: case GenericOpcode::G_FPTOUI: { - const std::optional Source = operandType(Function, Instruction, 1); - return Type && Source && isSupportedIntegerType(*Type) && isRVFloatType(*Source) + const std::optional 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 Source = operandType(Function, Instruction, 1); - return Type && Source && isRVFloatType(*Type) && isSupportedIntegerType(*Source) + const std::optional 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 Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); - return Type && Left && Right && isRVFloatType(*Type) && *Left == *Type && *Right == *Type + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional 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 Condition = operandType(Function, Instruction, 1); - const std::optional TrueValue = operandType(Function, Instruction, 2); - const std::optional FalseValue = operandType(Function, Instruction, 3); + const std::optional Condition = operandType(Function, Instruction, 1); + const std::optional TrueValue = operandType(Function, Instruction, 2); + const std::optional 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 Pointer = operandType(Function, Instruction, 1); - const std::optional Mask = operandType(Function, Instruction, 2); + const std::optional Pointer = operandType(Function, Instruction, 1); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In : LegalizationAction::Unsupported; } case GenericOpcode::G_ABS: { - const std::optional Source = operandType(Function, Instruction, 1); + const std::optional 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 Remainder = operandType(Function, Instruction, 1); - const std::optional Left = operandType(Function, Instruction, 2); - const std::optional Right = operandType(Function, Instruction, 3); + const std::optional Remainder = operandType(Function, Instruction, 1); + const std::optional Left = operandType(Function, Instruction, 2); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In } case GenericOpcode::G_SMULH: case GenericOpcode::G_UMULH: { - const std::optional Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional Right = operandType(Function, Instruction, 2); return Type && Left && Right && isNativeIntegerScalar(*Type) && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3484,8 +3485,8 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SMAX: case GenericOpcode::G_UMIN: case GenericOpcode::G_UMAX: { - const std::optional Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional Right = operandType(Function, Instruction, 2); return Type && Left && Right && isSupportedIntegerScalar(*Type) && *Left == *Type && *Right == *Type ? LegalizationAction::Legal @@ -3497,9 +3498,9 @@ Expected RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SSUBO: case GenericOpcode::G_UMULO: case GenericOpcode::G_SMULO: { - const std::optional Overflow = operandType(Function, Instruction, 1); - const std::optional Left = operandType(Function, Instruction, 2); - const std::optional Right = operandType(Function, Instruction, 3); + const std::optional Overflow = operandType(Function, Instruction, 1); + const std::optional Left = operandType(Function, Instruction, 2); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_USUBE: case GenericOpcode::G_SADDE: case GenericOpcode::G_SSUBE: { - const std::optional CarryOut = operandType(Function, Instruction, 1); - const std::optional Left = operandType(Function, Instruction, 2); - const std::optional Right = operandType(Function, Instruction, 3); - const std::optional CarryIn = operandType(Function, Instruction, 4); + const std::optional CarryOut = operandType(Function, Instruction, 1); + const std::optional Left = operandType(Function, Instruction, 2); + const std::optional Right = operandType(Function, Instruction, 3); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_ATOMICRMW_MIN: case GenericOpcode::G_ATOMICRMW_UMAX: case GenericOpcode::G_ATOMICRMW_UMIN: { - const std::optional Address = operandType(Function, Instruction, 1); - const std::optional Value = operandType(Function, Instruction, 2); + const std::optional Address = operandType(Function, Instruction, 1); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In : LegalizationAction::Unsupported; } case GenericOpcode::G_ATOMIC_CMPXCHG: { - const std::optional Address = operandType(Function, Instruction, 1); - const std::optional Compare = operandType(Function, Instruction, 2); - const std::optional NewValue = operandType(Function, Instruction, 3); + const std::optional Address = operandType(Function, Instruction, 1); + const std::optional Compare = operandType(Function, Instruction, 2); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In return Type->scalarBitWidth() == 64 ? LegalizationAction::Legal : LegalizationAction::Custom; } case GenericOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: { - const std::optional Success = operandType(Function, Instruction, 1); - const std::optional Address = operandType(Function, Instruction, 2); - const std::optional Compare = operandType(Function, Instruction, 3); - const std::optional NewValue = operandType(Function, Instruction, 4); + const std::optional Success = operandType(Function, Instruction, 1); + const std::optional Address = operandType(Function, Instruction, 2); + const std::optional Compare = operandType(Function, Instruction, 3); + const std::optional 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 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 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 RISCVLegalizerInfo::classify(const MachineInstr &In case GenericOpcode::G_SHL: case GenericOpcode::G_LSHR: case GenericOpcode::G_ASHR: { - const std::optional Left = operandType(Function, Instruction, 1); - const std::optional Right = operandType(Function, Instruction, 2); + const std::optional Left = operandType(Function, Instruction, 1); + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf(); MachineInstr *Extension = Destination == nullptr ? nullptr : singleRegisterUse(Function, *Destination); - const std::optional ExtensionType = + const std::optional 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 RISCVLegalizerInfo::classify(const MachineInstr &In : LegalizationAction::Unsupported; } case GenericOpcode::G_PTR_ADD: { - const std::optional Pointer = operandType(Function, Instruction, 1); - const std::optional Offset = operandType(Function, Instruction, 2); + const std::optional Pointer = operandType(Function, Instruction, 1); + const std::optional 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 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 RISCVLegalizerInfo::lower(MachineInstr &Instruction, MachineFunct if (Action == LegalizationAction::Custom && Instruction.opcode() == opcode(GenericOpcode::G_CONSTANT)) { const MachineOperand *Immediate = Instruction.operandAt(1); - const std::optional Type = resultType(Function, Instruction); - if (Immediate != nullptr && Type && (Type->isInteger() || Type->isAnyScalar()) && + const std::optional 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 registerType(Register Reg, const MachineFunction &Function) { +[[nodiscard]] std::optional 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 Type = DestinationType ? DestinationType : SourceType; + const std::optional 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"); -- cgit v1.2.3