aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/Target
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/Target')
-rw-r--r--backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp344
-rw-r--r--backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc114
2 files changed, 316 insertions, 142 deletions
diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index dd63743..db7ef45 100644
--- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -66,6 +66,76 @@ operandType(const MachineFunction &Function, const MachineInstr &Instruction, st
(Type.scalarBitWidth() == 32 || Type.scalarBitWidth() == 64);
}
+[[nodiscard]] Expected<InstructionOpcode> floatingCompareOpcode(FloatingPredicate Predicate,
+ std::uint32_t BitWidth) {
+ if (BitWidth == 32) {
+ switch (Predicate) {
+ case FloatingPredicate::OrderedEqual:
+ return InstructionOpcode::FEQ_S;
+ case FloatingPredicate::OrderedLessThan:
+ return InstructionOpcode::FLT_S;
+ case FloatingPredicate::OrderedLessEqual:
+ return InstructionOpcode::FLE_S;
+ default:
+ break;
+ }
+ } else if (BitWidth == 64) {
+ switch (Predicate) {
+ case FloatingPredicate::OrderedEqual:
+ return InstructionOpcode::FEQ_D;
+ case FloatingPredicate::OrderedLessThan:
+ return InstructionOpcode::FLT_D;
+ case FloatingPredicate::OrderedLessEqual:
+ return InstructionOpcode::FLE_D;
+ default:
+ break;
+ }
+ }
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RISC-V floating comparison predicate is not directly supported");
+}
+
+// Convert a floating predicate by swapping or inverting it to one supported by
+// a scalar RISC-V comparison instruction.
+[[nodiscard]] bool legalizeFloatingPredicate(Register &Left, Register &Right,
+ FloatingPredicate &Predicate,
+ bool &NeedsInvert) noexcept {
+ switch (Predicate) {
+ case FloatingPredicate::OrderedGreaterThan:
+ Predicate = FloatingPredicate::OrderedLessThan;
+ std::swap(Left, Right);
+ return true;
+ case FloatingPredicate::OrderedGreaterEqual:
+ Predicate = FloatingPredicate::OrderedLessEqual;
+ std::swap(Left, Right);
+ return true;
+ case FloatingPredicate::UnorderedNotEqual:
+ Predicate = FloatingPredicate::OrderedEqual;
+ NeedsInvert = true;
+ return true;
+ case FloatingPredicate::UnorderedGreaterThan:
+ Predicate = FloatingPredicate::OrderedLessEqual;
+ NeedsInvert = true;
+ return true;
+ case FloatingPredicate::UnorderedGreaterEqual:
+ Predicate = FloatingPredicate::OrderedLessThan;
+ NeedsInvert = true;
+ return true;
+ case FloatingPredicate::UnorderedLessThan:
+ Predicate = FloatingPredicate::OrderedLessEqual;
+ NeedsInvert = true;
+ std::swap(Left, Right);
+ return true;
+ case FloatingPredicate::UnorderedLessEqual:
+ Predicate = FloatingPredicate::OrderedLessThan;
+ NeedsInvert = true;
+ std::swap(Left, Right);
+ return true;
+ default:
+ return false;
+ }
+}
+
[[nodiscard]] bool isSupportedIntegerType(LowLevelType Type) noexcept {
return (Type.isCategoryNeutralScalar() && Type.scalarBitWidth() != 0 &&
Type.scalarBitWidth() <= 64) ||
@@ -955,168 +1025,158 @@ private:
Destination == nullptr || Left == nullptr || Right == nullptr || !FloatType || !ResultType)
return makeUnexpected(ErrorCode::VerificationError,
"RISC-V floating comparison has invalid operands");
- const FloatingPredicate Condition = *Predicate->floatingPredicate();
+ FloatingPredicate Condition = *Predicate->floatingPredicate();
const Register DestinationRegister = *Destination;
- const Register LeftRegister = *Left;
- const Register RightRegister = *Right;
- const InstructionOpcode EqualOpcode =
- FloatType->scalarBitWidth() == 32 ? InstructionOpcode::FEQ_S : InstructionOpcode::FEQ_D;
- const InstructionOpcode LessOpcode =
- FloatType->scalarBitWidth() == 32 ? InstructionOpcode::FLT_S : InstructionOpcode::FLT_D;
- const InstructionOpcode LessEqualOpcode =
- FloatType->scalarBitWidth() == 32 ? InstructionOpcode::FLE_S : InstructionOpcode::FLE_D;
-
- auto ErasePredicate = Instruction.eraseOperand(1);
- if (!ErasePredicate)
- return std::unexpected(ErasePredicate.error());
- const auto SetBase = [&Instruction](InstructionOpcode OpcodeValue, Register Def,
- Register NewLeft, Register NewRight) -> Expected<void> {
- auto SetDestination = Instruction.operandAt(0)->setRegister(Def);
- if (!SetDestination)
- return std::unexpected(SetDestination.error());
- auto SetLeft = Instruction.operandAt(1)->setRegister(NewLeft);
- if (!SetLeft)
- return std::unexpected(SetLeft.error());
- auto SetRight = Instruction.operandAt(2)->setRegister(NewRight);
- if (!SetRight)
- return std::unexpected(SetRight.error());
- return Instruction.setOpcode(instructionOpcode(OpcodeValue));
+ Register LeftRegister = *Left;
+ Register RightRegister = *Right;
+ MachineIRBuilder Builder(Function, Target);
+
+ const auto BuildBinary = [&](InstructionOpcode OpcodeValue, Register Def, Register LeftValue,
+ Register RightValue) -> Expected<MachineInstr *> {
+ auto Point = Builder.setInsertPointBefore(Instruction);
+ if (!Point)
+ return std::unexpected(Point.error());
+ auto Registers = constrainBuilderRegisters(Function, Target, {Def, LeftValue, RightValue});
+ if (!Registers)
+ return std::unexpected(Registers.error());
+ auto Pending = Builder.buildInstr(instructionOpcode(OpcodeValue));
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ auto DefResult = Pending->addDef(Def);
+ if (!DefResult)
+ return std::unexpected(DefResult.error());
+ auto LeftResult = Pending->addUse(LeftValue);
+ if (!LeftResult)
+ return std::unexpected(LeftResult.error());
+ auto RightResult = Pending->addUse(RightValue);
+ if (!RightResult)
+ return std::unexpected(RightResult.error());
+ auto Built = Pending->build();
+ if (!Built)
+ return std::unexpected(Built.error());
+ auto Constraint = constrainSelectedInstruction(**Built, Function, Target);
+ if (!Constraint)
+ return std::unexpected(Constraint.error());
+ return *Built;
};
- const auto BuildInverted = [&](InstructionOpcode BaseOpcode, Register BaseLeft,
- Register BaseRight) -> Expected<void> {
- auto Temporary = createTemporary(Function, *ResultType, Target);
- if (!Temporary)
- return std::unexpected(Temporary.error());
- auto Base = SetBase(BaseOpcode, *Temporary, BaseLeft, BaseRight);
- if (!Base)
- return std::unexpected(Base.error());
- MachineIRBuilder Builder(Function, Target);
- auto Invert = buildImmediateAfter(Builder, Instruction, InstructionOpcode::XORI,
- DestinationRegister, *Temporary, 1);
- if (!Invert)
- return std::unexpected(Invert.error());
- return {};
+ const auto BuildImmediate = [&](InstructionOpcode OpcodeValue, Register Def, Register Source,
+ std::int64_t Immediate) -> Expected<MachineInstr *> {
+ auto Point = Builder.setInsertPointBefore(Instruction);
+ if (!Point)
+ return std::unexpected(Point.error());
+ auto Registers = constrainBuilderRegisters(Function, Target, {Def, Source});
+ if (!Registers)
+ return std::unexpected(Registers.error());
+ auto Pending = Builder.buildInstr(instructionOpcode(OpcodeValue));
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ auto DefResult = Pending->addDef(Def);
+ if (!DefResult)
+ return std::unexpected(DefResult.error());
+ auto SourceResult = Pending->addUse(Source);
+ if (!SourceResult)
+ return std::unexpected(SourceResult.error());
+ auto ImmediateResult = Pending->addImmediate(Immediate);
+ if (!ImmediateResult)
+ return std::unexpected(ImmediateResult.error());
+ auto Built = Pending->build();
+ if (!Built)
+ return std::unexpected(Built.error());
+ auto Constraint = constrainSelectedInstruction(**Built, Function, Target);
+ if (!Constraint)
+ return std::unexpected(Constraint.error());
+ return *Built;
};
- const auto BuildSelfAnd = [&](bool Invert) -> Expected<void> {
- auto First = createTemporary(Function, *ResultType, Target);
- auto Second = createTemporary(Function, *ResultType, Target);
- if (!First || !Second)
- return std::unexpected((!First ? First.error() : Second.error()));
- auto Base = SetBase(EqualOpcode, *First, LeftRegister, LeftRegister);
- if (!Base)
- return std::unexpected(Base.error());
- MachineIRBuilder Builder(Function, Target);
- auto SecondInstruction = buildBinaryAfter(Builder, Instruction, EqualOpcode, *Second,
- RightRegister, RightRegister);
- if (!SecondInstruction)
- return std::unexpected(SecondInstruction.error());
- Register CombinedDestination = DestinationRegister;
- if (Invert) {
+
+ Register TemporaryResult = DestinationRegister;
+ bool NeedsInvert = false;
+ if (legalizeFloatingPredicate(LeftRegister, RightRegister, Condition, NeedsInvert)) {
+ if (NeedsInvert) {
auto Temporary = createTemporary(Function, *ResultType, Target);
if (!Temporary)
return std::unexpected(Temporary.error());
- CombinedDestination = *Temporary;
+ TemporaryResult = *Temporary;
}
- auto Combined = buildBinaryAfter(Builder, **SecondInstruction, InstructionOpcode::AND,
- CombinedDestination, *First, *Second);
- if (!Combined)
- return std::unexpected(Combined.error());
- if (!Invert)
- return {};
- auto Inverted = buildImmediateAfter(Builder, **Combined, InstructionOpcode::XORI,
- DestinationRegister, CombinedDestination, 1);
- if (!Inverted)
- return std::unexpected(Inverted.error());
- return {};
- };
- const auto BuildOrderedNotEqual = [&](bool Invert) -> Expected<void> {
+ auto OpcodeValue = floatingCompareOpcode(Condition, FloatType->scalarBitWidth());
+ if (!OpcodeValue)
+ return std::unexpected(OpcodeValue.error());
+ auto Comparison = BuildBinary(*OpcodeValue, TemporaryResult, LeftRegister, RightRegister);
+ if (!Comparison)
+ return std::unexpected(Comparison.error());
+ } else if (Condition == FloatingPredicate::OrderedNotEqual ||
+ Condition == FloatingPredicate::UnorderedEqual) {
+ NeedsInvert = Condition == FloatingPredicate::UnorderedEqual;
auto First = createTemporary(Function, *ResultType, Target);
auto Second = createTemporary(Function, *ResultType, Target);
if (!First || !Second)
return std::unexpected((!First ? First.error() : Second.error()));
- auto Base = SetBase(LessOpcode, *First, LeftRegister, RightRegister);
- if (!Base)
- return std::unexpected(Base.error());
- MachineIRBuilder Builder(Function, Target);
- auto SecondInstruction =
- buildBinaryAfter(Builder, Instruction, LessOpcode, *Second, RightRegister, LeftRegister);
- if (!SecondInstruction)
- return std::unexpected(SecondInstruction.error());
- Register CombinedDestination = DestinationRegister;
- if (Invert) {
+ auto LessOpcode =
+ floatingCompareOpcode(FloatingPredicate::OrderedLessThan, FloatType->scalarBitWidth());
+ if (!LessOpcode)
+ return std::unexpected(LessOpcode.error());
+ auto FirstComparison = BuildBinary(*LessOpcode, *First, LeftRegister, RightRegister);
+ if (!FirstComparison)
+ return std::unexpected(FirstComparison.error());
+ auto SecondComparison = BuildBinary(*LessOpcode, *Second, RightRegister, LeftRegister);
+ if (!SecondComparison)
+ return std::unexpected(SecondComparison.error());
+ if (NeedsInvert) {
auto Temporary = createTemporary(Function, *ResultType, Target);
if (!Temporary)
return std::unexpected(Temporary.error());
- CombinedDestination = *Temporary;
+ TemporaryResult = *Temporary;
}
- auto Combined = buildBinaryAfter(Builder, **SecondInstruction, InstructionOpcode::OR,
- CombinedDestination, *First, *Second);
+ auto Combined = BuildBinary(InstructionOpcode::OR, TemporaryResult, *First, *Second);
if (!Combined)
return std::unexpected(Combined.error());
- if (!Invert)
- return {};
- auto Inverted = buildImmediateAfter(Builder, **Combined, InstructionOpcode::XORI,
- DestinationRegister, CombinedDestination, 1);
+ } else if (Condition == FloatingPredicate::Ordered ||
+ Condition == FloatingPredicate::Unordered) {
+ NeedsInvert = Condition == FloatingPredicate::Unordered;
+ auto EqualOpcode =
+ floatingCompareOpcode(FloatingPredicate::OrderedEqual, FloatType->scalarBitWidth());
+ if (!EqualOpcode)
+ return std::unexpected(EqualOpcode.error());
+ if (NeedsInvert) {
+ auto Temporary = createTemporary(Function, *ResultType, Target);
+ if (!Temporary)
+ return std::unexpected(Temporary.error());
+ TemporaryResult = *Temporary;
+ }
+ if (LeftRegister == RightRegister) {
+ auto Comparison = BuildBinary(*EqualOpcode, TemporaryResult, LeftRegister, LeftRegister);
+ if (!Comparison)
+ return std::unexpected(Comparison.error());
+ } else {
+ auto First = createTemporary(Function, *ResultType, Target);
+ auto Second = createTemporary(Function, *ResultType, Target);
+ if (!First || !Second)
+ return std::unexpected((!First ? First.error() : Second.error()));
+ auto FirstComparison = BuildBinary(*EqualOpcode, *First, LeftRegister, LeftRegister);
+ if (!FirstComparison)
+ return std::unexpected(FirstComparison.error());
+ auto SecondComparison = BuildBinary(*EqualOpcode, *Second, RightRegister, RightRegister);
+ if (!SecondComparison)
+ return std::unexpected(SecondComparison.error());
+ auto Combined = BuildBinary(InstructionOpcode::AND, TemporaryResult, *First, *Second);
+ if (!Combined)
+ return std::unexpected(Combined.error());
+ }
+ } else {
+ return makeUnexpected(ErrorCode::Unsupported,
+ "RISC-V floating comparison predicate has no LLVM selection");
+ }
+
+ if (NeedsInvert) {
+ auto Inverted =
+ BuildImmediate(InstructionOpcode::XORI, DestinationRegister, TemporaryResult, 1);
if (!Inverted)
return std::unexpected(Inverted.error());
- return {};
- };
-
- switch (Condition) {
- case FloatingPredicate::AlwaysFalse:
- case FloatingPredicate::AlwaysTrue: {
- auto EraseRight = Instruction.eraseOperand(2);
- if (!EraseRight)
- return std::unexpected(EraseRight.error());
- auto EraseLeft = Instruction.eraseOperand(1);
- if (!EraseLeft)
- return std::unexpected(EraseLeft.error());
- auto Zero = physicalRegister(PhysicalRegisterID::X0);
- if (!Zero)
- return std::unexpected(Zero.error());
- auto InsertZero = insertPhysicalRegister(Instruction, 1, *Zero, RegisterOperandFlag::Use);
- if (!InsertZero)
- return std::unexpected(InsertZero.error());
- auto Immediate =
- appendImmediate(Instruction, Condition == FloatingPredicate::AlwaysTrue ? 1 : 0);
- if (!Immediate)
- return std::unexpected(Immediate.error());
- return Instruction.setOpcode(instructionOpcode(InstructionOpcode::ADDI));
- }
- case FloatingPredicate::OrderedEqual:
- return SetBase(EqualOpcode, DestinationRegister, LeftRegister, RightRegister);
- case FloatingPredicate::OrderedGreaterThan:
- return SetBase(LessOpcode, DestinationRegister, RightRegister, LeftRegister);
- case FloatingPredicate::OrderedGreaterEqual:
- return SetBase(LessEqualOpcode, DestinationRegister, RightRegister, LeftRegister);
- case FloatingPredicate::OrderedLessThan:
- return SetBase(LessOpcode, DestinationRegister, LeftRegister, RightRegister);
- case FloatingPredicate::OrderedLessEqual:
- return SetBase(LessEqualOpcode, DestinationRegister, LeftRegister, RightRegister);
- case FloatingPredicate::OrderedNotEqual:
- return BuildOrderedNotEqual(false);
- case FloatingPredicate::Ordered:
- return BuildSelfAnd(false);
- case FloatingPredicate::Unordered:
- return BuildSelfAnd(true);
- case FloatingPredicate::UnorderedEqual:
- return BuildOrderedNotEqual(true);
- case FloatingPredicate::UnorderedGreaterThan:
- return BuildInverted(LessEqualOpcode, LeftRegister, RightRegister);
- case FloatingPredicate::UnorderedGreaterEqual:
- return BuildInverted(LessOpcode, LeftRegister, RightRegister);
- case FloatingPredicate::UnorderedLessThan:
- return BuildInverted(LessEqualOpcode, RightRegister, LeftRegister);
- case FloatingPredicate::UnorderedLessEqual:
- return BuildInverted(LessOpcode, RightRegister, LeftRegister);
- case FloatingPredicate::UnorderedNotEqual:
- return BuildInverted(EqualOpcode, LeftRegister, RightRegister);
- case FloatingPredicate::Count:
- return makeUnexpected(ErrorCode::Unsupported,
- "RISC-V floating comparison predicate is invalid");
}
- return makeUnexpected(ErrorCode::Unsupported,
- "RISC-V floating comparison predicate is invalid");
+ MachineBasicBlock *Block = Instruction.parent();
+ if (Block == nullptr)
+ return makeUnexpected(ErrorCode::InternalError,
+ "RISC-V floating comparison is detached from its block");
+ return Block->removeInstruction(Instruction);
}
[[nodiscard]] Expected<void> selectFence(MachineInstr &Instruction) const {
diff --git a/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc b/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc
index 18046b5..a5d9107 100644
--- a/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc
+++ b/backend/lib/Target/RISCV/RISCVGISelFloating.rccdesc
@@ -1,5 +1,119 @@
selection_rules:
-
+ id: select_g_fcmp_oeq_s32
+ priority: 100
+ match:
+ opcode: G_FCMP
+ result_type: { kind: scalar, bits: 64 }
+ floating_predicate: { index: 1, value: oeq }
+ operand_types:
+ - { index: 2, kind: scalar, bits: 32 }
+ - { index: 3, kind: scalar, bits: 32 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 2, bank: FPR }
+ - { index: 3, bank: FPR }
+ apply:
+ instructions:
+ - opcode: FEQ_S
+ root: true
+ operands: [{ operand: 0 }, { operand: 2 }, { operand: 3 }]
+ -
+ id: select_g_fcmp_olt_s32
+ priority: 100
+ match:
+ opcode: G_FCMP
+ result_type: { kind: scalar, bits: 64 }
+ floating_predicate: { index: 1, value: olt }
+ operand_types:
+ - { index: 2, kind: scalar, bits: 32 }
+ - { index: 3, kind: scalar, bits: 32 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 2, bank: FPR }
+ - { index: 3, bank: FPR }
+ apply:
+ instructions:
+ - opcode: FLT_S
+ root: true
+ operands: [{ operand: 0 }, { operand: 2 }, { operand: 3 }]
+ -
+ id: select_g_fcmp_ole_s32
+ priority: 100
+ match:
+ opcode: G_FCMP
+ result_type: { kind: scalar, bits: 64 }
+ floating_predicate: { index: 1, value: ole }
+ operand_types:
+ - { index: 2, kind: scalar, bits: 32 }
+ - { index: 3, kind: scalar, bits: 32 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 2, bank: FPR }
+ - { index: 3, bank: FPR }
+ apply:
+ instructions:
+ - opcode: FLE_S
+ root: true
+ operands: [{ operand: 0 }, { operand: 2 }, { operand: 3 }]
+ -
+ id: select_g_fcmp_oeq_s64
+ priority: 100
+ match:
+ opcode: G_FCMP
+ result_type: { kind: scalar, bits: 64 }
+ floating_predicate: { index: 1, value: oeq }
+ operand_types:
+ - { index: 2, kind: scalar, bits: 64 }
+ - { index: 3, kind: scalar, bits: 64 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 2, bank: FPR }
+ - { index: 3, bank: FPR }
+ apply:
+ instructions:
+ - opcode: FEQ_D
+ root: true
+ operands: [{ operand: 0 }, { operand: 2 }, { operand: 3 }]
+ -
+ id: select_g_fcmp_olt_s64
+ priority: 100
+ match:
+ opcode: G_FCMP
+ result_type: { kind: scalar, bits: 64 }
+ floating_predicate: { index: 1, value: olt }
+ operand_types:
+ - { index: 2, kind: scalar, bits: 64 }
+ - { index: 3, kind: scalar, bits: 64 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 2, bank: FPR }
+ - { index: 3, bank: FPR }
+ apply:
+ instructions:
+ - opcode: FLT_D
+ root: true
+ operands: [{ operand: 0 }, { operand: 2 }, { operand: 3 }]
+ -
+ id: select_g_fcmp_ole_s64
+ priority: 100
+ match:
+ opcode: G_FCMP
+ result_type: { kind: scalar, bits: 64 }
+ floating_predicate: { index: 1, value: ole }
+ operand_types:
+ - { index: 2, kind: scalar, bits: 64 }
+ - { index: 3, kind: scalar, bits: 64 }
+ operand_banks:
+ - { index: 0, bank: GPR }
+ - { index: 2, bank: FPR }
+ - { index: 3, bank: FPR }
+ apply:
+ instructions:
+ - opcode: FLE_D
+ root: true
+ operands: [{ operand: 0 }, { operand: 2 }, { operand: 3 }]
+ -
id: select_g_fadd_s32
priority: 100
match: