From f5c592905e6e1ef4b78337d76c8215e543607b8d Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Mon, 17 Aug 2026 03:16:26 +0800 Subject: [RISCV][GlobalISel] Generate conditional branch selection --- .../CodeGen/GlobalISel/GIMatchTableExecutor.cpp | 32 ++- backend/lib/TableGen/Parser.cpp | 23 +- backend/lib/Target/RISCV/CMakeLists.txt | 1 + .../RISCV/GISel/RISCVInstructionSelector.cpp | 13 -- .../lib/Target/RISCV/RISCVGISelControlFlow.rccdesc | 252 +++++++++++++++++++++ backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc | 10 - 6 files changed, 296 insertions(+), 35 deletions(-) create mode 100644 backend/lib/Target/RISCV/RISCVGISelControlFlow.rccdesc (limited to 'backend/lib') diff --git a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp index 739f12b..d4f73f6 100644 --- a/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp +++ b/backend/lib/CodeGen/GlobalISel/GIMatchTableExecutor.cpp @@ -94,15 +94,16 @@ namespace { } [[nodiscard]] Expected matchesIntegerPredicate(const MachineInstr &Instruction, - const GIMatchTableInstruction &Step) { - if (Step.Value >= static_cast(IntegerPredicate::Count)) { + std::size_t OperandIndex, + std::uint32_t PredicateValue) { + if (PredicateValue >= static_cast(IntegerPredicate::Count)) { return makeUnexpected(ErrorCode::VerificationError, "generated match table has an invalid integer predicate"); } - const MachineOperand *Operand = Instruction.operandAt(Step.OperandIndex); + const MachineOperand *Operand = Instruction.operandAt(OperandIndex); const auto *Predicate = Operand == nullptr ? nullptr : Operand->getIf(); const IntegerPredicate *Integer = Predicate == nullptr ? nullptr : Predicate->integerPredicate(); - return Integer != nullptr && static_cast(*Integer) == Step.Value; + return Integer != nullptr && static_cast(*Integer) == PredicateValue; } [[nodiscard]] std::optional immediateValue(const MachineOperand &Operand) { @@ -205,6 +206,15 @@ operandOrDefConstantValue(const MachineInstr &Instruction, const MachineFunction return Definition != nullptr && Definition->opcode().value() == Step.Value; } +[[nodiscard]] Expected +matchesOperandDefIntegerPredicate(const MachineInstr &Instruction, const MachineFunction &Function, + const GIMatchTableInstruction &Step) { + const MachineInstr *Definition = operandDefinition(Instruction, Function, Step.OperandIndex); + if (Definition == nullptr) + return false; + return matchesIntegerPredicate(*Definition, Step.Auxiliary, Step.Value); +} + [[nodiscard]] Expected matchesOperandDefOperandConstantRanges(const GIMatchTable &Table, const MachineInstr &Instruction, const MachineFunction &Function, @@ -367,7 +377,7 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine return makeUnexpected(ErrorCode::VerificationError, "generated match table performs a predicate after an action"); } - auto Matched = matchesIntegerPredicate(Instruction, Step); + auto Matched = matchesIntegerPredicate(Instruction, Step.OperandIndex, Step.Value); if (!Matched) return std::unexpected(Matched.error()); if (!*Matched) @@ -422,6 +432,18 @@ matchRule(const GIMatchTable &Table, const GIMatchTableRule &Rule, const Machine return std::optional{}; break; } + case GIMatchTableOpcode::CheckOperandDefIntegerPredicate: { + if (Applying) { + return makeUnexpected(ErrorCode::VerificationError, + "generated match table performs a predicate after an action"); + } + auto Matched = matchesOperandDefIntegerPredicate(Instruction, Function, Step); + if (!Matched) + return std::unexpected(Matched.error()); + if (!*Matched) + return std::optional{}; + break; + } case GIMatchTableOpcode::CheckOperandDefOperandConstantRanges: { if (Applying) { return makeUnexpected(ErrorCode::VerificationError, diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp index 7c6a8de..1a2af30 100644 --- a/backend/lib/TableGen/Parser.cpp +++ b/backend/lib/TableGen/Parser.cpp @@ -1152,8 +1152,9 @@ private: return true; } - [[nodiscard]] bool parseSelectionIntegerPredicate(const yaml::Node &Node, - SourceSelectionRule &Result) { + [[nodiscard]] bool + parseSelectionIntegerPredicate(const yaml::Node &Node, + std::optional &Result) { if (!requireMapping(&Node, "selection integer predicate") || !checkKeys(Node, {"index", "value"}, "selection integer predicate")) { return false; @@ -1165,7 +1166,7 @@ private: const auto Index = unsignedInteger32(*IndexNode, "selection integer predicate index"); if (!Index) return false; - Result.IntegerPredicate = SourceSelectionIntegerPredicate{ + Result = SourceSelectionIntegerPredicate{ .OperandIndex = *Index, .Predicate = *Value, .Range = Node.range(), @@ -1303,8 +1304,10 @@ private: for (const yaml::NodeID ElementID : Node.sequence()) { const yaml::Node *Element = Input.node(ElementID); if (!requireMapping(Element, "selection def-use predicate") || - !checkKeys(*Element, {"operand", "opcode", "captures", "operand_def_constants"}, - "selection def-use predicate")) { + !checkKeys( + *Element, + {"operand", "opcode", "integer_predicate", "captures", "operand_def_constants"}, + "selection def-use predicate")) { return false; } const yaml::Node *OperandNode = @@ -1319,10 +1322,15 @@ private: SourceSelectionDefUsePredicate Predicate{ .RootOperandIndex = *Operand, .OpcodeSymbol = *Opcode, + .IntegerPredicate = std::nullopt, .Captures = {}, .OperandDefConstants = {}, .Range = Element->range(), }; + if (const yaml::Node *IntegerPredicate = optionalNode(*Element, "integer_predicate")) { + if (!parseSelectionIntegerPredicate(*IntegerPredicate, Predicate.IntegerPredicate)) + return false; + } if (const yaml::Node *Captures = optionalNode(*Element, "captures")) { if (!requireSequence(Captures, "selection def-use captures")) return false; @@ -1352,7 +1360,8 @@ private: if (!parseSelectionOperandDefConstants(*Constants, Predicate.OperandDefConstants)) return false; } - if (Predicate.Captures.empty() && Predicate.OperandDefConstants.empty()) { + if (!Predicate.IntegerPredicate && Predicate.Captures.empty() && + Predicate.OperandDefConstants.empty()) { fail(Element->range(), "selection def-use predicate requires a capture or constant predicate"); return false; @@ -1553,7 +1562,7 @@ private: Result.ResultType = std::move(*Parsed); } if (const yaml::Node *Predicate = optionalNode(Node, "integer_predicate")) { - if (!parseSelectionIntegerPredicate(*Predicate, Result)) + if (!parseSelectionIntegerPredicate(*Predicate, Result.IntegerPredicate)) return false; } if (const yaml::Node *TargetPredicates = optionalNode(Node, "target_predicates")) { diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index f9eb79f..48f3263 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -15,6 +15,7 @@ set( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVInstrInfoZb.rccdesc" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVInstrInfoPseudo.rccdesc" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelInteger.rccdesc" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelControlFlow.rccdesc" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelShift.rccdesc" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelFloating.rccdesc" ) diff --git a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 89b6ecd..1e2eb92 100644 --- a/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/backend/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -364,7 +364,6 @@ public: case GenericOpcode::G_FPEXTLOAD: case GenericOpcode::G_FPTRUNCSTORE: case GenericOpcode::G_STORE: - case GenericOpcode::G_BRCOND: return {}; case GenericOpcode::G_FCONSTANT: { const MachineOperand *Immediate = Instruction.operandAt(1); @@ -440,8 +439,6 @@ public: return selectStore(Instruction, Function); case GenericOpcode::G_FPTRUNCSTORE: return selectFloatTruncStore(Instruction, Function, Target); - case GenericOpcode::G_BRCOND: - return selectConditionalBranch(Instruction); case GenericOpcode::G_CONSTANT: return selectIntegerConstant(Instruction, Function, Target, Type); case GenericOpcode::G_FCONSTANT: @@ -1422,16 +1419,6 @@ private: return makeUnexpected(ErrorCode::Unsupported, "RISC-V cannot select this generic store type"); } - [[nodiscard]] Expected selectConditionalBranch(MachineInstr &Instruction) const { - auto Zero = physicalRegister(PhysicalRegisterID::X0); - if (!Zero) - return std::unexpected(Zero.error()); - auto Inserted = insertPhysicalRegister(Instruction, 1, *Zero, RegisterOperandFlag::Use); - if (!Inserted) - return std::unexpected(Inserted.error()); - return Instruction.setOpcode(instructionOpcode(InstructionOpcode::BNE)); - } - [[nodiscard]] Expected selectIntegerConstant(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, diff --git a/backend/lib/Target/RISCV/RISCVGISelControlFlow.rccdesc b/backend/lib/Target/RISCV/RISCVGISelControlFlow.rccdesc new file mode 100644 index 0000000..c58135f --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVGISelControlFlow.rccdesc @@ -0,0 +1,252 @@ +# SPDX-License-Identifier: GPL-3.0-or-later + +selection_rules: + - + id: select_g_br + priority: 100 + match: + opcode: G_BR + apply: + instructions: + - opcode: PseudoBR + root: true + operands: [{ operand: 0 }] + - + id: select_g_brcond_sgt_minus_one + priority: 600 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: sgt } + captures: + - { id: lhs, operand: 2 } + operand_def_constants: + - index: 3 + ranges: [{ min: -1, max: -1 }] + apply: + instructions: + - opcode: BGE + root: true + operands: + - { captured_operand: lhs } + - { physical_register: X0, flags: [use] } + - { operand: 1 } + erase_operand_definitions: [0] + - + id: select_g_brcond_slt_one + priority: 600 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: slt } + captures: + - { id: lhs, operand: 2 } + operand_def_constants: + - index: 3 + ranges: [{ min: 1, max: 1 }] + apply: + instructions: + - opcode: BGE + root: true + operands: + - { physical_register: X0, flags: [use] } + - { captured_operand: lhs } + - { operand: 1 } + erase_operand_definitions: [0] + - + id: select_g_brcond_eq + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: eq } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BEQ + root: true + operands: [{ captured_operand: lhs }, { captured_operand: rhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_ne + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: ne } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BNE + root: true + operands: [{ captured_operand: lhs }, { captured_operand: rhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_slt + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: slt } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BLT + root: true + operands: [{ captured_operand: lhs }, { captured_operand: rhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_sge + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: sge } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BGE + root: true + operands: [{ captured_operand: lhs }, { captured_operand: rhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_ult + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: ult } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BLTU + root: true + operands: [{ captured_operand: lhs }, { captured_operand: rhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_uge + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: uge } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BGEU + root: true + operands: [{ captured_operand: lhs }, { captured_operand: rhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_sgt + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: sgt } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BLT + root: true + operands: [{ captured_operand: rhs }, { captured_operand: lhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_sle + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: sle } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BGE + root: true + operands: [{ captured_operand: rhs }, { captured_operand: lhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_ugt + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: ugt } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BLTU + root: true + operands: [{ captured_operand: rhs }, { captured_operand: lhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond_ule + priority: 400 + match: + opcode: G_BRCOND + def_use: + - operand: 0 + opcode: G_ICMP + integer_predicate: { index: 1, value: ule } + captures: + - { id: lhs, operand: 2 } + - { id: rhs, operand: 3 } + apply: + instructions: + - opcode: BGEU + root: true + operands: [{ captured_operand: rhs }, { captured_operand: lhs }, { operand: 1 }] + erase_operand_definitions: [0] + - + id: select_g_brcond + priority: 100 + match: + opcode: G_BRCOND + apply: + instructions: + - opcode: BNE + root: true + operands: + - { operand: 0 } + - { physical_register: X0, flags: [use] } + - { operand: 1 } diff --git a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc index 6ba88ef..f40e5d4 100644 --- a/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc +++ b/backend/lib/Target/RISCV/RISCVGISelInteger.rccdesc @@ -1,14 +1,4 @@ selection_rules: - - - id: select_g_br - priority: 100 - match: - opcode: G_BR - apply: - instructions: - - opcode: PseudoBR - root: true - operands: [{ operand: 0 }] - id: select_g_implicit_def priority: 100 -- cgit v1.2.3