diff options
Diffstat (limited to 'backend/utils/TableGen/InstrInfoEmitter.cpp')
| -rw-r--r-- | backend/utils/TableGen/InstrInfoEmitter.cpp | 192 |
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 |
