aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 23:55:38 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 23:55:38 +0800
commitaa69e15c6909c3b162b15f5326f0a72ba9bb7163 (patch)
tree6428eb20e41bad1fc8ad2f5c259bc5537f54554d /backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
parentcd30fb546e389d1fb78ce8e579b3dba3a8fdb52a (diff)
downloadrcc-project-aa69e15c6909c3b162b15f5326f0a72ba9bb7163.tar.gz
rcc-project-aa69e15c6909c3b162b15f5326f0a72ba9bb7163.tar.xz
[CodeGen] Unify scalar low-level types
Diffstat (limited to 'backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp')
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp261
1 files changed, 140 insertions, 121 deletions
diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index a7160b4..e4c937f 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -31,8 +31,8 @@
namespace rcc::riscv {
namespace {
-[[nodiscard]] std::optional<LLT> registerType(const MachineFunction &Function,
- const MachineOperand &Operand) {
+[[nodiscard]] std::optional<LowLevelType> registerType(const MachineFunction &Function,
+ const MachineOperand &Operand) {
const Register *Reg = Operand.getIf<Register>();
if (Reg == nullptr || !Reg->isVirtual())
return std::nullopt;
@@ -42,43 +42,59 @@ namespace {
return Info->get().Type;
}
-[[nodiscard]] std::optional<LLT> resultType(const MachineFunction &Function,
- const MachineInstr &Instruction) {
+[[nodiscard]] std::optional<LowLevelType> resultType(const MachineFunction &Function,
+ const MachineInstr &Instruction) {
const MachineOperand *Result = Instruction.operandAt(0);
return Result == nullptr ? std::nullopt : registerType(Function, *Result);
}
-[[nodiscard]] std::optional<LLT> operandType(const MachineFunction &Function,
- const MachineInstr &Instruction, std::size_t Index) {
+[[nodiscard]] std::optional<LowLevelType>
+operandType(const MachineFunction &Function, const MachineInstr &Instruction, std::size_t Index) {
const MachineOperand *Operand = Instruction.operandAt(Index);
return Operand == nullptr ? std::nullopt : registerType(Function, *Operand);
}
-[[nodiscard]] bool isRVFloatType(LLT Type) noexcept {
- if (!Type.isFloat())
- return false;
- const std::optional<FloatSemantics> Semantics = Type.floatSemantics();
- return Semantics &&
- (*Semantics == FloatSemantics::IEEESingle || *Semantics == FloatSemantics::IEEEDouble);
+[[nodiscard]] bool isSupportedFloatingScalar(LowLevelType Type) noexcept {
+ return Type.isCategoryNeutralScalar() &&
+ (Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64);
}
-[[nodiscard]] bool isSupportedIntegerType(LLT Type) noexcept {
- return ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 &&
+[[nodiscard]] bool isSupportedIntegerType(LowLevelType Type) noexcept {
+ return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 &&
Type.scalarBitWidth() <= 64) ||
(Type.isPointer() && Type.scalarBitWidth() == 64);
}
-[[nodiscard]] bool isSupportedIntegerScalar(LLT Type) noexcept {
- return (Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 &&
+[[nodiscard]] bool isSupportedIntegerScalar(LowLevelType Type) noexcept {
+ return Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 &&
Type.scalarBitWidth() <= 64;
}
-[[nodiscard]] bool isScalarGPRType(LLT Type) noexcept {
- return ((Type.isInteger() || Type.isAnyScalar()) && Type.scalarBitWidth() != 0 &&
+[[nodiscard]] bool isScalarGPRType(LowLevelType Type) noexcept {
+ return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 &&
Type.scalarBitWidth() <= 64) ||
(Type.isPointer() && Type.scalarBitWidth() == 64);
}
+[[nodiscard]] constexpr RegisterBankID fprBank() noexcept {
+ return RegisterBankID::fromValue(static_cast<std::uint32_t>(RegisterBank::FPR));
+}
+
+[[nodiscard]] Expected<RegisterBankID> registerBank(const MachineFunction &Function, Register Reg) {
+ if (!Reg.isVirtual()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V generic instruction requires a virtual register");
+ }
+ auto Info = Function.registerInfo().virtualRegisterInfo(Reg);
+ if (!Info)
+ return std::unexpected(Info.error());
+ if (!Info->get().Bank) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "RISC-V instruction selection requires an assigned register bank");
+ }
+ return *Info->get().Bank;
+}
+
[[nodiscard]] bool fitsSigned(std::int64_t Value, std::uint32_t Bits) noexcept {
const std::int64_t Minimum = -(std::int64_t{1} << (Bits - 1U));
const std::int64_t Maximum = (std::int64_t{1} << (Bits - 1U)) - 1;
@@ -146,9 +162,9 @@ public:
const MachineFunction &Function,
const TargetDescription &Target) const override {
if (Instruction.opcode() == instructionOpcode(InstructionOpcode::G_SLLW)) {
- const std::optional<LLT> Type = resultType(Function, Instruction);
- const std::optional<LLT> Left = operandType(Function, Instruction, 1);
- const std::optional<LLT> Right = operandType(Function, Instruction, 2);
+ const std::optional<LowLevelType> Type = resultType(Function, Instruction);
+ const std::optional<LowLevelType> Left = operandType(Function, Instruction, 1);
+ const std::optional<LowLevelType> Right = operandType(Function, Instruction, 2);
return Type && Left && Right && isScalarGPRType(*Type) && Type->scalarBitWidth() == 64 &&
*Left == *Type && *Right == *Type
? Expected<void>{}
@@ -158,9 +174,9 @@ public:
if (!isGenericOpcode(Instruction.opcode()))
return {};
const GenericOpcode Generic = static_cast<GenericOpcode>(Instruction.opcode().value());
- const std::optional<LLT> Type = resultType(Function, Instruction);
+ const std::optional<LowLevelType> Type = resultType(Function, Instruction);
const auto Integer = [Type] { return Type && isSupportedIntegerType(*Type); };
- const auto Float = [Type] { return Type && isRVFloatType(*Type); };
+ const auto Float = [Type] { return Type && isSupportedFloatingScalar(*Type); };
auto Classification = Subtarget.getLegalizerInfo()->classify(Instruction, Function, Target);
if (!Classification)
return std::unexpected(Classification.error());
@@ -226,8 +242,7 @@ public:
const MachineOperand *Immediate = Instruction.operandAt(1);
const auto *Floating =
Immediate == nullptr ? nullptr : Immediate->getIf<FloatingImmediateOperand>();
- const std::optional<FloatSemantics> Semantics = Type ? Type->floatSemantics() : std::nullopt;
- if (!Float() || Floating == nullptr || !Semantics || Floating->Bits.semantics() != *Semantics)
+ if (!Float() || Floating == nullptr || Floating->Bits.bitWidth() != Type->scalarBitWidth())
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V selector requires a matching floating constant");
return {};
@@ -240,7 +255,6 @@ public:
case GenericOpcode::G_CONSTANT_FOLD_BARRIER:
case GenericOpcode::G_PTRTOINT:
case GenericOpcode::G_INTTOPTR:
- case GenericOpcode::G_BITCAST:
case GenericOpcode::G_TRUNC:
case GenericOpcode::G_SEXT:
case GenericOpcode::G_SEXT_INREG:
@@ -307,7 +321,7 @@ public:
if (Instruction.opcode() == instructionOpcode(InstructionOpcode::G_SLLW))
return Instruction.setOpcode(instructionOpcode(InstructionOpcode::SLLW));
const GenericOpcode Generic = static_cast<GenericOpcode>(Instruction.opcode().value());
- const std::optional<LLT> Type = resultType(Function, Instruction);
+ const std::optional<LowLevelType> Type = resultType(Function, Instruction);
const auto SelectDirect = [&Instruction](InstructionOpcode Selected) {
return Instruction.setOpcode(instructionOpcode(Selected));
@@ -364,7 +378,7 @@ public:
case GenericOpcode::G_PTRMASK:
return SelectDirect(InstructionOpcode::AND);
case GenericOpcode::G_LOAD:
- return selectLoad(Instruction, Type);
+ return selectLoad(Instruction, Function, Type);
case GenericOpcode::G_SEXTLOAD:
return selectExtLoad(Instruction, Type, true);
case GenericOpcode::G_ZEXTLOAD:
@@ -397,8 +411,6 @@ public:
case GenericOpcode::G_PTRTOINT:
case GenericOpcode::G_INTTOPTR:
return Instruction.setOpcode(opcode(GenericOpcode::COPY));
- case GenericOpcode::G_BITCAST:
- return selectBitcast(Instruction, Function);
case GenericOpcode::G_FADD:
return selectRoundingBinary(Instruction, Type, InstructionOpcode::FADD_S,
InstructionOpcode::FADD_D);
@@ -526,11 +538,17 @@ public:
}
private:
- [[nodiscard]] Expected<Register> createTemporary(MachineFunction &Function, LLT Type,
- const TargetDescription &Target) const {
+ [[nodiscard]] Expected<Register>
+ createTemporary(MachineFunction &Function, LowLevelType Type, const TargetDescription &Target,
+ std::optional<RegisterBankID> Bank = std::nullopt) const {
auto Temporary = Function.registerInfo().createVirtualRegister(Type);
if (!Temporary)
return std::unexpected(Temporary.error());
+ if (Bank) {
+ auto SetBank = Function.registerInfo().setRegisterBank(*Temporary, *Bank);
+ if (!SetBank)
+ return std::unexpected(SetBank.error());
+ }
auto Constraint = RegisterBanks.constrainRegister(Function, *Temporary, Target);
if (!Constraint)
return std::unexpected(Constraint.error());
@@ -624,7 +642,7 @@ private:
[[nodiscard]] Expected<Register> normalizeIntegerBefore(MachineInstr &Anchor,
MachineFunction &Function,
const TargetDescription &Target,
- Register Source, LLT Type,
+ Register Source, LowLevelType Type,
bool Signed) const {
if (!isSupportedIntegerScalar(Type))
return makeUnexpected(ErrorCode::Unsupported,
@@ -689,9 +707,9 @@ private:
[[nodiscard]] Expected<MachineInstr *>
buildGPRSelectAfter(MachineIRBuilder &Builder, MachineInstr &Anchor, MachineFunction &Function,
- const TargetDescription &Target, LLT ValueType, Register Destination,
+ const TargetDescription &Target, LowLevelType ValueType, Register Destination,
Register Condition, Register TrueValue, Register FalseValue) const {
- auto IntegerType = LLT::makeInteger(ValueType.scalarBitWidth());
+ auto IntegerType = LowLevelType::makeCategoryNeutralScalar(ValueType.scalarBitWidth());
if (!IntegerType)
return std::unexpected(IntegerType.error());
auto Mask = createTemporary(Function, *IntegerType, Target);
@@ -725,7 +743,7 @@ private:
[[nodiscard]] Expected<void> selectDivRem(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type, bool Signed) const {
+ std::optional<LowLevelType> Type, bool Signed) const {
const MachineOperand *RemainderOperand = Instruction.operandAt(1);
const MachineOperand *LeftOperand = Instruction.operandAt(2);
const MachineOperand *RightOperand = Instruction.operandAt(3);
@@ -772,7 +790,8 @@ private:
[[nodiscard]] Expected<void> selectMultiplyHigh(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type, bool Signed) const {
+ std::optional<LowLevelType> Type,
+ bool Signed) const {
if (!Type)
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V high multiplication has no result type");
@@ -793,7 +812,7 @@ private:
"RISC-V high multiplication has invalid register operands");
const Register DestinationRegister = *Destination;
const Register RightRegister = *Right;
- auto I64 = LLT::makeInteger(64);
+ auto I64 = LowLevelType::makeCategoryNeutralScalar(64);
if (!I64)
return std::unexpected(I64.error());
auto ExtendedLeft = createTemporary(Function, *I64, Target);
@@ -868,7 +887,7 @@ private:
[[nodiscard]] Expected<void> selectIntegerMinMax(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
GenericOpcode Generic) const {
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
const MachineOperand *LeftOperand = Instruction.operandAt(1);
@@ -880,7 +899,7 @@ private:
if (!Type || Destination == nullptr || Left == nullptr || Right == nullptr)
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V integer min/max has invalid operands");
- auto I1 = LLT::makeInteger(1);
+ auto I1 = LowLevelType::makeCategoryNeutralScalar(1);
if (!I1)
return std::unexpected(I1.error());
auto Condition = createTemporary(Function, *I1, Target);
@@ -922,7 +941,7 @@ private:
[[nodiscard]] Expected<void> selectValue(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type) const {
+ std::optional<LowLevelType> Type) const {
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
const MachineOperand *ConditionOperand = Instruction.operandAt(1);
const MachineOperand *TrueOperand = Instruction.operandAt(2);
@@ -942,7 +961,7 @@ private:
const Register DestinationRegister = *Destination;
const Register TrueRegister = *TrueValue;
const Register FalseRegister = *FalseValue;
- auto I1 = LLT::makeInteger(1);
+ auto I1 = LowLevelType::makeCategoryNeutralScalar(1);
if (!I1)
return std::unexpected(I1.error());
auto NormalizedCondition = createTemporary(Function, *I1, Target);
@@ -964,8 +983,12 @@ private:
if (!SetNormalize)
return std::unexpected(SetNormalize.error());
+ auto DestinationBank = registerBank(Function, DestinationRegister);
+ if (!DestinationBank)
+ return std::unexpected(DestinationBank.error());
+
MachineIRBuilder Builder(Function, Target);
- if (!Type->isFloat()) {
+ if (*DestinationBank != fprBank()) {
auto Selected =
buildGPRSelectAfter(Builder, Instruction, Function, Target, *Type, DestinationRegister,
*NormalizedCondition, TrueRegister, FalseRegister);
@@ -974,7 +997,7 @@ private:
return {};
}
- auto IntegerType = LLT::makeInteger(Type->scalarBitWidth());
+ auto IntegerType = LowLevelType::makeCategoryNeutralScalar(Type->scalarBitWidth());
if (!IntegerType)
return std::unexpected(IntegerType.error());
auto IntegerTrue = createTemporary(Function, *IntegerType, Target);
@@ -1010,7 +1033,7 @@ private:
[[nodiscard]] Expected<void> selectAbsoluteValue(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type) const {
+ std::optional<LowLevelType> Type) const {
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
const MachineOperand *SourceOperand = Instruction.operandAt(1);
const Register *Destination =
@@ -1059,12 +1082,13 @@ private:
[[nodiscard]] Expected<std::pair<Register, MachineInstr *>>
buildSignedOverflowAfter(MachineIRBuilder &Builder, MachineInstr &Anchor,
- MachineFunction &Function, const TargetDescription &Target, LLT Type,
- Register Result, Register Left, Register Right, bool IsAdd) const {
+ MachineFunction &Function, const TargetDescription &Target,
+ LowLevelType Type, Register Result, Register Left, Register Right,
+ bool IsAdd) const {
auto FirstDifference = createTemporary(Function, Type, Target);
auto SecondDifference = createTemporary(Function, Type, Target);
auto SignBits = createTemporary(Function, Type, Target);
- auto I1 = LLT::makeInteger(1);
+ auto I1 = LowLevelType::makeCategoryNeutralScalar(1);
if (!I1)
return std::unexpected(I1.error());
auto Overflow = createTemporary(Function, *I1, Target);
@@ -1101,7 +1125,7 @@ private:
[[nodiscard]] Expected<void> selectOverflow(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
GenericOpcode Generic) const {
const MachineOperand *ResultOperand = Instruction.operandAt(0);
const MachineOperand *OverflowOperand = Instruction.operandAt(1);
@@ -1183,7 +1207,7 @@ private:
return {};
}
- auto I64 = LLT::makeInteger(64);
+ auto I64 = LowLevelType::makeCategoryNeutralScalar(64);
if (!I64)
return std::unexpected(I64.error());
auto Zero = physicalRegister(PhysicalRegisterID::X0);
@@ -1305,7 +1329,7 @@ private:
[[nodiscard]] Expected<void> selectExtendedOverflow(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
GenericOpcode Generic) const {
const MachineOperand *ResultOperand = Instruction.operandAt(0);
const MachineOperand *CarryOutOperand = Instruction.operandAt(1);
@@ -1336,7 +1360,7 @@ private:
IsAdd ? (IsWord ? InstructionOpcode::ADDW : InstructionOpcode::ADD)
: (IsWord ? InstructionOpcode::SUBW : InstructionOpcode::SUB);
auto Partial = createTemporary(Function, *Type, Target);
- auto I1 = LLT::makeInteger(1);
+ auto I1 = LowLevelType::makeCategoryNeutralScalar(1);
if (!Partial || !I1)
return std::unexpected(!Partial ? Partial.error() : I1.error());
auto NormalizedCarry = createTemporary(Function, *I1, Target);
@@ -1404,7 +1428,7 @@ private:
[[nodiscard]] Expected<void> selectAtomicRMW(MachineInstr &Instruction, MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
GenericOpcode Generic) const {
const MachineOperand *AddressOperand = Instruction.operandAt(1);
const MachineOperand *ValueOperand = Instruction.operandAt(2);
@@ -1484,8 +1508,8 @@ private:
MachineFunction &Function,
const TargetDescription &Target,
GenericOpcode Generic,
- std::optional<LLT> Type) const {
- const std::optional<LLT> SourceType = operandType(Function, Instruction, 1);
+ std::optional<LowLevelType> Type) const {
+ const std::optional<LowLevelType> SourceType = operandType(Function, Instruction, 1);
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
const MachineOperand *SourceOperand = Instruction.operandAt(1);
const Register *Destination =
@@ -1539,7 +1563,7 @@ private:
[[nodiscard]] Expected<void> selectSignExtendInRegister(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type) const {
+ std::optional<LowLevelType> Type) const {
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
const MachineOperand *SourceOperand = Instruction.operandAt(1);
const Register *Destination =
@@ -1610,7 +1634,7 @@ private:
DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf<Register>();
const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf<Register>();
- const std::optional<LLT> LeftType = operandType(Function, Instruction, 2);
+ const std::optional<LowLevelType> LeftType = operandType(Function, Instruction, 2);
if (Predicate == nullptr || Predicate->integerPredicate() == nullptr ||
Destination == nullptr || Left == nullptr || Right == nullptr || !LeftType)
return makeUnexpected(ErrorCode::VerificationError,
@@ -1779,8 +1803,8 @@ private:
DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf<Register>();
const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf<Register>();
- const std::optional<LLT> FloatType = operandType(Function, Instruction, 2);
- const std::optional<LLT> ResultType = resultType(Function, Instruction);
+ const std::optional<LowLevelType> FloatType = operandType(Function, Instruction, 2);
+ const std::optional<LowLevelType> ResultType = resultType(Function, Instruction);
if (Predicate == nullptr || Predicate->floatingPredicate() == nullptr ||
Destination == nullptr || Left == nullptr || Right == nullptr || !FloatType || !ResultType)
return makeUnexpected(ErrorCode::VerificationError,
@@ -1951,8 +1975,9 @@ private:
[[nodiscard]] Expected<void> selectFloatToInteger(MachineInstr &Instruction,
MachineFunction &Function,
- std::optional<LLT> Type, bool Unsigned) const {
- const std::optional<LLT> Source = operandType(Function, Instruction, 1);
+ std::optional<LowLevelType> Type,
+ bool Unsigned) const {
+ const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1);
if (!Type || !Source)
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V floating-to-integer conversion has invalid types");
@@ -1973,8 +1998,9 @@ private:
[[nodiscard]] Expected<void> selectIntegerToFloat(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type, bool Unsigned) const {
- const std::optional<LLT> Source = operandType(Function, Instruction, 1);
+ std::optional<LowLevelType> Type,
+ bool Unsigned) const {
+ const std::optional<LowLevelType> Source = operandType(Function, Instruction, 1);
const MachineOperand *SourceOperand = Instruction.operandAt(1);
const Register *SourceRegister =
SourceOperand == nullptr ? nullptr : SourceOperand->getIf<Register>();
@@ -2003,12 +2029,12 @@ private:
}
[[nodiscard]] Expected<void> selectFloatingMinMax(MachineInstr &Instruction,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
InstructionOpcode Single,
InstructionOpcode Double) const {
- if (Type && Type->isFloat() && Type->scalarBitWidth() == 32)
+ if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 32)
return Instruction.setOpcode(instructionOpcode(Single));
- if (Type && Type->isFloat() && Type->scalarBitWidth() == 64)
+ if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64)
return Instruction.setOpcode(instructionOpcode(Double));
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V cannot select this floating min/max type");
@@ -2068,40 +2094,20 @@ private:
return Instruction.setOpcode(instructionOpcode(InstructionOpcode::EBREAK));
}
- [[nodiscard]] Expected<void> selectBitcast(MachineInstr &Instruction,
- MachineFunction &Function) const {
- const std::optional<LLT> DestinationType = resultType(Function, Instruction);
- const std::optional<LLT> SourceType = operandType(Function, Instruction, 1);
- if (!DestinationType || !SourceType)
- return makeUnexpected(ErrorCode::VerificationError,
- "RISC-V bitcast has invalid register types");
- if (DestinationType->isInteger() && SourceType->isFloat()) {
- return Instruction.setOpcode(instructionOpcode(SourceType->scalarBitWidth() == 32
- ? InstructionOpcode::FMV_X_W
- : InstructionOpcode::FMV_X_D));
- }
- if (DestinationType->isFloat() && SourceType->isInteger()) {
- return Instruction.setOpcode(instructionOpcode(DestinationType->scalarBitWidth() == 32
- ? InstructionOpcode::FMV_W_X
- : InstructionOpcode::FMV_D_X));
- }
- return makeUnexpected(ErrorCode::Unsupported, "RISC-V bitcast pair is unsupported");
- }
-
[[nodiscard]] Expected<void> selectIntegerBinary(MachineInstr &Instruction,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
InstructionOpcode DoubleWord,
InstructionOpcode Word) const {
if (!Type || !isSupportedIntegerType(*Type))
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V integer instruction requires a supported scalar integer");
- const bool IsWord = Type->isInteger() && Type->scalarBitWidth() <= 32;
+ const bool IsWord = Type->isCategoryNeutralScalar() && Type->scalarBitWidth() <= 32;
return Instruction.setOpcode(instructionOpcode(IsWord ? Word : DoubleWord));
}
[[nodiscard]] Expected<void>
selectNormalizedIntegerBinary(MachineInstr &Instruction, MachineFunction &Function,
- const TargetDescription &Target, std::optional<LLT> Type,
+ const TargetDescription &Target, std::optional<LowLevelType> Type,
InstructionOpcode DoubleWord, InstructionOpcode Word, bool Signed,
bool NormalizeRight) const {
const MachineOperand *LeftOperand = Instruction.operandAt(1);
@@ -2134,8 +2140,8 @@ private:
return Instruction.setOpcode(instructionOpcode(IsWord ? Word : DoubleWord));
}
- [[nodiscard]] Expected<void> selectLoad(MachineInstr &Instruction,
- std::optional<LLT> Type) const {
+ [[nodiscard]] Expected<void> selectLoad(MachineInstr &Instruction, MachineFunction &Function,
+ std::optional<LowLevelType> Type) const {
if (!Type)
return makeUnexpected(ErrorCode::VerificationError,
"load result has no virtual-register type");
@@ -2143,8 +2149,16 @@ private:
if (!Bytes)
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V load size does not match its result type");
+ const MachineOperand *DestinationOperand = Instruction.operandAt(0);
+ const Register *Destination =
+ DestinationOperand == nullptr ? nullptr : DestinationOperand->getIf<Register>();
+ if (Destination == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError, "RISC-V load has no destination");
+ auto Bank = registerBank(Function, *Destination);
+ if (!Bank)
+ return std::unexpected(Bank.error());
if (Instruction.memOperands().front()->isAtomic()) {
- if (!isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8))
+ if (*Bank == fprBank() || !isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8))
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V atomic load requires a 32-bit or 64-bit GPR value");
return Instruction.setOpcode(
@@ -2153,7 +2167,7 @@ private:
auto AppendOffset = appendImmediate(Instruction, 0);
if (!AppendOffset)
return std::unexpected(AppendOffset.error());
- if (isSupportedIntegerType(*Type)) {
+ if (*Bank != fprBank() && isSupportedIntegerType(*Type)) {
const InstructionOpcode Selected = *Bytes == 1 ? InstructionOpcode::LB
: *Bytes == 2 ? InstructionOpcode::LH
: *Bytes == 4 ? InstructionOpcode::LW
@@ -2163,15 +2177,15 @@ private:
return makeUnexpected(ErrorCode::Unsupported, "RISC-V integer load width is unsupported");
return Instruction.setOpcode(instructionOpcode(Selected));
}
- if (Type->isFloat() && Type->scalarBitWidth() == 32)
+ if (*Bank == fprBank() && Type->scalarBitWidth() == 32 && *Bytes == 4)
return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FLW));
- if (Type->isFloat() && Type->scalarBitWidth() == 64)
+ if (*Bank == fprBank() && Type->scalarBitWidth() == 64 && *Bytes == 8)
return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FLD));
return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this generic load type");
}
- [[nodiscard]] Expected<void> selectExtLoad(MachineInstr &Instruction, std::optional<LLT> Type,
- bool Signed) const {
+ [[nodiscard]] Expected<void> selectExtLoad(MachineInstr &Instruction,
+ std::optional<LowLevelType> Type, bool Signed) const {
if (!Type || !isSupportedIntegerType(*Type))
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V extension load requires an integer result");
@@ -2201,10 +2215,10 @@ private:
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V floating extension load has no destination register");
const Register DestinationRegister = *Destination;
- auto F32 = LLT::makeFloat(FloatSemantics::IEEESingle);
+ auto F32 = LowLevelType::makeCategoryNeutralScalar(32);
if (!F32)
return std::unexpected(F32.error());
- auto Temporary = createTemporary(Function, *F32, Target);
+ auto Temporary = createTemporary(Function, *F32, Target, fprBank());
if (!Temporary)
return std::unexpected(Temporary.error());
auto SetDestination = Instruction.operandAt(0)->setRegister(*Temporary);
@@ -2233,10 +2247,10 @@ private:
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V floating truncation store has no value register");
const Register ValueRegister = *Value;
- auto F32 = LLT::makeFloat(FloatSemantics::IEEESingle);
+ auto F32 = LowLevelType::makeCategoryNeutralScalar(32);
if (!F32)
return std::unexpected(F32.error());
- auto Temporary = createTemporary(Function, *F32, Target);
+ auto Temporary = createTemporary(Function, *F32, Target, fprBank());
if (!Temporary)
return std::unexpected(Temporary.error());
MachineIRBuilder Builder(Function, Target);
@@ -2270,7 +2284,7 @@ private:
[[nodiscard]] Expected<void> selectStore(MachineInstr &Instruction,
MachineFunction &Function) const {
const MachineOperand *Value = Instruction.operandAt(0);
- const std::optional<LLT> Type =
+ const std::optional<LowLevelType> Type =
Value == nullptr ? std::nullopt : registerType(Function, *Value);
if (!Type)
return makeUnexpected(ErrorCode::VerificationError,
@@ -2279,8 +2293,14 @@ private:
if (!Bytes)
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V store size does not match its value type");
+ const Register *ValueRegister = Value->getIf<Register>();
+ if (ValueRegister == nullptr)
+ return makeUnexpected(ErrorCode::VerificationError, "RISC-V store has no value register");
+ auto Bank = registerBank(Function, *ValueRegister);
+ if (!Bank)
+ return std::unexpected(Bank.error());
if (Instruction.memOperands().front()->isAtomic()) {
- if (!isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8))
+ if (*Bank == fprBank() || !isSupportedIntegerType(*Type) || (*Bytes != 4 && *Bytes != 8))
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V atomic store requires a 32-bit or 64-bit GPR value");
auto Zero = physicalRegister(PhysicalRegisterID::X0);
@@ -2295,7 +2315,7 @@ private:
auto AppendOffset = appendImmediate(Instruction, 0);
if (!AppendOffset)
return std::unexpected(AppendOffset.error());
- if (isSupportedIntegerType(*Type)) {
+ if (*Bank != fprBank() && isSupportedIntegerType(*Type)) {
const InstructionOpcode Selected = *Bytes == 1 ? InstructionOpcode::SB
: *Bytes == 2 ? InstructionOpcode::SH
: *Bytes == 4 ? InstructionOpcode::SW
@@ -2305,9 +2325,9 @@ private:
return makeUnexpected(ErrorCode::Unsupported, "RISC-V integer store width is unsupported");
return Instruction.setOpcode(instructionOpcode(Selected));
}
- if (Type->isFloat() && Type->scalarBitWidth() == 32)
+ if (*Bank == fprBank() && Type->scalarBitWidth() == 32 && *Bytes == 4)
return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FSW));
- if (Type->isFloat() && Type->scalarBitWidth() == 64)
+ if (*Bank == fprBank() && Type->scalarBitWidth() == 64 && *Bytes == 8)
return Instruction.setOpcode(instructionOpcode(InstructionOpcode::FSD));
return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this generic store type");
}
@@ -2335,7 +2355,7 @@ private:
[[nodiscard]] Expected<void> selectIntegerConstant(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type) const {
+ std::optional<LowLevelType> Type) const {
if (!Type || !isSupportedIntegerType(*Type)) {
return makeUnexpected(ErrorCode::Unsupported,
"RISC-V constant selection requires an i1-i64 or pointer result");
@@ -2357,7 +2377,7 @@ private:
const Register Destination = *DestinationValue;
const std::int64_t Value = *ImmediateValue;
const std::uint32_t ImmediateTargetFlags = ImmediateOperand->targetFlags();
- const bool IsWord = Type->isInteger() && Type->scalarBitWidth() <= 32;
+ const bool IsWord = Type->isCategoryNeutralScalar() && Type->scalarBitWidth() <= 32;
const InstructionOpcode AddImmediate =
IsWord ? InstructionOpcode::ADDIW : InstructionOpcode::ADDI;
const InstructionOpcode ShiftLeftImmediate =
@@ -2488,14 +2508,13 @@ private:
[[nodiscard]] Expected<void> selectFloatingConstant(MachineInstr &Instruction,
MachineFunction &Function,
const TargetDescription &Target,
- std::optional<LLT> Type) const {
- if (!Type || !isRVFloatType(*Type))
+ std::optional<LowLevelType> Type) const {
+ if (!Type || !isSupportedFloatingScalar(*Type))
return makeUnexpected(ErrorCode::Unsupported, "RISC-V floating constant requires f32 or f64");
const MachineOperand *Immediate = Instruction.operandAt(1);
const auto *Floating =
Immediate == nullptr ? nullptr : Immediate->getIf<FloatingImmediateOperand>();
- const std::optional<FloatSemantics> Semantics = Type->floatSemantics();
- if (Floating == nullptr || !Semantics || Floating->Bits.semantics() != *Semantics)
+ if (Floating == nullptr || Floating->Bits.bitWidth() != Type->scalarBitWidth())
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V floating constant has mismatched bit semantics");
const MachineOperand *DestinationOperand = Instruction.operandAt(0);
@@ -2511,7 +2530,7 @@ private:
auto Integer = APInt::fromUnsigned(64, Bits);
if (!Integer)
return std::unexpected(Integer.error());
- auto IntegerType = LLT::makeInteger(64);
+ auto IntegerType = LowLevelType::makeCategoryNeutralScalar(64);
if (!IntegerType)
return std::unexpected(IntegerType.error());
auto Temporary = createTemporary(Function, *IntegerType, Target);
@@ -2564,35 +2583,35 @@ private:
}
[[nodiscard]] Expected<void> selectRoundingBinary(MachineInstr &Instruction,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
InstructionOpcode Single,
InstructionOpcode Double) const {
auto RoundingMode = appendImmediate(Instruction, 0);
if (!RoundingMode)
return std::unexpected(RoundingMode.error());
- if (Type && Type->isFloat() && Type->scalarBitWidth() == 32)
+ if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 32)
return Instruction.setOpcode(instructionOpcode(Single));
- if (Type && Type->isFloat() && Type->scalarBitWidth() == 64)
+ if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64)
return Instruction.setOpcode(instructionOpcode(Double));
return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this floating binary type");
}
[[nodiscard]] Expected<void> selectRoundingTernary(MachineInstr &Instruction,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
InstructionOpcode Single,
InstructionOpcode Double) const {
return selectRoundingBinary(Instruction, Type, Single, Double);
}
[[nodiscard]] Expected<void> selectRoundingUnary(MachineInstr &Instruction,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
InstructionOpcode Single,
InstructionOpcode Double) const {
return selectRoundingBinary(Instruction, Type, Single, Double);
}
[[nodiscard]] Expected<void> selectSignInjection(MachineInstr &Instruction,
- std::optional<LLT> Type,
+ std::optional<LowLevelType> Type,
InstructionOpcode Single,
InstructionOpcode Double) const {
const MachineOperand *Source = Instruction.operandAt(1);
@@ -2603,9 +2622,9 @@ private:
auto Duplicate = insertVirtualUse(Instruction, 2, *SourceReg);
if (!Duplicate)
return std::unexpected(Duplicate.error());
- if (Type && Type->isFloat() && Type->scalarBitWidth() == 32)
+ if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 32)
return Instruction.setOpcode(instructionOpcode(Single));
- if (Type && Type->isFloat() && Type->scalarBitWidth() == 64)
+ if (Type && Type->isCategoryNeutralScalar() && Type->scalarBitWidth() == 64)
return Instruction.setOpcode(instructionOpcode(Double));
return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this floating unary type");
}