aboutsummaryrefslogtreecommitdiff
path: root/backend/utils/TableGen/InstrInfoEmitter.cpp
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 13:10:47 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-13 13:10:47 +0800
commit444db30751380e8fe459bfeae4c5bb2a93c596eb (patch)
tree5c60a23678f836113e75fb2526d3ec7b28b42f55 /backend/utils/TableGen/InstrInfoEmitter.cpp
parentfde3e045d4dcc5c404cb4216389e18b0e720b8e0 (diff)
downloadrcc-project-444db30751380e8fe459bfeae4c5bb2a93c596eb.tar.gz
rcc-project-444db30751380e8fe459bfeae4c5bb2a93c596eb.tar.xz
[TableGen] Split the target description generator
Diffstat (limited to 'backend/utils/TableGen/InstrInfoEmitter.cpp')
-rw-r--r--backend/utils/TableGen/InstrInfoEmitter.cpp192
1 files changed, 192 insertions, 0 deletions
diff --git a/backend/utils/TableGen/InstrInfoEmitter.cpp b/backend/utils/TableGen/InstrInfoEmitter.cpp
new file mode 100644
index 0000000..6c6426d
--- /dev/null
+++ b/backend/utils/TableGen/InstrInfoEmitter.cpp
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "TableGenBackends.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <ostream>
+#include <span>
+#include <sstream>
+#include <string>
+#include <string_view>
+
+namespace rcc::targetgen {
+namespace {
+
+void emitOperandDescriptor(std::ostream &Output, const NormalizedOperand &Operand) {
+ Output << " {.Kinds = OperandKindSet{";
+ for (const std::string &Kind : Operand.Kinds)
+ Output << "MachineOperand::Kind::" << Kind << ", ";
+ Output << "}, .RegisterRole = RegisterOperandRole::" << Operand.RegisterRole;
+ Output << ", .RegClass = ";
+ if (Operand.RegisterClass)
+ Output << "RegisterClassID::fromValue(" << *Operand.RegisterClass << ")";
+ else
+ Output << "std::nullopt";
+ Output << ", .RegBank = ";
+ if (Operand.RegisterBank)
+ Output << "RegisterBankID::fromValue(" << *Operand.RegisterBank << ")";
+ else
+ Output << "std::nullopt";
+ Output << ", .ImmediatePredicate = ";
+ if (Operand.ImmediatePredicate)
+ Output << "ImmediatePredicateID::fromValue(" << *Operand.ImmediatePredicate << ")";
+ else
+ Output << "std::nullopt";
+ Output << ", .MemoryRole = MemoryOperandRole::" << Operand.MemoryRole;
+ Output << ", .DefaultTiedOperand = ";
+ if (Operand.DefaultTiedOperand)
+ Output << "std::size_t{" << *Operand.DefaultTiedOperand << "}";
+ else
+ Output << "std::nullopt";
+ Output << ", .EarlyClobber = " << (Operand.EarlyClobber ? "true" : "false")
+ << ", .Optional = " << (Operand.Optional ? "true" : "false")
+ << ", .VariadicGroup = " << (Operand.VariadicGroup ? "true" : "false")
+ << ", .AllowSubReg = " << (Operand.AllowSubReg ? "true" : "false");
+ Output << ", .Name = ";
+ if (Operand.Name)
+ Output << "NamedOperandID::fromValue(" << *Operand.Name << ")";
+ else
+ Output << "std::nullopt";
+ Output << ", .TargetOperandType = std::nullopt, .AllowedTargetFlags = "
+ << Operand.AllowedTargetFlags << ", .TypeConstraint = std::nullopt},\n";
+}
+
+void emitImplicitRegisterList(std::ostream &Output, const NormalizedTargetModel &Model,
+ std::span<const NormalizedImplicitRegister> Registers) {
+ Output << "{";
+ for (const NormalizedImplicitRegister &Register : Registers) {
+ Output << "{physical(PhysicalRegisterID::" << findRegister(Model, Register.Register).Symbol
+ << "), " << (Register.EarlyClobber ? "true" : "false") << ", "
+ << (Register.Renamable ? "true" : "false") << "}, ";
+ }
+ Output << "}";
+}
+
+void emitImmediatePredicate(std::ostream &Output, const NormalizedImmediatePredicate &Predicate) {
+ const std::int64_t PositiveLimit = std::int64_t{1} << (Predicate.Bits - 1U);
+ const std::int64_t Minimum = Predicate.IsSigned ? -PositiveLimit : 0;
+ const std::int64_t Maximum =
+ Predicate.IsSigned
+ ? PositiveLimit - 1
+ : static_cast<std::int64_t>((std::uint64_t{1} << Predicate.Bits) - std::uint64_t{1});
+ Output << " {.ID = ImmediatePredicateID::fromValue(" << Predicate.ID << "), .Name = ";
+ appendQuoted(Output, Predicate.Name);
+ Output << ", .Predicate = [](const MachineOperand &Operand) {\n"
+ << " const auto *Value = Operand.getIf<std::int64_t>();\n"
+ << " return Value != nullptr && *Value >= " << Minimum
+ << " && *Value <= " << Maximum;
+ if (Predicate.Alignment != 1)
+ Output << " && (*Value % " << Predicate.Alignment << ") == 0";
+ if (Predicate.NonZero)
+ Output << " && *Value != 0";
+ if (!Predicate.AllowedValues.empty()) {
+ Output << " && (";
+ for (std::size_t Index = 0; Index < Predicate.AllowedValues.size(); ++Index) {
+ if (Index != 0)
+ Output << " || ";
+ Output << "*Value == " << Predicate.AllowedValues[Index];
+ }
+ Output << ")";
+ }
+ Output << ";\n }},\n";
+}
+
+} // namespace
+
+[[nodiscard]] std::string emitInstructionHeader(const NormalizedTargetModel &Model,
+ std::string_view SourceName) {
+ const std::string Guard = "RCC_TARGET_" + upperIdentifier(Model.Target.Namespace) + "_" +
+ upperIdentifier(Model.Target.Name) + "INSTRUCTIONS_H";
+ 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 << "#ifndef " << Guard << "\n#define " << Guard << "\n\n";
+ Output << "#include <cstdint>\n\n";
+ Output << "namespace rcc::" << Model.Target.Namespace << " {\n\n";
+
+ Output << "enum class InstructionOpcode : std::uint32_t {\n Invalid = 0,\n";
+ for (const NormalizedInstruction &Instruction : Model.Instructions)
+ Output << " " << Instruction.Symbol << " = " << Instruction.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "enum class ImmediatePredicate : std::uint32_t {\n None = 0,\n";
+ for (const NormalizedImmediatePredicate &Predicate : Model.ImmediatePredicates)
+ Output << " " << Predicate.Symbol << " = " << Predicate.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "enum class NamedOperand : std::uint32_t {\n None = 0,\n";
+ for (const NormalizedNamedOperand &Operand : Model.NamedOperands)
+ Output << " " << Operand.Symbol << " = " << Operand.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "enum class SchedulingClass : std::uint32_t {\n None = 0,\n";
+ for (const NormalizedSchedulingClass &Class : Model.SchedulingClasses)
+ Output << " " << Class.Symbol << " = " << Class.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "enum class EncodingCategory : std::uint32_t {\n None = 0,\n";
+ for (const NormalizedEncodingCategory &Category : Model.EncodingCategories)
+ Output << " " << Category.Symbol << " = " << Category.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "enum class AssemblyFormat : std::uint32_t {\n None = 0,\n";
+ for (const NormalizedAssemblyFormat &Format : Model.AssemblyFormats)
+ Output << " " << Format.Symbol << " = " << Format.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "enum class CallingConvention : std::uint32_t {\n None = 0,\n";
+ for (const NormalizedCallingConvention &Convention : Model.CallingConventions)
+ Output << " " << Convention.Symbol << " = " << Convention.ID << ",\n";
+ Output << "};\n\n";
+
+ Output << "} // namespace rcc::" << Model.Target.Namespace << "\n\n";
+ Output << "#endif // " << Guard << "\n";
+ return Output.str();
+}
+
+std::string emitInstructionInfo(const NormalizedTargetModel &Model) {
+ std::ostringstream Output;
+ Output
+ << "void appendGeneratedInstructionInfo(std::vector<rcc::InstructionDescriptor> "
+ "&Descriptors,\n"
+ << " std::vector<rcc::ImmediatePredicate> &Predicates) {\n"
+ << " Predicates = {\n";
+ for (const NormalizedImmediatePredicate &Predicate : Model.ImmediatePredicates)
+ emitImmediatePredicate(Output, Predicate);
+ Output << " };\n Descriptors = {\n";
+ for (const NormalizedInstruction &Instruction : Model.Instructions) {
+ Output << " {.InstructionOpcode = Opcode::fromValue(" << Instruction.ID << "), .Name = ";
+ appendQuoted(Output, Instruction.Name);
+ Output << ", .Operands = {\n";
+ for (const NormalizedOperand &Operand : Instruction.Operands)
+ emitOperandDescriptor(Output, Operand);
+ Output << " }, .NumExplicitDefs = " << Instruction.NumExplicitDefs
+ << ", .Variadic = " << (Instruction.Variadic ? "true" : "false")
+ << ", .MinimumVariadicRepetitions = 0, .ImplicitDefs = ";
+ emitImplicitRegisterList(Output, Model, Instruction.ImplicitDefs);
+ Output << ", .ImplicitUses = ";
+ emitImplicitRegisterList(Output, Model, Instruction.ImplicitUses);
+ Output << ", .AllowExtraImplicitOperands = "
+ << (Instruction.AllowExtraImplicitOperands ? "true" : "false")
+ << ", .Flags = InstructionFlags{";
+ for (const std::string &Flag : Instruction.Flags)
+ Output << "InstructionFlag::" << Flag << ", ";
+ Output << "}, .SchedulingClass = SchedulingClassID::fromValue(" << Instruction.SchedulingClass
+ << "), .EncodingCategory = EncodingCategoryID::fromValue("
+ << Instruction.EncodingCategory << "), .AssemblyFormat = AssemblyFormatID::fromValue("
+ << Instruction.AssemblyFormat << "), .RequiresMemoryOperands = "
+ << (Instruction.RequiresMemoryOperands ? "true" : "false")
+ << ", .Owner = PseudoOwner::" << Instruction.Owner
+ << ", .Deadline = PipelineStage::" << Instruction.Deadline
+ << ", .VerifyExplicitOperands = nullptr, "
+ ".VerifyInstructionSemantics = nullptr},\n";
+ }
+ Output << " };\n}\n\n";
+
+ return Output.str();
+}
+
+} // namespace rcc::targetgen