aboutsummaryrefslogtreecommitdiff
path: root/backend/utils/TableGen/GlobalISelCombinerEmitter.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-19 05:13:13 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-19 05:13:13 +0800
commitdf7095e67ea06f7d6a81d99e70c804ce54ef950d (patch)
treeb61459583ac9972b196d5e639f02593374eae41f /backend/utils/TableGen/GlobalISelCombinerEmitter.cpp
parent307fc0961972ac5264d6f3459978fbec95cad3a9 (diff)
downloadrcc-project-df7095e67ea06f7d6a81d99e70c804ce54ef950d.tar.gz
rcc-project-df7095e67ea06f7d6a81d99e70c804ce54ef950d.tar.xz
[GlobalISel] Generate prelegalizer combiner rules
Diffstat (limited to 'backend/utils/TableGen/GlobalISelCombinerEmitter.cpp')
-rw-r--r--backend/utils/TableGen/GlobalISelCombinerEmitter.cpp154
1 files changed, 154 insertions, 0 deletions
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 <cstddef>
+#include <cstdint>
+#include <sstream>
+#include <string>
+#include <string_view>
+
+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<GIMatchTableConstantRange, " << ConstantRangeCount
+ << "> 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<GIMatchTableInstruction, " << InstructionCount
+ << "> 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<std::uint32_t>(Rule.ResultType->Kind));
+ (void)Kind;
+ }
+ for (const NormalizedSelectionOperandTypePredicate &Predicate : Rule.OperandTypes) {
+ emitInstruction(Output, "CheckOperandType", Predicate.OperandIndex, Predicate.Type.Bits,
+ static_cast<std::uint32_t>(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<std::uint32_t>(FirstConstantRange), Predicate.OperandIndex,
+ static_cast<std::int64_t>(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<GIMatchTableRule, " << Model.CombinerRules.size()
+ << "> 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