From df7095e67ea06f7d6a81d99e70c804ce54ef950d Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Wed, 19 Aug 2026 05:13:13 +0800 Subject: [GlobalISel] Generate prelegalizer combiner rules --- .../utils/TableGen/GlobalISelCombinerEmitter.cpp | 154 +++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 backend/utils/TableGen/GlobalISelCombinerEmitter.cpp (limited to 'backend/utils/TableGen/GlobalISelCombinerEmitter.cpp') diff --git a/backend/utils/TableGen/GlobalISelCombinerEmitter.cpp b/backend/utils/TableGen/GlobalISelCombinerEmitter.cpp new file mode 100644 index 0000000..0c727e3 --- /dev/null +++ b/backend/utils/TableGen/GlobalISelCombinerEmitter.cpp @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "TableGenBackends.h" + +#include +#include +#include +#include +#include + +namespace rcc::targetgen { +namespace { + +void emitInstruction(std::ostream &Output, std::string_view Opcode, std::uint32_t OperandIndex = 0, + std::uint32_t Value = 0, std::uint32_t Auxiliary = 0, + std::int64_t Immediate = 0, std::string_view Symbol = {}) { + Output << " {GIMatchTableOpcode::" << Opcode << ", " << OperandIndex << ", " << Value << ", " + << Auxiliary << ", " << Immediate << ", "; + appendQuoted(Output, Symbol); + Output << "},\n"; +} + +[[nodiscard]] std::size_t instructionCount(const NormalizedCombinerRule &Rule) noexcept { + std::size_t Count = 2U + (Rule.ResultType ? 1U : 0U) + Rule.OperandTypes.size() + + Rule.TargetPredicates.size() + Rule.InstructionFlags.size() + + (Rule.Action.ClearInstructionFlags != 0 ? 1U : 0U) + + Rule.EraseOperandDefinitions.size(); + for (const NormalizedSelectionDefUsePredicate &DefUse : Rule.DefUsePredicates) + Count += 1U + DefUse.Captures.size() + DefUse.OperandDefConstants.size(); + Count += Rule.Action.Kind == NormalizedCombinerActionKind::ReplaceRootWithCapturedOperand + ? 1U + : 1U + Rule.Action.OperandRenderers.size(); + return Count; +} + +} // namespace + +std::string emitGlobalISelCombiner(const NormalizedTargetModel &Model, + std::string_view SourceName) { + std::size_t InstructionCount = 0; + std::size_t ConstantRangeCount = 0; + for (const NormalizedCombinerRule &Rule : Model.CombinerRules) { + InstructionCount += instructionCount(Rule); + for (const NormalizedSelectionDefUsePredicate &DefUse : Rule.DefUsePredicates) + for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : + DefUse.OperandDefConstants) + ConstantRangeCount += Predicate.Ranges.size(); + } + + 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_GLOBALISEL_COMBINER_TABLE\n\n"; + Output << "constexpr std::array GeneratedGlobalISelCombinerConstantRanges = {{\n"; + for (const NormalizedCombinerRule &Rule : Model.CombinerRules) { + for (const NormalizedSelectionDefUsePredicate &DefUse : Rule.DefUsePredicates) { + for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : + DefUse.OperandDefConstants) { + for (const NormalizedSelectionConstantRange &Range : Predicate.Ranges) + Output << " {" << Range.Minimum << ", " << Range.Maximum << "},\n"; + } + } + } + Output << "}};\n\n"; + + Output << "constexpr std::array GeneratedGlobalISelCombinerInstructions = {{\n"; + std::size_t FirstConstantRange = 0; + for (const NormalizedCombinerRule &Rule : Model.CombinerRules) { + emitInstruction(Output, "CheckOpcode", 0, Rule.MatchOpcode); + if (Rule.ResultType) { + const char *Kind = "Any"; + if (Rule.ResultType->Kind == NormalizedSelectionTypeKind::Scalar) + Kind = "Scalar"; + else if (Rule.ResultType->Kind == NormalizedSelectionTypeKind::Pointer) + Kind = "Pointer"; + emitInstruction(Output, "CheckOperandType", 0, Rule.ResultType->Bits, + static_cast(Rule.ResultType->Kind)); + (void)Kind; + } + for (const NormalizedSelectionOperandTypePredicate &Predicate : Rule.OperandTypes) { + emitInstruction(Output, "CheckOperandType", Predicate.OperandIndex, Predicate.Type.Bits, + static_cast(Predicate.Type.Kind)); + } + for (const std::string &Predicate : Rule.TargetPredicates) + emitInstruction(Output, "CheckTargetPredicate", 0, 0, 0, 0, Predicate); + for (const std::uint32_t Flags : Rule.InstructionFlags) + emitInstruction(Output, "CheckInstructionFlag", 0, Flags); + for (const NormalizedSelectionDefUsePredicate &DefUse : Rule.DefUsePredicates) { + emitInstruction(Output, "CheckOperandDefOpcode", DefUse.RootOperandIndex, DefUse.Opcode); + for (const NormalizedSelectionOperandDefConstantPredicate &Predicate : + DefUse.OperandDefConstants) { + emitInstruction(Output, "CheckOperandDefOperandConstantRanges", DefUse.RootOperandIndex, + static_cast(FirstConstantRange), Predicate.OperandIndex, + static_cast(Predicate.Ranges.size())); + FirstConstantRange += Predicate.Ranges.size(); + } + for (const NormalizedSelectionDefUseCapture &Capture : DefUse.Captures) + emitInstruction(Output, "CaptureDefOperand", DefUse.RootOperandIndex, Capture.ID, + Capture.OperandIndex); + } + if (Rule.Action.Kind == NormalizedCombinerActionKind::ReplaceRootWithCapturedOperand) { + emitInstruction(Output, "ReplaceRootWithCapturedOperand", 0, Rule.Action.CapturedOperand); + } else { + emitInstruction(Output, "MutateOpcode", 0, Rule.Action.ResultOpcode); + for (const NormalizedCombinerOperandRenderer &Renderer : Rule.Action.OperandRenderers) { + switch (Renderer.SourceKind) { + case NormalizedCombinerOperandRenderer::Kind::RootOperand: + emitInstruction(Output, "RenderOperand", Renderer.Value); + break; + case NormalizedCombinerOperandRenderer::Kind::CapturedOperand: + emitInstruction(Output, "RenderCapturedOperand", 0, Renderer.Value); + break; + case NormalizedCombinerOperandRenderer::Kind::CapturedTypeBits: + emitInstruction(Output, "RenderCapturedTypeBits", 0, Renderer.Value); + break; + case NormalizedCombinerOperandRenderer::Kind::Immediate: + emitInstruction(Output, "RenderImmediate", 0, 0, 0, Renderer.Immediate); + break; + } + } + } + if (Rule.Action.ClearInstructionFlags != 0) + emitInstruction(Output, "ClearInstructionFlags", 0, Rule.Action.ClearInstructionFlags); + for (const std::uint32_t OperandIndex : Rule.EraseOperandDefinitions) + emitInstruction(Output, "EraseOperandDefinition", OperandIndex); + emitInstruction(Output, "Complete"); + } + Output << "}};\n\n"; + + Output << "constexpr std::array GeneratedGlobalISelCombinerRules = {{\n"; + std::size_t FirstInstruction = 0; + for (const NormalizedCombinerRule &Rule : Model.CombinerRules) { + const std::size_t Count = instructionCount(Rule); + Output << " {"; + appendQuoted(Output, Rule.Symbol); + Output << ", " << Rule.Priority << ", " << FirstInstruction << ", " << Count << "},\n"; + FirstInstruction += Count; + } + Output << "}};\n\n"; + Output + << "[[nodiscard]] constexpr GIMatchTable generatedGlobalISelCombinerMatchTable() noexcept {\n" + " return {GeneratedGlobalISelCombinerInstructions, GeneratedGlobalISelCombinerRules,\n" + " GeneratedGlobalISelCombinerConstantRanges, GIMatchTableKind::Combiner};\n" + "}\n\n"; + Output << "#endif // GET_GLOBALISEL_COMBINER_TABLE\n"; + return Output.str(); +} + +} // namespace rcc::targetgen -- cgit v1.2.3