From 2d05768bedb7f4209038330bebab270a7f1b558d Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sun, 16 Aug 2026 18:26:43 +0800 Subject: [RISCV][GlobalISel] Generate integer arithmetic selections --- .../RISCV/GISel/RISCVInstructionSelector.cpp | 115 +-------- backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc | 260 +++++++++++++++++++++ 2 files changed, 264 insertions(+), 111 deletions(-) (limited to 'backend/lib/Target/RISCV') diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 08e9f6c..c3f2a17 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -190,19 +190,13 @@ public: const auto Integer = [Type] { return Type && isSupportedIntegerType(*Type); }; const auto Float = [Type] { return Type && isSupportedFloatingScalar(*Type); }; switch (Generic) { - case GenericOpcode::G_ADD: - case GenericOpcode::G_SUB: - case GenericOpcode::G_MUL: - case GenericOpcode::G_SDIV: - case GenericOpcode::G_UDIV: - case GenericOpcode::G_SREM: - case GenericOpcode::G_UREM: - case GenericOpcode::G_AND: - case GenericOpcode::G_OR: - case GenericOpcode::G_XOR: case GenericOpcode::G_SHL: case GenericOpcode::G_LSHR: case GenericOpcode::G_ASHR: + if (!Integer()) + return makeUnexpected(ErrorCode::Unsupported, + "RISC-V selector requires an i1-i64 integer or 64-bit pointer value"); + return {}; case GenericOpcode::G_CONSTANT: if (!Integer()) return makeUnexpected(ErrorCode::Unsupported, @@ -251,8 +245,6 @@ public: case GenericOpcode::G_SEXT_INREG: case GenericOpcode::G_ZEXT: case GenericOpcode::G_FCMP: - case GenericOpcode::G_SDIVREM: - case GenericOpcode::G_UDIVREM: case GenericOpcode::G_SMULH: case GenericOpcode::G_UMULH: case GenericOpcode::G_SMIN: @@ -310,48 +302,6 @@ public: const std::optional Type = resultType(Function, Instruction); switch (Generic) { - case GenericOpcode::G_ADD: - return selectIntegerBinary(Instruction, Function, Type, InstructionOpcode::ADD, - InstructionOpcode::ADDW, InstructionOpcode::ADDI, - InstructionOpcode::ADDIW, true, 12, 12); - case GenericOpcode::G_SUB: - return selectIntegerBinary(Instruction, Type, InstructionOpcode::SUB, - InstructionOpcode::SUBW); - case GenericOpcode::G_MUL: - return selectIntegerBinary(Instruction, Type, InstructionOpcode::MUL, - InstructionOpcode::MULW); - case GenericOpcode::G_SDIV: - return selectNormalizedIntegerBinary(Instruction, Function, Target, Type, - InstructionOpcode::DIV, InstructionOpcode::DIVW, true, - true); - case GenericOpcode::G_UDIV: - return selectNormalizedIntegerBinary(Instruction, Function, Target, Type, - InstructionOpcode::DIVU, InstructionOpcode::DIVUW, false, - true); - case GenericOpcode::G_SREM: - return selectNormalizedIntegerBinary(Instruction, Function, Target, Type, - InstructionOpcode::REM, InstructionOpcode::REMW, true, - true); - case GenericOpcode::G_UREM: - return selectNormalizedIntegerBinary(Instruction, Function, Target, Type, - InstructionOpcode::REMU, InstructionOpcode::REMUW, false, - true); - case GenericOpcode::G_SDIVREM: - return selectDivRem(Instruction, Function, Target, Type, true); - case GenericOpcode::G_UDIVREM: - return selectDivRem(Instruction, Function, Target, Type, false); - case GenericOpcode::G_AND: - return selectIntegerBinary(Instruction, Function, Type, InstructionOpcode::AND, - InstructionOpcode::AND, InstructionOpcode::ANDI, - InstructionOpcode::ANDI, true, 12, 12); - case GenericOpcode::G_OR: - return selectIntegerBinary(Instruction, Function, Type, InstructionOpcode::OR, - InstructionOpcode::OR, InstructionOpcode::ORI, - InstructionOpcode::ORI, true, 12, 12); - case GenericOpcode::G_XOR: - return selectIntegerBinary(Instruction, Function, Type, InstructionOpcode::XOR, - InstructionOpcode::XOR, InstructionOpcode::XORI, - InstructionOpcode::XORI, true, 12, 12); case GenericOpcode::G_SHL: return selectIntegerBinary(Instruction, Function, Type, InstructionOpcode::SLL, InstructionOpcode::SLLW, InstructionOpcode::SLLI, @@ -777,52 +727,6 @@ private: FalseValue, *MaskedDifference); } - [[nodiscard]] Expected selectDivRem(MachineInstr &Instruction, MachineFunction &Function, - const TargetDescription &Target, - std::optional Type, bool Signed) const { - const MachineOperand *RemainderOperand = Instruction.operandAt(1); - const MachineOperand *LeftOperand = Instruction.operandAt(2); - const MachineOperand *RightOperand = Instruction.operandAt(3); - const Register *Remainder = - RemainderOperand == nullptr ? nullptr : RemainderOperand->getIf(); - const Register *Left = LeftOperand == nullptr ? nullptr : LeftOperand->getIf(); - const Register *Right = RightOperand == nullptr ? nullptr : RightOperand->getIf(); - if (!Type || Remainder == nullptr || Left == nullptr || Right == nullptr) - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V division-with-remainder has invalid operands"); - const Register RemainderRegister = *Remainder; - auto LeftRegister = normalizeIntegerBefore(Instruction, Function, Target, *Left, *Type, Signed); - auto RightRegister = - normalizeIntegerBefore(Instruction, Function, Target, *Right, *Type, Signed); - if (!LeftRegister || !RightRegister) - return std::unexpected(!LeftRegister ? LeftRegister.error() : RightRegister.error()); - auto RemoveRemainder = Instruction.eraseOperand(1); - if (!RemoveRemainder) - return std::unexpected(RemoveRemainder.error()); - auto SetLeft = Instruction.operandAt(1)->setRegister(*LeftRegister); - if (!SetLeft) - return std::unexpected(SetLeft.error()); - auto SetRight = Instruction.operandAt(2)->setRegister(*RightRegister); - if (!SetRight) - return std::unexpected(SetRight.error()); - const bool IsWord = Type->scalarBitWidth() <= 32; - const InstructionOpcode Division = - IsWord ? (Signed ? InstructionOpcode::DIVW : InstructionOpcode::DIVUW) - : (Signed ? InstructionOpcode::DIV : InstructionOpcode::DIVU); - const InstructionOpcode RemainderOpcode = - IsWord ? (Signed ? InstructionOpcode::REMW : InstructionOpcode::REMUW) - : (Signed ? InstructionOpcode::REM : InstructionOpcode::REMU); - auto SetDivision = Instruction.setOpcode(instructionOpcode(Division)); - if (!SetDivision) - return std::unexpected(SetDivision.error()); - MachineIRBuilder Builder(Function, Target); - auto BuiltRemainder = buildBinaryAfter(Builder, Instruction, RemainderOpcode, RemainderRegister, - *LeftRegister, *RightRegister); - if (!BuiltRemainder) - return std::unexpected(BuiltRemainder.error()); - return {}; - } - [[nodiscard]] Expected selectMultiplyHigh(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, @@ -1941,17 +1845,6 @@ private: return Instruction.setOpcode(instructionOpcode(InstructionOpcode::EBREAK)); } - [[nodiscard]] Expected selectIntegerBinary(MachineInstr &Instruction, - 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->isCategoryNeutralScalar() && Type->scalarBitWidth() <= 32; - return Instruction.setOpcode(instructionOpcode(IsWord ? Word : DoubleWord)); - } - [[nodiscard]] Expected foldRightConstantToImmediate(MachineInstr &Instruction, const MachineFunction &Function, bool Signed, diff --git a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc index 9e32842..0413007 100644 --- a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc +++ b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc @@ -83,6 +83,266 @@ selection_rules: - opcode: AND root: true operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_add_immediate + priority: 400 + match: + opcode: G_ADD + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + operand_def_constants: + - index: 2 + ranges: [{ min: -2048, max: 2047 }] + apply: + instructions: + - opcode: ADDI + root: true + operands: [{ operand: 0 }, { operand: 1 }, { captured_immediate: 2 }] + erase_operand_definitions: [2] + - + id: select_g_and_immediate + priority: 400 + match: + opcode: G_AND + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + operand_def_constants: + - index: 2 + ranges: [{ min: -2048, max: 2047 }] + apply: + instructions: + - opcode: ANDI + root: true + operands: [{ operand: 0 }, { operand: 1 }, { captured_immediate: 2 }] + erase_operand_definitions: [2] + - + id: select_g_or_immediate + priority: 400 + match: + opcode: G_OR + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + operand_def_constants: + - index: 2 + ranges: [{ min: -2048, max: 2047 }] + apply: + instructions: + - opcode: ORI + root: true + operands: [{ operand: 0 }, { operand: 1 }, { captured_immediate: 2 }] + erase_operand_definitions: [2] + - + id: select_g_xor_immediate + priority: 400 + match: + opcode: G_XOR + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + operand_def_constants: + - index: 2 + ranges: [{ min: -2048, max: 2047 }] + apply: + instructions: + - opcode: XORI + root: true + operands: [{ operand: 0 }, { operand: 1 }, { captured_immediate: 2 }] + erase_operand_definitions: [2] + - + id: select_g_add_register + priority: 100 + match: + opcode: G_ADD + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: ADD + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_sub_register + priority: 100 + match: + opcode: G_SUB + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: SUB + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_mul_register + priority: 100 + match: + opcode: G_MUL + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: MUL + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_sdiv_register + priority: 100 + match: + opcode: G_SDIV + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: DIV + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_udiv_register + priority: 100 + match: + opcode: G_UDIV + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: DIVU + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_srem_register + priority: 100 + match: + opcode: G_SREM + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: REM + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_urem_register + priority: 100 + match: + opcode: G_UREM + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: REMU + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_and_register + priority: 100 + match: + opcode: G_AND + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: AND + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_or_register + priority: 100 + match: + opcode: G_OR + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: OR + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] + - + id: select_g_xor_register + priority: 100 + match: + opcode: G_XOR + result_type: { kind: scalar, bits: 64 } + operand_types: + - { index: 1, kind: scalar, bits: 64 } + - { index: 2, kind: scalar, bits: 64 } + operand_banks: + - { index: 0, bank: GPR } + - { index: 1, bank: GPR } + - { index: 2, bank: GPR } + apply: + instructions: + - opcode: XOR + root: true + operands: [{ operand: 0 }, { operand: 1 }, { operand: 2 }] - id: select_g_sllw priority: 100 -- cgit v1.2.3