From 75f1223070749b0df3002226ebbb474c68c71f90 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sat, 22 Aug 2026 19:16:18 +0800 Subject: [RISCV] Generate MC pseudo lowering --- backend/utils/TableGen/CMakeLists.txt | 2 + .../utils/TableGen/Common/CodeGenInstruction.cpp | 9 +- .../TableGen/Common/CodeGenMCPseudoLowering.cpp | 121 +++++++++++++++++++++ backend/utils/TableGen/Common/CodeGenTarget.cpp | 3 +- backend/utils/TableGen/Common/CodeGenTarget.h | 20 ++++ backend/utils/TableGen/MCPseudoLoweringEmitter.cpp | 69 ++++++++++++ backend/utils/TableGen/TableGenBackends.h | 3 + backend/utils/TableGen/rcc-tblgen.cpp | 17 ++- 8 files changed, 232 insertions(+), 12 deletions(-) create mode 100644 backend/utils/TableGen/Common/CodeGenMCPseudoLowering.cpp create mode 100644 backend/utils/TableGen/MCPseudoLoweringEmitter.cpp (limited to 'backend/utils') 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 +#include +#include +#include +#include + +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 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(Operand.SourceOperandIndex.has_value()) + + static_cast(!Operand.RegisterSymbol.empty()) + + static_cast(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 Operands; +}; + struct NormalizedEncodingCategory final { std::uint32_t ID = 0; std::string Symbol; @@ -393,6 +411,7 @@ struct NormalizedTargetModel final { std::vector SelectionRules; std::vector CombinerRules; std::vector MacroFusionRules; + std::vector MCPseudoExpansions; }; [[nodiscard]] std::optional @@ -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 +#include +#include +#include +#include + +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>\n" + "lowerGeneratedMCPseudo(const MachineInstr &Instruction,\n" + " MachineMCContext &Context) {\n" + " switch (Instruction.opcode().value()) {\n" + " default:\n" + " return std::optional{};\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{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 [--input ]... --register-header " "--instruction-header --tables --global-isel " - "--global-isel-combiner --macro-fusion \n"; + "--global-isel-combiner --macro-fusion " + "--mc-pseudo-lowering \n"; return false; } @@ -176,7 +181,8 @@ combineDescriptionSources(const std::vector &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; } -- cgit v1.2.3