// SPDX-License-Identifier: GPL-3.0-or-later #include "TableGenBackends.h" #include #include #include #include #include #include #include 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 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::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();\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 \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 " "&Descriptors,\n" << " std::vector &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