// 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