diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-22 19:16:18 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-22 19:16:18 +0800 |
| commit | 75f1223070749b0df3002226ebbb474c68c71f90 (patch) | |
| tree | e3b386180f6ea394381862d5ff9b5394ac0a6481 | |
| parent | 36b0be1ec1558f88d4f031a1817c3a4c2cba07a6 (diff) | |
| download | rcc-project-75f1223070749b0df3002226ebbb474c68c71f90.tar.gz rcc-project-75f1223070749b0df3002226ebbb474c68c71f90.tar.xz | |
[RISCV] Generate MC pseudo lowering
| -rw-r--r-- | backend/include/rcc/TableGen/Record.h | 15 | ||||
| -rw-r--r-- | backend/lib/TableGen/Parser.cpp | 69 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/CMakeLists.txt | 10 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc | 30 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc | 35 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp | 9 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp | 187 | ||||
| -rw-r--r-- | backend/utils/TableGen/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenInstruction.cpp | 9 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp | 121 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenTarget.cpp | 3 | ||||
| -rw-r--r-- | backend/utils/TableGen/Common/CodeGenTarget.h | 20 | ||||
| -rw-r--r-- | backend/utils/TableGen/MCPseudoLoweringEmitter.cpp | 69 | ||||
| -rw-r--r-- | backend/utils/TableGen/TableGenBackends.h | 3 | ||||
| -rw-r--r-- | backend/utils/TableGen/rcc-tblgen.cpp | 17 |
15 files changed, 392 insertions, 207 deletions
diff --git a/backend/include/rcc/TableGen/Record.h b/backend/include/rcc/TableGen/Record.h index 9ebfb7f..f3c7d12 100644 --- a/backend/include/rcc/TableGen/Record.h +++ b/backend/include/rcc/TableGen/Record.h @@ -189,6 +189,20 @@ struct SourceMacroFusionRule final { TextRange Range; }; +struct SourceMCPseudoOperand final { + std::optional<std::uint32_t> SourceOperandIndex; + std::string RegisterSymbol; + std::optional<std::int64_t> Immediate; + TextRange Range; +}; + +struct SourceMCPseudoExpansion final { + std::string PseudoOpcodeSymbol; + std::string ResultOpcodeSymbol; + std::vector<SourceMCPseudoOperand> Operands; + TextRange Range; +}; + struct SourceEncodingCategory final { std::uint32_t ID = 0; std::string Symbol; @@ -441,6 +455,7 @@ struct DescriptionAST final { std::vector<SourceSelectionRule> SelectionRules; std::vector<SourceCombinerRule> CombinerRules; std::vector<SourceMacroFusionRule> MacroFusionRules; + std::vector<SourceMCPseudoExpansion> MCPseudoExpansions; }; [[nodiscard]] std::string lowerASCII(std::string_view Value); diff --git a/backend/lib/TableGen/Parser.cpp b/backend/lib/TableGen/Parser.cpp index c383aed..67c7a43 100644 --- a/backend/lib/TableGen/Parser.cpp +++ b/backend/lib/TableGen/Parser.cpp @@ -41,7 +41,7 @@ public: "register_classes", "register_masks", "mir_operand_flags", "named_operands", "immediate_predicates", "scheduling_classes", "encoding_categories", "assembly_formats", "calling_conventions", "instructions", "selection_rules", - "combiner_rules", "macro_fusion_rules"}, + "combiner_rules", "macro_fusion_rules", "mc_pseudo_expansions"}, "target description root")) { return std::nullopt; } @@ -84,6 +84,7 @@ public: const yaml::Node *SelectionRulesNode = optionalNode(*Root, "selection_rules"); const yaml::Node *CombinerRulesNode = optionalNode(*Root, "combiner_rules"); const yaml::Node *MacroFusionRulesNode = optionalNode(*Root, "macro_fusion_rules"); + const yaml::Node *MCPseudoExpansionsNode = optionalNode(*Root, "mc_pseudo_expansions"); if (UnitsNode == nullptr || RegistersNode == nullptr || BanksNode == nullptr || ClassesNode == nullptr || MasksNode == nullptr || NamedOperandsNode == nullptr || ImmediatePredicatesNode == nullptr || SchedulingClassesNode == nullptr || @@ -108,7 +109,9 @@ public: (CombinerRulesNode != nullptr && !parseCombinerRules(*CombinerRulesNode, Result.CombinerRules)) || (MacroFusionRulesNode != nullptr && - !parseMacroFusionRules(*MacroFusionRulesNode, Result.MacroFusionRules))) { + !parseMacroFusionRules(*MacroFusionRulesNode, Result.MacroFusionRules)) || + (MCPseudoExpansionsNode != nullptr && + !parseMCPseudoExpansions(*MCPseudoExpansionsNode, Result.MCPseudoExpansions))) { return std::nullopt; } return Result; @@ -2099,6 +2102,68 @@ private: return true; } + [[nodiscard]] bool parseMCPseudoOperands(const yaml::Node &Node, + std::vector<SourceMCPseudoOperand> &Result) { + if (!requireSequence(&Node, "MC pseudo expansion operands")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "MC pseudo expansion operand") || + !checkKeys(*Element, {"operand", "register", "immediate"}, + "MC pseudo expansion operand")) { + return false; + } + SourceMCPseudoOperand Operand; + Operand.Range = Element->range(); + if (const yaml::Node *SourceNode = optionalNode(*Element, "operand")) { + const auto Source = unsignedInteger32(*SourceNode, "MC pseudo source operand"); + if (!Source) + return false; + Operand.SourceOperandIndex = *Source; + } + if (const yaml::Node *RegisterNode = optionalNode(*Element, "register")) { + const auto Register = scalar(*RegisterNode, "MC pseudo fixed register"); + if (!Register) + return false; + Operand.RegisterSymbol = *Register; + } + if (const yaml::Node *ImmediateNode = optionalNode(*Element, "immediate")) { + const auto Immediate = signedInteger(*ImmediateNode, "MC pseudo fixed immediate"); + if (!Immediate) + return false; + Operand.Immediate = *Immediate; + } + Result.push_back(std::move(Operand)); + } + return true; + } + + [[nodiscard]] bool parseMCPseudoExpansions(const yaml::Node &Node, + std::vector<SourceMCPseudoExpansion> &Result) { + if (!requireSequence(&Node, "mc_pseudo_expansions")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "MC pseudo expansion") || + !checkKeys(*Element, {"pseudo", "opcode", "operands"}, "MC pseudo expansion")) { + return false; + } + const auto Pseudo = requiredScalar(*Element, "pseudo", "MC pseudo expansion"); + const auto Opcode = requiredScalar(*Element, "opcode", "MC pseudo expansion"); + const yaml::Node *OperandsNode = requiredNode(*Element, "operands", "MC pseudo expansion"); + if (!Pseudo || !Opcode || OperandsNode == nullptr) + return false; + SourceMCPseudoExpansion Expansion; + Expansion.PseudoOpcodeSymbol = *Pseudo; + Expansion.ResultOpcodeSymbol = *Opcode; + Expansion.Range = Element->range(); + if (!parseMCPseudoOperands(*OperandsNode, Expansion.Operands)) + return false; + Result.push_back(std::move(Expansion)); + } + return true; + } + [[nodiscard]] bool parseInstructions(const yaml::Node &Node, std::vector<SourceInstruction> &Result) { if (!requireSequence(&Node, "instructions")) diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index 00de7bd..dccced9 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -21,6 +21,7 @@ set( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelFloating.rccdesc" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVGISelCombiner.rccdesc" "${CMAKE_CURRENT_SOURCE_DIR}/RISCVMacroFusion.rccdesc" + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVMCPseudoLowering.rccdesc" ) set(RCCBackendRISCVTableGenArguments) foreach(RCCBackendRISCVDescriptionSource IN LISTS RCCBackendRISCVDescriptionSources) @@ -50,6 +51,10 @@ set( RCCBackendRISCVGeneratedMacroFusion "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenMacroFusion.inc" ) +set( + RCCBackendRISCVGeneratedMCPseudoLowering + "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenMCPseudoLowering.inc" +) add_custom_command( OUTPUT @@ -59,6 +64,7 @@ add_custom_command( "${RCCBackendRISCVGeneratedGlobalISel}" "${RCCBackendRISCVGeneratedGlobalISelCombiner}" "${RCCBackendRISCVGeneratedMacroFusion}" + "${RCCBackendRISCVGeneratedMCPseudoLowering}" COMMAND "$<TARGET_FILE:RCCBackendTableGenTool>" ${RCCBackendRISCVTableGenArguments} @@ -68,6 +74,7 @@ add_custom_command( --global-isel "${RCCBackendRISCVGeneratedGlobalISel}" --global-isel-combiner "${RCCBackendRISCVGeneratedGlobalISelCombiner}" --macro-fusion "${RCCBackendRISCVGeneratedMacroFusion}" + --mc-pseudo-lowering "${RCCBackendRISCVGeneratedMCPseudoLowering}" DEPENDS RCCBackendTableGenTool ${RCCBackendRISCVDescriptionSources} COMMENT "Generating RCC RV64GC target tables" VERBATIM @@ -82,6 +89,7 @@ add_custom_target( "${RCCBackendRISCVGeneratedGlobalISel}" "${RCCBackendRISCVGeneratedGlobalISelCombiner}" "${RCCBackendRISCVGeneratedMacroFusion}" + "${RCCBackendRISCVGeneratedMCPseudoLowering}" ) set_source_files_properties( @@ -91,6 +99,7 @@ set_source_files_properties( "${RCCBackendRISCVGeneratedGlobalISel}" "${RCCBackendRISCVGeneratedGlobalISelCombiner}" "${RCCBackendRISCVGeneratedMacroFusion}" + "${RCCBackendRISCVGeneratedMCPseudoLowering}" PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE ) @@ -127,6 +136,7 @@ add_library( "${RCCBackendRISCVGeneratedGlobalISel}" "${RCCBackendRISCVGeneratedGlobalISelCombiner}" "${RCCBackendRISCVGeneratedMacroFusion}" + "${RCCBackendRISCVGeneratedMCPseudoLowering}" ) add_library(RCCBackend::RISCV ALIAS RCCBackendRISCV) add_dependencies(RCCBackendRISCV RCCBackendRISCVGeneratedTablesTarget) diff --git a/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc b/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc index 14bcf26..3e458df 100644 --- a/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc +++ b/backend/lib/Target/RISCV/RISCVInstrInfoPseudo.rccdesc @@ -227,9 +227,9 @@ instructions: - { kinds: [register], role: def, register_class: GPR, register_bank: GPR } num_explicit_defs: 1 implicit_uses: [{ register: FFLAGS }] - flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects] - owner: post_ra_expansion - deadline: post_ra_finalized + flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects, terminal_emission] + owner: asm_printer + deadline: emission - id: 1246 @@ -239,9 +239,9 @@ instructions: - { kinds: [register], role: use, register_class: GPR, register_bank: GPR } num_explicit_defs: 0 implicit_defs: [{ register: FFLAGS }] - flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects] - owner: post_ra_expansion - deadline: post_ra_finalized + flags: [pseudo, produces_code, allowed_pre_legalizer, has_side_effects, terminal_emission] + owner: asm_printer + deadline: emission - id: 1217 symbol: PseudoLOAD_STACK_ARG @@ -342,10 +342,10 @@ instructions: operands: [] num_explicit_defs: 0 allow_extra_implicit_operands: true - flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, return, barrier] + flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, return, barrier, terminal_emission] size: 4 - owner: post_ra_expansion - deadline: post_ra_finalized + owner: asm_printer + deadline: emission - id: 1225 @@ -404,10 +404,10 @@ instructions: operands: - { kinds: [basic_block], name: TARGET } num_explicit_defs: 0 - flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, barrier] + flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, barrier, terminal_emission] size: 4 - owner: post_ra_expansion - deadline: post_ra_finalized + owner: asm_printer + deadline: emission - id: 1267 symbol: PseudoLLA @@ -441,7 +441,7 @@ instructions: - { kinds: [register], role: use, register_class: GPRJALRNonX7, register_bank: GPR, name: RS1 } - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } num_explicit_defs: 0 - flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, indirect_branch, barrier] + flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, indirect_branch, barrier, terminal_emission] size: 4 - owner: post_ra_expansion - deadline: post_ra_finalized + owner: asm_printer + deadline: emission diff --git a/backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc b/backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc new file mode 100644 index 0000000..a505281 --- /dev/null +++ b/backend/lib/Target/RISCV/RISCVMCPseudoLowering.rccdesc @@ -0,0 +1,35 @@ +mc_pseudo_expansions: + - + pseudo: PseudoBR + opcode: JAL + operands: + - { register: X0 } + - { operand: 0 } + - + pseudo: PseudoBRIND + opcode: JALR + operands: + - { register: X0 } + - { operand: 0 } + - { operand: 1 } + - + pseudo: PseudoRET + opcode: JALR + operands: + - { register: X0 } + - { register: X1 } + - { immediate: 0 } + - + pseudo: ReadFFLAGS + opcode: CSRRS + operands: + - { operand: 0 } + - { immediate: 1 } + - { register: X0 } + - + pseudo: WriteFFLAGS + opcode: CSRRW + operands: + - { register: X0 } + - { immediate: 1 } + - { operand: 0 } diff --git a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp index 61cb587..85c06ad 100644 --- a/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp +++ b/backend/lib/Target/RISCV/RISCVMCTargetLowering.cpp @@ -240,6 +240,10 @@ constexpr std::uint32_t KnownTargetFlags = CallTargetFlag | PCRelativeHighTarget "RISC-V MC lowering encountered a non-encoding operand"); } +#define GET_MC_PSEUDO_LOWERING +#include "RISCVGenMCPseudoLowering.inc" +#undef GET_MC_PSEUDO_LOWERING + [[nodiscard]] const AssemblyFormatInfo *assemblyFormat(AssemblyFormatID ID) noexcept { const auto Formats = assemblyFormats(); const auto Position = std::ranges::find(Formats, ID, &AssemblyFormatInfo::ID); @@ -866,6 +870,11 @@ Expected<mc::MCInst> RISCVMCTargetLowering::lowerInstruction(const MachineInstr Expected<void> RISCVMCTargetLowering::emitTerminalInstruction(const MachineInstr &Instruction, MachineMCContext &Context, mc::MCStreamer &Streamer) const { + auto Pseudo = lowerGeneratedMCPseudo(Instruction, Context); + if (!Pseudo) + return std::unexpected(Pseudo.error()); + if (*Pseudo) + return Streamer.emitInstruction(**Pseudo); if (Instruction.opcode() != opcode(GenericOpcode::INLINEASM) && Instruction.opcode() != opcode(GenericOpcode::INLINEASM_BR)) { return TargetMCInstLowering::emitTerminalInstruction(Instruction, Context, Streamer); diff --git a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp index 257fa3a..19e52d9 100644 --- a/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp +++ b/backend/lib/Target/RISCV/RISCVPseudoExpansion.cpp @@ -243,7 +243,15 @@ copyRegisters(const MachineInstr &Instruction) { auto Def = Pending->addDef(Destination); if (!Def) return std::unexpected(Def.error()); - auto Use = Pending->addUse(Source); + RegisterOperandFlags SourceFlags; + const RegisterOperandFlags OriginalSourceFlags = Instruction.operandAt(1)->registerFlags(); + if (OriginalSourceFlags.has(RegisterOperandFlag::Kill)) + SourceFlags.set(RegisterOperandFlag::Kill); + if (*DestinationBank == GPR && *SourceBank == GPR && + OriginalSourceFlags.has(RegisterOperandFlag::Renamable)) { + SourceFlags.set(RegisterOperandFlag::Renamable); + } + auto Use = Pending->addUse(Source, SourceFlags); if (!Use) return std::unexpected(Use.error()); if (DuplicateSource) { @@ -440,53 +448,6 @@ copyRegisters(const MachineInstr &Instruction) { return {}; } -[[nodiscard]] Expected<bool> expandFFLAGSAccess(MachineInstr &Instruction, - MachineFunction &Function, - const TargetDescription &Target, bool IsRead) { - const MachineOperand *ValueOperand = Instruction.operandAt(0); - const Register *Value = ValueOperand == nullptr ? nullptr : ValueOperand->getIf<Register>(); - if (Value == nullptr || !Value->isPhysical()) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V FFLAGS pseudo retains a nonphysical value register"); - } - auto Zero = physicalRegister(PhysicalRegisterID::X0); - if (!Zero) - return std::unexpected(Zero.error()); - - MachineIRBuilder Builder(Function, Target); - auto Point = Builder.setInsertPointBefore(Instruction); - if (!Point) - return std::unexpected(Point.error()); - auto Pending = Builder.buildInstr( - instructionOpcode(IsRead ? InstructionOpcode::CSRRS : InstructionOpcode::CSRRW)); - if (!Pending) - return std::unexpected(Pending.error()); - Expected<void> Added = IsRead ? Pending->addOperand(ValueOperand->cloneDetached()) - : Pending->addDef(Register::fromPhysical(*Zero)); - if (!Added) - return std::unexpected(Added.error()); - Added = Pending->addImmediate(1); - if (!Added) - return std::unexpected(Added.error()); - Added = IsRead ? Pending->addUse(Register::fromPhysical(*Zero)) - : Pending->addOperand(ValueOperand->cloneDetached()); - if (!Added) - return std::unexpected(Added.error()); - auto Implicit = copyExtraImplicitOperands(Instruction, 1, *Pending, std::nullopt, std::nullopt); - if (!Implicit) - return std::unexpected(Implicit.error()); - auto Replacement = Pending->build(); - if (!Replacement) - return std::unexpected(Replacement.error()); - auto Decoration = copyCommonDecoration(Instruction, **Replacement, true, true, true); - if (!Decoration) - return std::unexpected(Decoration.error()); - auto Removed = removeOldInstruction(Instruction); - if (!Removed) - return std::unexpected(Removed.error()); - return true; -} - [[nodiscard]] Expected<bool> expandCall(MachineInstr &Instruction, MachineFunction &Function, const TargetDescription &Target, bool IsTail) { MachineBasicBlock *Block = Instruction.parent(); @@ -585,126 +546,6 @@ copyRegisters(const MachineInstr &Instruction) { return true; } -[[nodiscard]] Expected<bool> expandReturn(MachineInstr &Instruction, MachineFunction &Function, - const TargetDescription &Target) { - auto Zero = physicalRegister(PhysicalRegisterID::X0); - auto Link = physicalRegister(PhysicalRegisterID::X1); - if (!Zero || !Link) - return makeUnexpected(ErrorCode::InternalError, "RISC-V return registers are unavailable"); - MachineIRBuilder Builder(Function, Target); - auto Point = Builder.setInsertPointBefore(Instruction); - if (!Point) - return std::unexpected(Point.error()); - auto Pending = Builder.buildInstr(instructionOpcode(InstructionOpcode::JALR_RET)); - if (!Pending) - return std::unexpected(Pending.error()); - auto Def = Pending->addDef(Register::fromPhysical(*Zero)); - if (!Def) - return std::unexpected(Def.error()); - auto Use = Pending->addUse(Register::fromPhysical(*Link)); - if (!Use) - return std::unexpected(Use.error()); - auto Immediate = Pending->addImmediate(0); - if (!Immediate) - return std::unexpected(Immediate.error()); - auto Implicit = copyExtraImplicitOperands(Instruction, 0, *Pending, std::nullopt, *Link); - if (!Implicit) - return std::unexpected(Implicit.error()); - auto Replacement = Pending->build(); - if (!Replacement) - return std::unexpected(Replacement.error()); - auto Decoration = copyCommonDecoration(Instruction, **Replacement, true, true, true); - if (!Decoration) - return std::unexpected(Decoration.error()); - auto Removed = removeOldInstruction(Instruction); - if (!Removed) - return std::unexpected(Removed.error()); - return true; -} - -[[nodiscard]] Expected<bool> expandBranch(MachineInstr &Instruction, MachineFunction &Function, - const TargetDescription &Target) { - const MachineOperand *TargetOperand = Instruction.operandAt(0); - const BasicBlockOperand *TargetBlock = - TargetOperand == nullptr ? nullptr : TargetOperand->getIf<BasicBlockOperand>(); - if (TargetBlock == nullptr || TargetBlock->Block == nullptr) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V PseudoBR has no basic-block target"); - } - - auto Zero = physicalRegister(PhysicalRegisterID::X0); - if (!Zero) - return std::unexpected(Zero.error()); - MachineIRBuilder Builder(Function, Target); - auto Point = Builder.setInsertPointBefore(Instruction); - if (!Point) - return std::unexpected(Point.error()); - auto Pending = Builder.buildInstr(instructionOpcode(InstructionOpcode::JAL)); - if (!Pending) - return std::unexpected(Pending.error()); - auto Def = Pending->addDef(Register::fromPhysical(*Zero)); - if (!Def) - return std::unexpected(Def.error()); - auto Destination = Pending->addBasicBlock(*TargetBlock->Block); - if (!Destination) - return std::unexpected(Destination.error()); - auto Replacement = Pending->build(); - if (!Replacement) - return std::unexpected(Replacement.error()); - auto Decoration = copyCommonDecoration(Instruction, **Replacement, true, true, true); - if (!Decoration) - return std::unexpected(Decoration.error()); - auto Removed = removeOldInstruction(Instruction); - if (!Removed) - return std::unexpected(Removed.error()); - return true; -} - -[[nodiscard]] Expected<bool> expandIndirectBranch(MachineInstr &Instruction, - MachineFunction &Function, - const TargetDescription &Target) { - const MachineOperand *Address = Instruction.operandAt(0); - const MachineOperand *Offset = Instruction.operandAt(1); - if (Address == nullptr || Address->getIf<Register>() == nullptr || Offset == nullptr || - Offset->getIf<std::int64_t>() == nullptr) { - return makeUnexpected(ErrorCode::VerificationError, - "RISC-V PseudoBRIND has malformed operands"); - } - - auto Zero = physicalRegister(PhysicalRegisterID::X0); - if (!Zero) - return std::unexpected(Zero.error()); - MachineIRBuilder Builder(Function, Target); - auto Point = Builder.setInsertPointBefore(Instruction); - if (!Point) - return std::unexpected(Point.error()); - auto Pending = Builder.buildInstr(instructionOpcode(InstructionOpcode::JALR)); - if (!Pending) - return std::unexpected(Pending.error()); - auto Added = Pending->addDef(Register::fromPhysical(*Zero)); - if (!Added) - return std::unexpected(Added.error()); - Added = Pending->addOperand(Address->cloneDetached()); - if (!Added) - return std::unexpected(Added.error()); - Added = Pending->addOperand(Offset->cloneDetached()); - if (!Added) - return std::unexpected(Added.error()); - auto Implicit = copyExtraImplicitOperands(Instruction, 2, *Pending, std::nullopt, std::nullopt); - if (!Implicit) - return std::unexpected(Implicit.error()); - auto Replacement = Pending->build(); - if (!Replacement) - return std::unexpected(Replacement.error()); - auto Decoration = copyCommonDecoration(Instruction, **Replacement, true, true, true); - if (!Decoration) - return std::unexpected(Decoration.error()); - auto Removed = removeOldInstruction(Instruction); - if (!Removed) - return std::unexpected(Removed.error()); - return true; -} - class RISCVPseudoExpansionInfo final : public TargetPseudoExpansionInfo { public: [[nodiscard]] Expected<bool> preparePostRAPseudo(MachineInstr &Instruction, @@ -735,16 +576,6 @@ public: return expandCall(Instruction, Function, Target, false); if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoTAIL)) return expandCall(Instruction, Function, Target, true); - if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoRET)) - return expandReturn(Instruction, Function, Target); - if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoBR)) - return expandBranch(Instruction, Function, Target); - if (Instruction.opcode() == instructionOpcode(InstructionOpcode::PseudoBRIND)) - return expandIndirectBranch(Instruction, Function, Target); - if (Instruction.opcode() == instructionOpcode(InstructionOpcode::ReadFFLAGS)) - return expandFFLAGSAccess(Instruction, Function, Target, true); - if (Instruction.opcode() == instructionOpcode(InstructionOpcode::WriteFFLAGS)) - return expandFFLAGSAccess(Instruction, Function, Target, false); return false; } }; diff --git a/backend/utils/TableGen/CMakeLists.txt b/backend/utils/TableGen/CMakeLists.txt index ff6f8c8..48c1632 100644 --- a/backend/utils/TableGen/CMakeLists.txt +++ b/backend/utils/TableGen/CMakeLists.txt @@ -8,8 +8,10 @@ set( GlobalISelEmitter.cpp GlobalISelCombinerEmitter.cpp MacroFusionEmitter.cpp + MCPseudoLoweringEmitter.cpp Common/CodeGenInstruction.cpp Common/CodeGenMacroFusion.cpp + Common/CodeGenMCPseudoLowering.cpp Common/CodeGenRegisters.cpp Common/CodeGenSchedule.cpp Common/CodeGenSelection.cpp diff --git a/backend/utils/TableGen/Common/CodeGenInstruction.cpp b/backend/utils/TableGen/Common/CodeGenInstruction.cpp index 61c72a2..45b597c 100644 --- a/backend/utils/TableGen/Common/CodeGenInstruction.cpp +++ b/backend/utils/TableGen/Common/CodeGenInstruction.cpp @@ -388,13 +388,10 @@ CodeGenTarget::normalizeImplicitRegisters(const std::vector<SourceImplicitRegist HasEncodingCategory || HasAssemblyFormat; const bool IsPseudoSource = std::ranges::find(Instruction.Flags, "pseudo") != Instruction.Flags.end(); - const bool IsTerminalEmissionSource = - std::ranges::find(Instruction.Flags, "terminal_emission") != Instruction.Flags.end(); - if (HasAnyMachineFact != HasAllMachineFacts || - ((!IsPseudoSource || IsTerminalEmissionSource) && !HasAllMachineFacts)) { + if ((!IsPseudoSource && !HasAllMachineFacts) || HasAnyMachineFact != HasAllMachineFacts) { fail(Instruction.Range, - "encoded instructions and terminal-emission pseudos require complete scheduling, " - "encoding, mnemonic, and assembly-format facts"); + "encoded instructions require complete scheduling, encoding, mnemonic, and " + "assembly-format facts"); return false; } const auto SchedulingClass = SchedulingClassBySymbol.find(Instruction.SchedulingClassSymbol); diff --git a/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp b/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp new file mode 100644 index 0000000..49ec2a6 --- /dev/null +++ b/backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "CodeGenTarget.h" + +#include <algorithm> +#include <cstdint> +#include <ranges> +#include <string_view> +#include <unordered_set> + +namespace rcc::targetgen { +namespace { + +[[nodiscard]] const NormalizedInstruction *findInstruction(const NormalizedTargetModel &Model, + std::string_view Symbol) noexcept { + const auto Position = + std::ranges::find(Model.Instructions, Symbol, &NormalizedInstruction::Symbol); + return Position == Model.Instructions.end() ? nullptr : &*Position; +} + +[[nodiscard]] bool hasFlag(const NormalizedInstruction &Instruction, + std::string_view Flag) noexcept { + return std::ranges::contains(Instruction.Flags, Flag); +} + +[[nodiscard]] bool hasCompatibleKind(const NormalizedOperand &Source, + const NormalizedOperand &Result) noexcept { + return std::ranges::any_of(Source.Kinds, [&Result](const std::string &Kind) { + return std::ranges::contains(Result.Kinds, Kind); + }); +} + +} // namespace + +bool CodeGenTarget::normalizeMCPseudoExpansions(NormalizedTargetModel &Result) { + std::unordered_set<std::uint32_t> PseudoOpcodes; + for (const SourceMCPseudoExpansion &Expansion : Input.MCPseudoExpansions) { + const NormalizedInstruction *Pseudo = findInstruction(Result, Expansion.PseudoOpcodeSymbol); + const NormalizedInstruction *ResultInstruction = + findInstruction(Result, Expansion.ResultOpcodeSymbol); + if (Pseudo == nullptr || ResultInstruction == nullptr || + !PseudoOpcodes.insert(Pseudo == nullptr ? 0 : Pseudo->ID).second) { + fail(Expansion.Range, + "MC pseudo expansions require a unique declared pseudo and result instruction"); + return false; + } + if (!hasFlag(*Pseudo, "Pseudo") || !hasFlag(*Pseudo, "TerminalEmission") || + Pseudo->Owner != "AsmPrinter" || Pseudo->Deadline != "Emission" || + hasFlag(*ResultInstruction, "Pseudo") || ResultInstruction->AssemblyMnemonic.empty()) { + fail(Expansion.Range, + "MC pseudo expansions require an AsmPrinter-owned terminal pseudo and encoded result"); + return false; + } + if (Expansion.Operands.size() != ResultInstruction->Operands.size()) { + fail(Expansion.Range, "MC pseudo expansion operand count must match the result instruction"); + return false; + } + + NormalizedMCPseudoExpansion Normalized{ + .PseudoOpcode = Pseudo->ID, + .ResultOpcode = ResultInstruction->ID, + .Operands = {}, + }; + Normalized.Operands.reserve(Expansion.Operands.size()); + for (std::size_t Index = 0; Index < Expansion.Operands.size(); ++Index) { + const SourceMCPseudoOperand &Operand = Expansion.Operands[Index]; + const unsigned SourceCount = static_cast<unsigned>(Operand.SourceOperandIndex.has_value()) + + static_cast<unsigned>(!Operand.RegisterSymbol.empty()) + + static_cast<unsigned>(Operand.Immediate.has_value()); + if (SourceCount != 1) { + fail(Operand.Range, + "MC pseudo expansion operands require exactly one operand, register, or immediate"); + return false; + } + const NormalizedOperand &ResultOperand = ResultInstruction->Operands[Index]; + if (Operand.SourceOperandIndex) { + if (*Operand.SourceOperandIndex >= Pseudo->Operands.size() || + !hasCompatibleKind(Pseudo->Operands[*Operand.SourceOperandIndex], ResultOperand)) { + fail(Operand.Range, + "MC pseudo source operand must exist and match the result operand kind"); + return false; + } + Normalized.Operands.push_back({ + .Kind = NormalizedMCPseudoOperandKind::SourceOperand, + .Value = *Operand.SourceOperandIndex, + .Immediate = 0, + }); + continue; + } + if (!Operand.RegisterSymbol.empty()) { + const auto Register = RegisterBySymbol.find(Operand.RegisterSymbol); + if (Register == RegisterBySymbol.end() || + !std::ranges::contains(ResultOperand.Kinds, "Register")) { + fail(Operand.Range, + "MC pseudo fixed register must be declared and target a register operand"); + return false; + } + Normalized.Operands.push_back({ + .Kind = NormalizedMCPseudoOperandKind::Register, + .Value = Register->second, + .Immediate = 0, + }); + continue; + } + if (!std::ranges::contains(ResultOperand.Kinds, "Immediate")) { + fail(Operand.Range, "MC pseudo fixed immediate must target an immediate operand"); + return false; + } + Normalized.Operands.push_back({ + .Kind = NormalizedMCPseudoOperandKind::Immediate, + .Value = 0, + .Immediate = *Operand.Immediate, + }); + } + Result.MCPseudoExpansions.push_back(std::move(Normalized)); + } + std::ranges::sort(Result.MCPseudoExpansions, {}, &NormalizedMCPseudoExpansion::PseudoOpcode); + return true; +} + +} // namespace rcc::targetgen diff --git a/backend/utils/TableGen/Common/CodeGenTarget.cpp b/backend/utils/TableGen/Common/CodeGenTarget.cpp index 9b96d2e..d4c9795 100644 --- a/backend/utils/TableGen/Common/CodeGenTarget.cpp +++ b/backend/utils/TableGen/Common/CodeGenTarget.cpp @@ -37,7 +37,7 @@ CodeGenTarget::CodeGenTarget(const DescriptionAST &Input, std::string SourceName !normalizeSchedulingClasses(Result) || !normalizeEncodingCategories(Result) || !normalizeAssemblyFormats(Result) || !normalizeInstructions(Result) || !normalizeSelectionRules(Result) || !normalizeCombinerRules(Result) || - !normalizeMacroFusionRules(Result)) { + !normalizeMacroFusionRules(Result) || !normalizeMCPseudoExpansions(Result)) { return std::nullopt; } std::ranges::sort(Result.RegisterUnits, {}, &SourceRegisterUnit::ID); @@ -219,6 +219,7 @@ DescriptionGenerationResult generateDescription(const std::string &SourceName, .GlobalISel = emitGlobalISel(*Model, DisplayName), .GlobalISelCombiner = emitGlobalISelCombiner(*Model, DisplayName), .MacroFusion = emitMacroFusion(*Model, DisplayName), + .MCPseudoLowering = emitMCPseudoLowering(*Model, DisplayName), }, .Diagnostics = {}, }; diff --git a/backend/utils/TableGen/Common/CodeGenTarget.h b/backend/utils/TableGen/Common/CodeGenTarget.h index 6d3e185..43c7383 100644 --- a/backend/utils/TableGen/Common/CodeGenTarget.h +++ b/backend/utils/TableGen/Common/CodeGenTarget.h @@ -151,6 +151,24 @@ struct NormalizedMacroFusionRule final { bool RequireSecondDestinationTie = false; }; +enum class NormalizedMCPseudoOperandKind : std::uint8_t { + SourceOperand, + Register, + Immediate, +}; + +struct NormalizedMCPseudoOperand final { + NormalizedMCPseudoOperandKind Kind = NormalizedMCPseudoOperandKind::SourceOperand; + std::uint32_t Value = 0; + std::int64_t Immediate = 0; +}; + +struct NormalizedMCPseudoExpansion final { + std::uint32_t PseudoOpcode = 0; + std::uint32_t ResultOpcode = 0; + std::vector<NormalizedMCPseudoOperand> Operands; +}; + struct NormalizedEncodingCategory final { std::uint32_t ID = 0; std::string Symbol; @@ -393,6 +411,7 @@ struct NormalizedTargetModel final { std::vector<NormalizedSelectionRule> SelectionRules; std::vector<NormalizedCombinerRule> CombinerRules; std::vector<NormalizedMacroFusionRule> MacroFusionRules; + std::vector<NormalizedMCPseudoExpansion> MCPseudoExpansions; }; [[nodiscard]] std::optional<std::string_view> @@ -437,6 +456,7 @@ private: [[nodiscard]] bool normalizeSelectionRules(NormalizedTargetModel &Result); [[nodiscard]] bool normalizeCombinerRules(NormalizedTargetModel &Result); [[nodiscard]] bool normalizeMacroFusionRules(NormalizedTargetModel &Result); + [[nodiscard]] bool normalizeMCPseudoExpansions(NormalizedTargetModel &Result); const DescriptionAST &Input; std::string SourceName; diff --git a/backend/utils/TableGen/MCPseudoLoweringEmitter.cpp b/backend/utils/TableGen/MCPseudoLoweringEmitter.cpp new file mode 100644 index 0000000..5afa911 --- /dev/null +++ b/backend/utils/TableGen/MCPseudoLoweringEmitter.cpp @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "TableGenBackends.h" + +#include <cstddef> +#include <ostream> +#include <sstream> +#include <string> +#include <string_view> + +namespace rcc::targetgen { + +std::string emitMCPseudoLowering(const NormalizedTargetModel &Model, std::string_view SourceName) { + std::ostringstream Output; + Output << "// SPDX-License-Identifier: GPL-3.0-or-later\n\n"; + Output << "// This file is generated by rcc-tblgen from "; + appendQuoted(Output, SourceName); + Output << ". Do not edit it manually.\n\n"; + Output << "#ifdef GET_MC_PSEUDO_LOWERING\n\n"; + Output << "[[nodiscard]] Expected<std::optional<mc::MCInst>>\n" + "lowerGeneratedMCPseudo(const MachineInstr &Instruction,\n" + " MachineMCContext &Context) {\n" + " switch (Instruction.opcode().value()) {\n" + " default:\n" + " return std::optional<mc::MCInst>{};\n"; + for (const NormalizedMCPseudoExpansion &Expansion : Model.MCPseudoExpansions) { + Output << " case " << Expansion.PseudoOpcode << ": {\n" + << " mc::MCInst Result(mc::MCOpcode::fromValue(" << Expansion.ResultOpcode + << "));\n" + " Result.setFlags(Instruction.flags().rawValue());\n" + " Result.setSourceIdentity(Instruction.stableID().value());\n" + " Result.reserveOperands(" + << Expansion.Operands.size() << ");\n"; + for (std::size_t Index = 0; Index < Expansion.Operands.size(); ++Index) { + const NormalizedMCPseudoOperand &Operand = Expansion.Operands[Index]; + switch (Operand.Kind) { + case NormalizedMCPseudoOperandKind::SourceOperand: + Output << " const MachineOperand *Operand" << Index << " = Instruction.operandAt(" + << Operand.Value << ");\n" + << " if (Operand" << Index << " == nullptr)\n" + << " return makeUnexpected(ErrorCode::AssemblyLoweringFailed,\n" + " \"MC pseudo has too few operands\");\n" + << " auto Lowered" << Index << " =\n" + << " lowerOperand(*Operand" << Index + << ", Instruction.function(), Context);\n" + << " if (!Lowered" << Index << ")\n" + << " return std::unexpected(Lowered" << Index << ".error());\n" + << " Result.addOperand(std::move(*Lowered" << Index << "));\n"; + break; + case NormalizedMCPseudoOperandKind::Register: + Output << " Result.addOperand(mc::MCOperand::registerOperand(\n" + " mc::MCRegister::fromValue(" + << Operand.Value << ")));\n"; + break; + case NormalizedMCPseudoOperandKind::Immediate: + Output << " Result.addOperand(mc::MCOperand::immediate(" << Operand.Immediate << "));\n"; + break; + } + } + Output << " return std::optional<mc::MCInst>{std::move(Result)};\n" + " }\n"; + } + Output << " }\n" + "}\n\n" + "#endif // GET_MC_PSEUDO_LOWERING\n"; + return Output.str(); +} + +} // namespace rcc::targetgen diff --git a/backend/utils/TableGen/TableGenBackends.h b/backend/utils/TableGen/TableGenBackends.h index 6315a6c..dff0333 100644 --- a/backend/utils/TableGen/TableGenBackends.h +++ b/backend/utils/TableGen/TableGenBackends.h @@ -20,6 +20,7 @@ struct GeneratedDescription final { std::string GlobalISel; std::string GlobalISelCombiner; std::string MacroFusion; + std::string MCPseudoLowering; }; struct DescriptionGenerationResult final { @@ -50,6 +51,8 @@ struct DescriptionGenerationResult final { std::string_view SourceName); [[nodiscard]] std::string emitMacroFusion(const NormalizedTargetModel &Model, std::string_view SourceName); +[[nodiscard]] std::string emitMCPseudoLowering(const NormalizedTargetModel &Model, + std::string_view SourceName); [[nodiscard]] DescriptionGenerationResult generateDescription(const std::string &SourceName, std::string SourceText); diff --git a/backend/utils/TableGen/rcc-tblgen.cpp b/backend/utils/TableGen/rcc-tblgen.cpp index 47f0de4..cf10665 100644 --- a/backend/utils/TableGen/rcc-tblgen.cpp +++ b/backend/utils/TableGen/rcc-tblgen.cpp @@ -24,6 +24,7 @@ struct CommandLine final { std::string GlobalISelPath; std::string GlobalISelCombinerPath; std::string MacroFusionPath; + std::string MCPseudoLoweringPath; }; [[nodiscard]] bool parseCommandLine(int ArgumentCount, char *Arguments[], CommandLine &Result) { @@ -39,7 +40,8 @@ struct CommandLine final { } if (Argument == "--register-header" || Argument == "--instruction-header" || Argument == "--tables" || Argument == "--global-isel" || - Argument == "--global-isel-combiner" || Argument == "--macro-fusion") { + Argument == "--global-isel-combiner" || Argument == "--macro-fusion" || + Argument == "--mc-pseudo-lowering") { if (Index + 1 >= ArgumentCount) { std::cerr << "rcc-tblgen: missing value for " << Argument << '\n'; return false; @@ -55,6 +57,8 @@ struct CommandLine final { Destination = &Result.GlobalISelCombinerPath; else if (Argument == "--macro-fusion") Destination = &Result.MacroFusionPath; + else if (Argument == "--mc-pseudo-lowering") + Destination = &Result.MCPseudoLoweringPath; else Destination = &Result.TablesPath; *Destination = Arguments[++Index]; @@ -66,12 +70,13 @@ struct CommandLine final { if (!Result.InputPaths.empty() && !Result.RegisterHeaderPath.empty() && !Result.InstructionHeaderPath.empty() && !Result.TablesPath.empty() && !Result.GlobalISelPath.empty() && !Result.GlobalISelCombinerPath.empty() && - !Result.MacroFusionPath.empty()) { + !Result.MacroFusionPath.empty() && !Result.MCPseudoLoweringPath.empty()) { return true; } std::cerr << "usage: rcc-tblgen --input <file> [--input <fragment>]... --register-header <file> " "--instruction-header <file> --tables <file> --global-isel <file> " - "--global-isel-combiner <file> --macro-fusion <file>\n"; + "--global-isel-combiner <file> --macro-fusion <file> " + "--mc-pseudo-lowering <file>\n"; return false; } @@ -176,7 +181,8 @@ combineDescriptionSources(const std::vector<std::string> &Paths, continue; } if (Section.Name != "instructions" && Section.Name != "selection_rules" && - Section.Name != "combiner_rules") { + Section.Name != "combiner_rules" && Section.Name != "macro_fusion_rules" && + Section.Name != "mc_pseudo_expansions") { std::cerr << "rcc-tblgen: duplicate description section '" << Section.Name << "' in '" << Paths[Index] << "'\n"; return std::nullopt; @@ -238,7 +244,8 @@ int main(int ArgumentCount, char *Arguments[]) { writeFile(Command.TablesPath, Output.TargetTables) && writeFile(Command.GlobalISelPath, Output.GlobalISel) && writeFile(Command.GlobalISelCombinerPath, Output.GlobalISelCombiner) && - writeFile(Command.MacroFusionPath, Output.MacroFusion) + writeFile(Command.MacroFusionPath, Output.MacroFusion) && + writeFile(Command.MCPseudoLoweringPath, Output.MCPseudoLowering) ? 0 : 1; } |
