diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-07 22:03:11 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-07 22:03:11 +0800 |
| commit | 3e15bfd7b075209ec3b65d30d0611e060f6fbb77 (patch) | |
| tree | 9a55310fddbb48a87f32bd964ff94374593f3f4c /backend/lib | |
| parent | e16de95dce32f077361577377d5c52fc4ad78339 (diff) | |
| download | rcc-project-3e15bfd7b075209ec3b65d30d0611e060f6fbb77.tar.gz rcc-project-3e15bfd7b075209ec3b65d30d0611e060f6fbb77.tar.xz | |
[RISCV] Complete RV64GC instruction description
Diffstat (limited to 'backend/lib')
| -rw-r--r-- | backend/lib/CodeGen/InstructionDescriptor.cpp | 215 | ||||
| -rw-r--r-- | backend/lib/Target/Description/TargetDescriptionGenerator.cpp | 1909 | ||||
| -rw-r--r-- | backend/lib/Target/Description/TargetDescriptionGenerator.h | 1 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/CMakeLists.txt | 34 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCV.rccdesc | 2979 | ||||
| -rw-r--r-- | backend/lib/Target/RISCV/RISCVTarget.cpp | 61 |
6 files changed, 5144 insertions, 55 deletions
diff --git a/backend/lib/CodeGen/InstructionDescriptor.cpp b/backend/lib/CodeGen/InstructionDescriptor.cpp index 3d97440..57400d6 100644 --- a/backend/lib/CodeGen/InstructionDescriptor.cpp +++ b/backend/lib/CodeGen/InstructionDescriptor.cpp @@ -10,6 +10,7 @@ #include <cstddef> #include <cstdint> #include <string> +#include <unordered_map> #include <unordered_set> #include <utility> #include <vector> @@ -54,6 +55,8 @@ namespace { } bool SawOptional = false; + std::optional<std::size_t> VariadicBegin; + std::optional<std::size_t> VariadicEnd; for (std::size_t Index = 0; Index < Descriptor.Operands.size(); ++Index) { const OperandDescriptor &Operand = Descriptor.Operands[Index]; if (Operand.Kinds.empty()) { @@ -75,19 +78,17 @@ namespace { return makeUnexpected(ErrorCode::InvalidArgument, "non-register operand descriptor has register constraints"); } + if (Operand.TypeConstraint) { + if (!isRegisterOnly(Operand.Kinds) || Operand.TypeConstraint->Kinds.empty() || + Operand.TypeConstraint->Kinds.contains(LLT::Kind::Invalid)) { + return makeUnexpected(ErrorCode::InvalidArgument, + "typed operand descriptor requires a nonempty register type set"); + } + } if (Operand.EarlyClobber && !isDefRole(Operand.RegisterRole)) { return makeUnexpected(ErrorCode::InvalidArgument, "early-clobber operand descriptor must define a register"); } - if (Index < Descriptor.NumExplicitDefs && !isDefRole(Operand.RegisterRole)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "canonical explicit defs must precede instruction uses"); - } - if (Index >= Descriptor.NumExplicitDefs && isDefRole(Operand.RegisterRole)) { - return makeUnexpected(ErrorCode::InvalidArgument, - "register definition appears after the explicit def prefix"); - } - if (Descriptor.Variadic && Operand.Optional) { return makeUnexpected(ErrorCode::InvalidArgument, "variadic instruction descriptor cannot contain optional operands"); @@ -99,27 +100,61 @@ namespace { "optional operand descriptors must form a trailing suffix"); } - if (Operand.VariadicGroup && - (!Descriptor.Variadic || Index + 1 != Descriptor.Operands.size())) { - return makeUnexpected(ErrorCode::InvalidArgument, - "variadic operand group must be the final descriptor"); - } if (Operand.VariadicGroup && (Operand.Optional || Operand.DefaultTiedOperand)) { return makeUnexpected(ErrorCode::InvalidArgument, "variadic operand descriptor cannot be optional or have a default tie"); } + if (Operand.VariadicGroup) { + if (!Descriptor.Variadic) { + return makeUnexpected(ErrorCode::InvalidArgument, + "non-variadic instruction descriptor has a variadic group"); + } + if (!VariadicBegin) + VariadicBegin = Index; + VariadicEnd = Index + 1; + } else if (VariadicEnd) { + const bool LaterGroup = + std::ranges::any_of(Descriptor.Operands.begin() + static_cast<std::ptrdiff_t>(Index), + Descriptor.Operands.end(), [](const OperandDescriptor &Candidate) { + return Candidate.VariadicGroup; + }); + if (LaterGroup) { + return makeUnexpected(ErrorCode::InvalidArgument, + "variadic operand group descriptors must be contiguous"); + } + } } - if (Descriptor.Variadic && - (Descriptor.Operands.empty() || !Descriptor.Operands.back().VariadicGroup)) { + if (Descriptor.Variadic && !VariadicBegin) { return makeUnexpected(ErrorCode::InvalidArgument, - "variadic instruction descriptor requires a final variadic group"); + "variadic instruction descriptor requires a variadic group"); } - if (!Descriptor.Variadic && - std::ranges::any_of(Descriptor.Operands, - [](const OperandDescriptor &Operand) { return Operand.VariadicGroup; })) { + if (!Descriptor.Variadic && Descriptor.MinimumVariadicRepetitions != 0) { return makeUnexpected(ErrorCode::InvalidArgument, - "non-variadic instruction descriptor has a variadic group"); + "non-variadic instruction has a minimum variadic repetition count"); + } + + bool SawUse = false; + std::size_t MinimumDefs = 0; + for (std::size_t Index = 0; Index < Descriptor.Operands.size(); ++Index) { + const OperandDescriptor &Operand = Descriptor.Operands[Index]; + const std::size_t Repetitions = + Operand.VariadicGroup ? Descriptor.MinimumVariadicRepetitions : 1; + for (std::size_t Repeat = 0; Repeat < Repetitions; ++Repeat) { + if (isDefRole(Operand.RegisterRole)) { + if (SawUse) { + return makeUnexpected(ErrorCode::InvalidArgument, + "register definition appears after an instruction use"); + } + ++MinimumDefs; + } else { + SawUse = true; + } + } + } + if (Descriptor.NumExplicitDefs != MinimumDefs) { + return makeUnexpected(ErrorCode::InvalidArgument, + "instruction descriptor explicit def count does not match its shape"); } for (std::size_t Index = 0; Index < Descriptor.Operands.size(); ++Index) { @@ -207,11 +242,62 @@ namespace { return {}; } +struct OperandShape final { + std::size_t VariadicBegin = 0; + std::size_t VariadicEnd = 0; + std::size_t Repetitions = 0; +}; + +[[nodiscard]] Expected<OperandShape> resolveOperandShape(const InstructionDescriptor &Descriptor, + std::size_t OperandCount) { + if (!Descriptor.Variadic) { + std::size_t RequiredCount = Descriptor.Operands.size(); + while (RequiredCount != 0 && Descriptor.Operands[RequiredCount - 1].Optional) + --RequiredCount; + if (OperandCount < RequiredCount || OperandCount > Descriptor.Operands.size()) { + return makeUnexpected(ErrorCode::VerificationError, + "instruction has an invalid explicit operand count"); + } + return OperandShape{}; + } + + const auto Begin = std::ranges::find_if( + Descriptor.Operands, [](const OperandDescriptor &Operand) { return Operand.VariadicGroup; }); + const auto End = std::ranges::find_if_not( + Begin, Descriptor.Operands.end(), + [](const OperandDescriptor &Operand) { return Operand.VariadicGroup; }); + const std::size_t VariadicBegin = + static_cast<std::size_t>(std::distance(Descriptor.Operands.begin(), Begin)); + const std::size_t VariadicEnd = + static_cast<std::size_t>(std::distance(Descriptor.Operands.begin(), End)); + const std::size_t GroupSize = VariadicEnd - VariadicBegin; + const std::size_t FixedCount = Descriptor.Operands.size() - GroupSize; + if (GroupSize == 0 || OperandCount < FixedCount) { + return makeUnexpected(ErrorCode::VerificationError, + "instruction has an invalid variadic operand count"); + } + const std::size_t VariableCount = OperandCount - FixedCount; + if (VariableCount % GroupSize != 0 || + VariableCount / GroupSize < Descriptor.MinimumVariadicRepetitions) { + return makeUnexpected(ErrorCode::VerificationError, + "instruction has an incomplete or undersized variadic operand group"); + } + return OperandShape{VariadicBegin, VariadicEnd, VariableCount / GroupSize}; +} + [[nodiscard]] const OperandDescriptor &descriptorForOperand(const InstructionDescriptor &Descriptor, + const OperandShape &Shape, std::size_t Index) { - if (Index < Descriptor.Operands.size()) + if (!Descriptor.Variadic) return Descriptor.Operands[Index]; - return Descriptor.Operands.back(); + if (Index < Shape.VariadicBegin) + return Descriptor.Operands[Index]; + const std::size_t GroupSize = Shape.VariadicEnd - Shape.VariadicBegin; + const std::size_t VariableCount = Shape.Repetitions * GroupSize; + if (Index < Shape.VariadicBegin + VariableCount) { + return Descriptor.Operands[Shape.VariadicBegin + (Index - Shape.VariadicBegin) % GroupSize]; + } + return Descriptor.Operands[Shape.VariadicEnd + (Index - Shape.VariadicBegin - VariableCount)]; } } // namespace @@ -221,6 +307,11 @@ OperandKindSet::OperandKindSet(std::initializer_list<MachineOperand::Kind> Kinds add(Kind); } +LLTKindSet::LLTKindSet(std::initializer_list<LLT::Kind> Kinds) noexcept { + for (const LLT::Kind Kind : Kinds) + add(Kind); +} + InstructionFlags::InstructionFlags(std::initializer_list<InstructionFlag> Flags) noexcept { for (const InstructionFlag Flag : Flags) set(Flag); @@ -290,31 +381,65 @@ const InstructionDescriptor *InstructionSet::descriptor(std::string_view Name) c Expected<void> InstructionSet::validateExplicitOperands(const InstructionDescriptor &Descriptor, std::span<const MachineOperand> Operands, const MachineRegisterInfo &RegInfo) const { - std::size_t RequiredCount = Descriptor.Operands.size(); - if (Descriptor.Variadic) - --RequiredCount; - else { - while (RequiredCount != 0 && Descriptor.Operands[RequiredCount - 1].Optional) - --RequiredCount; - } - - if (Operands.size() < RequiredCount || - (!Descriptor.Variadic && Operands.size() > Descriptor.Operands.size())) { - return makeUnexpected(ErrorCode::VerificationError, - "instruction has an invalid explicit operand count"); - } + auto Shape = resolveOperandShape(Descriptor, Operands.size()); + if (!Shape) + return std::unexpected(Shape.error()); + bool SawUse = false; + std::unordered_map<std::uint16_t, LLT> EqualityGroups; for (std::size_t Index = 0; Index < Operands.size(); ++Index) { const MachineOperand &Operand = Operands[Index]; if (Operand.isImplicit()) { return makeUnexpected(ErrorCode::VerificationError, "explicit operand sequence contains an implicit register"); } - const auto Validation = - validateOperand(descriptorForOperand(Descriptor, Index), Operand, RegInfo); + const OperandDescriptor &OperandDesc = descriptorForOperand(Descriptor, *Shape, Index); + const auto Validation = validateOperand(OperandDesc, Operand, RegInfo); if (!Validation) return std::unexpected(Validation.error()); + if (Operand.isRegister()) { + if (isDefRole(OperandDesc.RegisterRole)) { + if (SawUse) { + return makeUnexpected(ErrorCode::VerificationError, + "instruction register definition appears after a use"); + } + } else { + SawUse = true; + } + } else { + SawUse = true; + } + + if (!OperandDesc.TypeConstraint) + continue; + const Register *Reg = Operand.getIf<Register>(); + if (Reg == nullptr || !Reg->isVirtual()) { + return makeUnexpected(ErrorCode::VerificationError, + "typed instruction operand must use a virtual register"); + } + auto Info = RegInfo.virtualRegisterInfo(*Reg); + if (!Info) + return std::unexpected(Info.error()); + if (!Info->get().Type) { + return makeUnexpected(ErrorCode::VerificationError, + "typed instruction operand virtual register has no LLT"); + } + const LLT Type = *Info->get().Type; + if (!OperandDesc.TypeConstraint->Kinds.contains(Type.kind())) { + return makeUnexpected(ErrorCode::VerificationError, + "instruction operand LLT kind is not permitted by its descriptor"); + } + if (OperandDesc.TypeConstraint->EqualityGroup) { + const auto [Position, Inserted] = + EqualityGroups.emplace(*OperandDesc.TypeConstraint->EqualityGroup, Type); + if (!Inserted && Position->second != Type) { + return makeUnexpected(ErrorCode::VerificationError, + "instruction operands in one LLT group have different types"); + } + } } + if (Descriptor.VerifyExplicitOperands != nullptr) + return Descriptor.VerifyExplicitOperands(Descriptor.InstructionOpcode, Operands, RegInfo); return {}; } @@ -472,7 +597,12 @@ Expected<void> InstructionSet::validateOperand(const OperandDescriptor &Descript const bool IsUse = Operand.isUse(); const bool ExpectedDef = isDefRole(Descriptor.RegisterRole); const bool ExpectedUse = isUseRole(Descriptor.RegisterRole); - if (IsDef != ExpectedDef || IsUse != ExpectedUse) { + if (Descriptor.RegisterRole == RegisterOperandRole::Any) { + if (!IsDef && !IsUse) { + return makeUnexpected(ErrorCode::VerificationError, + "unclassified register operand must define or use its register"); + } + } else if (IsDef != ExpectedDef || IsUse != ExpectedUse) { return makeUnexpected(ErrorCode::VerificationError, "register operand def/use role does not match its descriptor"); } @@ -564,7 +694,12 @@ Expected<void> InstructionSet::validateInstruction(const MachineInstr &Instructi auto ImplicitValidation = validateImplicitOperands(*Descriptor, ImplicitOperands); if (!ImplicitValidation) return std::unexpected(ImplicitValidation.error()); - return validateMemOperands(*Descriptor, Instruction.memOperands()); + auto MemoryValidation = validateMemOperands(*Descriptor, Instruction.memOperands()); + if (!MemoryValidation) + return std::unexpected(MemoryValidation.error()); + if (Descriptor->VerifyInstructionSemantics != nullptr) + return Descriptor->VerifyInstructionSemantics(Instruction, RegInfo); + return {}; } Expected<std::vector<MachineOperand>> diff --git a/backend/lib/Target/Description/TargetDescriptionGenerator.cpp b/backend/lib/Target/Description/TargetDescriptionGenerator.cpp index 259c9fe..3c5e817 100644 --- a/backend/lib/Target/Description/TargetDescriptionGenerator.cpp +++ b/backend/lib/Target/Description/TargetDescriptionGenerator.cpp @@ -6,8 +6,10 @@ #include <algorithm> #include <array> +#include <bit> #include <cctype> #include <charconv> +#include <cstddef> #include <cstdint> #include <limits> #include <optional> @@ -92,6 +94,126 @@ struct SourceRegisterMask final { TextRange Range; }; +struct SourceMIROperandFlag final { + std::string Name; + std::uint32_t Value = 0; + TextRange Range; +}; + +struct SourceMIROperandFlags final { + std::uint32_t DirectMask = 0; + std::vector<SourceMIROperandFlag> Direct; + std::vector<SourceMIROperandFlag> Bitmask; + TextRange Range; +}; + +struct SourceCallingConvention final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::string IntegerRegisterClassSymbol; + std::string FloatingRegisterClassSymbol; + std::vector<std::string> IntegerArgumentRegisterSymbols; + std::vector<std::string> FloatingArgumentRegisterSymbols; + std::vector<std::string> IntegerReturnRegisterSymbols; + std::vector<std::string> FloatingReturnRegisterSymbols; + std::string PreservedMaskName; + std::uint32_t StackAlignmentBytes = 0; + std::uint32_t StackArgumentAlignmentBytes = 0; + std::uint32_t ShadowSpaceBytes = 0; + bool SupportsVarArgs = false; + bool SupportsTailCalls = false; + TextRange Range; +}; + +struct SourceNamedOperand final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + TextRange Range; +}; + +struct SourceImmediatePredicate final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::string Kind; + std::uint32_t Bits = 0; + std::uint64_t Alignment = 1; + bool NonZero = false; + std::vector<std::int64_t> AllowedValues; + TextRange Range; +}; + +struct SourceSchedulingClass final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::uint32_t MicroOps = 0; + std::uint32_t Latency = 0; + TextRange Range; +}; + +struct SourceEncodingCategory final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::uint32_t SizeInBytes = 0; + TextRange Range; +}; + +struct SourceAssemblyFormat final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + TextRange Range; +}; + +struct SourceOperand final { + std::vector<std::string> Kinds; + std::string RegisterRole = "none"; + std::optional<std::string> RegisterClassSymbol; + std::optional<std::string> RegisterBankSymbol; + std::optional<std::string> ImmediatePredicateSymbol; + std::string MemoryRole = "none"; + std::optional<std::uint32_t> DefaultTiedOperand; + bool EarlyClobber = false; + bool Optional = false; + bool VariadicGroup = false; + bool AllowSubReg = false; + std::optional<std::string> NameSymbol; + std::uint32_t AllowedTargetFlags = 0; + TextRange Range; +}; + +struct SourceImplicitRegister final { + std::string RegisterSymbol; + bool EarlyClobber = false; + bool Renamable = false; + TextRange Range; +}; + +struct SourceInstruction final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::string AssemblyMnemonic; + std::vector<SourceOperand> Operands; + std::uint32_t NumExplicitDefs = 0; + bool Variadic = false; + std::vector<SourceImplicitRegister> ImplicitDefs; + std::vector<SourceImplicitRegister> ImplicitUses; + bool AllowExtraImplicitOperands = false; + std::vector<std::string> Flags; + std::string SchedulingClassSymbol; + std::string EncodingCategorySymbol; + std::string AssemblyFormatSymbol; + bool RequiresMemoryOperands = false; + std::string Owner = "none"; + std::string Deadline = "emission"; + TextRange Range; +}; + struct DescriptionAST final { SourceTarget Target; std::vector<SourceRegisterUnit> RegisterUnits; @@ -99,6 +221,14 @@ struct DescriptionAST final { std::vector<SourceRegisterBank> RegisterBanks; std::vector<SourceRegisterClass> RegisterClasses; std::vector<SourceRegisterMask> RegisterMasks; + SourceMIROperandFlags MIROperandFlags; + std::vector<SourceCallingConvention> CallingConventions; + std::vector<SourceNamedOperand> NamedOperands; + std::vector<SourceImmediatePredicate> ImmediatePredicates; + std::vector<SourceSchedulingClass> SchedulingClasses; + std::vector<SourceEncodingCategory> EncodingCategories; + std::vector<SourceAssemblyFormat> AssemblyFormats; + std::vector<SourceInstruction> Instructions; }; struct NormalizedRegisterUnitLane final { @@ -147,6 +277,104 @@ struct NormalizedRegisterMask final { std::vector<std::uint32_t> PreservedRegisters; }; +struct NormalizedCallingConvention final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::uint32_t IntegerRegisterClass = 0; + std::uint32_t FloatingRegisterClass = 0; + std::vector<std::uint32_t> IntegerArgumentRegisters; + std::vector<std::uint32_t> FloatingArgumentRegisters; + std::vector<std::uint32_t> IntegerReturnRegisters; + std::vector<std::uint32_t> FloatingReturnRegisters; + std::string PreservedMaskName; + std::uint32_t StackAlignmentBytes = 0; + std::uint32_t StackArgumentAlignmentBytes = 0; + std::uint32_t ShadowSpaceBytes = 0; + bool SupportsVarArgs = false; + bool SupportsTailCalls = false; +}; + +struct NormalizedNamedOperand final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; +}; + +struct NormalizedImmediatePredicate final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + bool IsSigned = false; + std::uint32_t Bits = 0; + std::uint64_t Alignment = 1; + bool NonZero = false; + std::vector<std::int64_t> AllowedValues; +}; + +struct NormalizedSchedulingClass final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::uint32_t MicroOps = 0; + std::uint32_t Latency = 0; +}; + +struct NormalizedEncodingCategory final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::uint32_t SizeInBytes = 0; +}; + +struct NormalizedAssemblyFormat final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; +}; + +struct NormalizedOperand final { + std::vector<std::string> Kinds; + std::string RegisterRole; + std::optional<std::uint32_t> RegisterClass; + std::optional<std::uint32_t> RegisterBank; + std::optional<std::uint32_t> ImmediatePredicate; + std::string MemoryRole; + std::optional<std::uint32_t> DefaultTiedOperand; + bool EarlyClobber = false; + bool Optional = false; + bool VariadicGroup = false; + bool AllowSubReg = false; + std::optional<std::uint32_t> Name; + std::uint32_t AllowedTargetFlags = 0; +}; + +struct NormalizedImplicitRegister final { + std::uint32_t Register = 0; + bool EarlyClobber = false; + bool Renamable = false; +}; + +struct NormalizedInstruction final { + std::uint32_t ID = 0; + std::string Symbol; + std::string Name; + std::string AssemblyMnemonic; + std::vector<NormalizedOperand> Operands; + std::uint32_t NumExplicitDefs = 0; + bool Variadic = false; + std::vector<NormalizedImplicitRegister> ImplicitDefs; + std::vector<NormalizedImplicitRegister> ImplicitUses; + bool AllowExtraImplicitOperands = false; + std::vector<std::string> Flags; + std::uint32_t SchedulingClass = 0; + std::uint32_t EncodingCategory = 0; + std::uint32_t AssemblyFormat = 0; + bool RequiresMemoryOperands = false; + std::string Owner; + std::string Deadline; +}; + struct NormalizedTargetModel final { SourceTarget Target; std::vector<SourceRegisterUnit> RegisterUnits; @@ -154,6 +382,14 @@ struct NormalizedTargetModel final { std::vector<NormalizedRegisterBank> RegisterBanks; std::vector<NormalizedRegisterClass> RegisterClasses; std::vector<NormalizedRegisterMask> RegisterMasks; + SourceMIROperandFlags MIROperandFlags; + std::vector<NormalizedCallingConvention> CallingConventions; + std::vector<NormalizedNamedOperand> NamedOperands; + std::vector<NormalizedImmediatePredicate> ImmediatePredicates; + std::vector<NormalizedSchedulingClass> SchedulingClasses; + std::vector<NormalizedEncodingCategory> EncodingCategories; + std::vector<NormalizedAssemblyFormat> AssemblyFormats; + std::vector<NormalizedInstruction> Instructions; }; [[nodiscard]] std::string lowerASCII(std::string_view Value) { @@ -181,6 +417,21 @@ struct NormalizedTargetModel final { }); } +[[nodiscard]] bool isAssemblyMnemonic(std::string_view Value) noexcept { + if (Value.empty()) + return false; + if (std::islower(static_cast<unsigned char>(Value.front())) == 0) + return false; + if (std::islower(static_cast<unsigned char>(Value.back())) == 0 && + std::isdigit(static_cast<unsigned char>(Value.back())) == 0) + return false; + return std::ranges::all_of(Value, [](char Character) { + const unsigned char Code = static_cast<unsigned char>(Character); + return std::islower(Code) != 0 || std::isdigit(Code) != 0 || Character == '.' || + Character == '_'; + }); +} + [[nodiscard]] std::string upperIdentifier(std::string_view Value) { std::string Result; Result.reserve(Value.size()); @@ -239,7 +490,9 @@ public: return std::nullopt; if (!checkKeys(*Root, {"schema", "target", "register_units", "registers", "register_banks", - "register_classes", "register_masks"}, + "register_classes", "register_masks", "mir_operand_flags", "named_operands", + "immediate_predicates", "scheduling_classes", "encoding_categories", + "assembly_formats", "calling_conventions", "instructions"}, "target description root")) { return std::nullopt; } @@ -248,7 +501,7 @@ public: if (SchemaNode == nullptr) return std::nullopt; const auto Schema = scalar(*SchemaNode, "target description schema"); - if (!Schema || *Schema != "rcc-target-description-v1") { + if (!Schema || *Schema != "rcc-target-description-v2") { if (Schema) fail(SchemaNode->range(), "unsupported target description schema"); return std::nullopt; @@ -264,13 +517,40 @@ public: const yaml::Node *ClassesNode = requiredNode(*Root, "register_classes", "target description root"); const yaml::Node *MasksNode = requiredNode(*Root, "register_masks", "target description root"); + const yaml::Node *MIROperandFlagsNode = optionalNode(*Root, "mir_operand_flags"); + const yaml::Node *NamedOperandsNode = + requiredNode(*Root, "named_operands", "target description root"); + const yaml::Node *ImmediatePredicatesNode = + requiredNode(*Root, "immediate_predicates", "target description root"); + const yaml::Node *SchedulingClassesNode = + requiredNode(*Root, "scheduling_classes", "target description root"); + const yaml::Node *EncodingCategoriesNode = + requiredNode(*Root, "encoding_categories", "target description root"); + const yaml::Node *AssemblyFormatsNode = + requiredNode(*Root, "assembly_formats", "target description root"); + const yaml::Node *CallingConventionsNode = + requiredNode(*Root, "calling_conventions", "target description root"); + const yaml::Node *InstructionsNode = + requiredNode(*Root, "instructions", "target description root"); if (UnitsNode == nullptr || RegistersNode == nullptr || BanksNode == nullptr || - ClassesNode == nullptr || MasksNode == nullptr || + ClassesNode == nullptr || MasksNode == nullptr || NamedOperandsNode == nullptr || + ImmediatePredicatesNode == nullptr || SchedulingClassesNode == nullptr || + EncodingCategoriesNode == nullptr || AssemblyFormatsNode == nullptr || + CallingConventionsNode == nullptr || InstructionsNode == nullptr || !parseRegisterUnits(*UnitsNode, Result.RegisterUnits) || !parseRegisters(*RegistersNode, Result.Registers) || !parseRegisterBanks(*BanksNode, Result.RegisterBanks) || !parseRegisterClasses(*ClassesNode, Result.RegisterClasses) || - !parseRegisterMasks(*MasksNode, Result.RegisterMasks)) { + !parseRegisterMasks(*MasksNode, Result.RegisterMasks) || + (MIROperandFlagsNode != nullptr && + !parseMIROperandFlags(*MIROperandFlagsNode, Result.MIROperandFlags)) || + !parseNamedOperands(*NamedOperandsNode, Result.NamedOperands) || + !parseImmediatePredicates(*ImmediatePredicatesNode, Result.ImmediatePredicates) || + !parseSchedulingClasses(*SchedulingClassesNode, Result.SchedulingClasses) || + !parseEncodingCategories(*EncodingCategoriesNode, Result.EncodingCategories) || + !parseAssemblyFormats(*AssemblyFormatsNode, Result.AssemblyFormats) || + !parseCallingConventions(*CallingConventionsNode, Result.CallingConventions) || + !parseInstructions(*InstructionsNode, Result.Instructions)) { return std::nullopt; } return Result; @@ -378,6 +658,21 @@ private: return static_cast<std::uint32_t>(*Value); } + [[nodiscard]] std::optional<std::int64_t> signedInteger(const yaml::Node &Node, + std::string_view Context) { + const auto Text = scalar(Node, Context); + if (!Text) + return std::nullopt; + std::int64_t Result = 0; + const auto [End, Error] = + std::from_chars(Text->data(), Text->data() + Text->size(), Result, 10); + if (Error != std::errc{} || End != Text->data() + Text->size()) { + fail(Node.range(), std::string(Context) + " must be a signed decimal integer"); + return std::nullopt; + } + return Result; + } + [[nodiscard]] std::optional<bool> boolean(const yaml::Node &Node, std::string_view Context) { const auto Text = scalar(Node, Context); if (!Text) @@ -407,6 +702,23 @@ private: return Result; } + [[nodiscard]] std::optional<std::vector<std::int64_t>> + signedIntegerSequence(const yaml::Node &Node, std::string_view Context) { + if (!requireSequence(&Node, Context)) + return std::nullopt; + std::vector<std::int64_t> Result; + for (const yaml::NodeID Value : Node.sequence()) { + const yaml::Node *Element = Input.node(Value); + if (Element == nullptr) + return std::nullopt; + const auto Parsed = signedInteger(*Element, Context); + if (!Parsed) + return std::nullopt; + Result.push_back(*Parsed); + } + return Result; + } + [[nodiscard]] bool parseTarget(const yaml::Node &Node, SourceTarget &Result) { if (!requireMapping(&Node, "target")) return false; @@ -684,6 +996,588 @@ private: return true; } + [[nodiscard]] bool parseMIROperandFlagSequence(const yaml::Node &Node, std::string_view Context, + std::vector<SourceMIROperandFlag> &Result) { + if (!requireSequence(&Node, Context)) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, Context) || !checkKeys(*Element, {"name", "value"}, Context)) { + return false; + } + const auto Name = requiredScalar(*Element, "name", Context); + const yaml::Node *ValueNode = requiredNode(*Element, "value", Context); + if (!Name || ValueNode == nullptr) + return false; + const auto Value = unsignedInteger32(*ValueNode, std::string(Context) + " value"); + if (!Value) + return false; + Result.push_back({.Name = *Name, .Value = *Value, .Range = Element->range()}); + } + return true; + } + + [[nodiscard]] bool parseMIROperandFlags(const yaml::Node &Node, SourceMIROperandFlags &Result) { + if (!requireMapping(&Node, "MIR operand flags") || + !checkKeys(Node, {"direct_mask", "direct", "bitmask"}, "MIR operand flags")) { + return false; + } + const yaml::Node *DirectMaskNode = requiredNode(Node, "direct_mask", "MIR operand flags"); + const yaml::Node *DirectNode = requiredNode(Node, "direct", "MIR operand flags"); + const yaml::Node *BitmaskNode = requiredNode(Node, "bitmask", "MIR operand flags"); + if (DirectMaskNode == nullptr || DirectNode == nullptr || BitmaskNode == nullptr) + return false; + const auto DirectMask = unsignedInteger32(*DirectMaskNode, "MIR operand flag direct_mask"); + if (!DirectMask || + !parseMIROperandFlagSequence(*DirectNode, "direct MIR operand flag", Result.Direct) || + !parseMIROperandFlagSequence(*BitmaskNode, "bitmask MIR operand flag", Result.Bitmask)) { + return false; + } + Result.DirectMask = *DirectMask; + Result.Range = Node.range(); + return true; + } + + [[nodiscard]] bool parseNamedOperands(const yaml::Node &Node, + std::vector<SourceNamedOperand> &Result) { + if (!requireSequence(&Node, "named_operands")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "named operand")) + return false; + if (!checkKeys(*Element, {"id", "symbol", "name"}, "named operand")) + return false; + const yaml::Node *IDNode = requiredNode(*Element, "id", "named operand"); + const auto Symbol = requiredScalar(*Element, "symbol", "named operand"); + const auto Name = requiredScalar(*Element, "name", "named operand"); + if (IDNode == nullptr || !Symbol || !Name) + return false; + const auto ID = unsignedInteger32(*IDNode, "named operand id"); + if (!ID) + return false; + Result.push_back({.ID = *ID, .Symbol = *Symbol, .Name = *Name, .Range = Element->range()}); + } + return true; + } + + [[nodiscard]] bool parseImmediatePredicates(const yaml::Node &Node, + std::vector<SourceImmediatePredicate> &Result) { + if (!requireSequence(&Node, "immediate_predicates")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "immediate predicate")) + return false; + if (!checkKeys( + *Element, + {"id", "symbol", "name", "kind", "bits", "alignment", "nonzero", "allowed_values"}, + "immediate predicate")) { + return false; + } + const yaml::Node *IDNode = requiredNode(*Element, "id", "immediate predicate"); + const auto Symbol = requiredScalar(*Element, "symbol", "immediate predicate"); + const auto Name = requiredScalar(*Element, "name", "immediate predicate"); + const auto Kind = requiredScalar(*Element, "kind", "immediate predicate"); + const yaml::Node *BitsNode = requiredNode(*Element, "bits", "immediate predicate"); + if (IDNode == nullptr || !Symbol || !Name || !Kind || BitsNode == nullptr) + return false; + const auto ID = unsignedInteger32(*IDNode, "immediate predicate id"); + const auto Bits = unsignedInteger32(*BitsNode, "immediate predicate bits"); + if (!ID || !Bits) + return false; + SourceImmediatePredicate Predicate{ + .ID = *ID, + .Symbol = *Symbol, + .Name = *Name, + .Kind = *Kind, + .Bits = *Bits, + .Alignment = 1, + .NonZero = false, + .AllowedValues = {}, + .Range = Element->range(), + }; + if (const yaml::Node *Alignment = optionalNode(*Element, "alignment")) { + const auto Value = unsignedInteger(*Alignment, "immediate predicate alignment"); + if (!Value) + return false; + Predicate.Alignment = *Value; + } + if (const yaml::Node *NonZero = optionalNode(*Element, "nonzero")) { + const auto Value = boolean(*NonZero, "immediate predicate nonzero"); + if (!Value) + return false; + Predicate.NonZero = *Value; + } + if (const yaml::Node *AllowedValues = optionalNode(*Element, "allowed_values")) { + const auto Values = + signedIntegerSequence(*AllowedValues, "immediate predicate allowed_values"); + if (!Values || Values->empty()) { + if (Values) + fail(AllowedValues->range(), "immediate predicate allowed_values must be nonempty"); + return false; + } + Predicate.AllowedValues = *Values; + } + Result.push_back(std::move(Predicate)); + } + return true; + } + + [[nodiscard]] bool parseSchedulingClasses(const yaml::Node &Node, + std::vector<SourceSchedulingClass> &Result) { + if (!requireSequence(&Node, "scheduling_classes")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "scheduling class")) + return false; + if (!checkKeys(*Element, {"id", "symbol", "name", "micro_ops", "latency"}, + "scheduling class")) { + return false; + } + const yaml::Node *IDNode = requiredNode(*Element, "id", "scheduling class"); + const auto Symbol = requiredScalar(*Element, "symbol", "scheduling class"); + const auto Name = requiredScalar(*Element, "name", "scheduling class"); + const yaml::Node *MicroOpsNode = requiredNode(*Element, "micro_ops", "scheduling class"); + const yaml::Node *LatencyNode = requiredNode(*Element, "latency", "scheduling class"); + if (IDNode == nullptr || !Symbol || !Name || MicroOpsNode == nullptr || + LatencyNode == nullptr) + return false; + const auto ID = unsignedInteger32(*IDNode, "scheduling class id"); + const auto MicroOps = unsignedInteger32(*MicroOpsNode, "scheduling class micro_ops"); + const auto Latency = unsignedInteger32(*LatencyNode, "scheduling class latency"); + if (!ID || !MicroOps || !Latency) + return false; + Result.push_back({ + .ID = *ID, + .Symbol = *Symbol, + .Name = *Name, + .MicroOps = *MicroOps, + .Latency = *Latency, + .Range = Element->range(), + }); + } + return true; + } + + [[nodiscard]] bool parseEncodingCategories(const yaml::Node &Node, + std::vector<SourceEncodingCategory> &Result) { + if (!requireSequence(&Node, "encoding_categories")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "encoding category")) + return false; + if (!checkKeys(*Element, {"id", "symbol", "name", "size_bytes"}, "encoding category")) + return false; + const yaml::Node *IDNode = requiredNode(*Element, "id", "encoding category"); + const auto Symbol = requiredScalar(*Element, "symbol", "encoding category"); + const auto Name = requiredScalar(*Element, "name", "encoding category"); + const yaml::Node *SizeNode = requiredNode(*Element, "size_bytes", "encoding category"); + if (IDNode == nullptr || !Symbol || !Name || SizeNode == nullptr) + return false; + const auto ID = unsignedInteger32(*IDNode, "encoding category id"); + const auto Size = unsignedInteger32(*SizeNode, "encoding category size_bytes"); + if (!ID || !Size) + return false; + Result.push_back({ + .ID = *ID, + .Symbol = *Symbol, + .Name = *Name, + .SizeInBytes = *Size, + .Range = Element->range(), + }); + } + return true; + } + + [[nodiscard]] bool parseAssemblyFormats(const yaml::Node &Node, + std::vector<SourceAssemblyFormat> &Result) { + if (!requireSequence(&Node, "assembly_formats")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "assembly format")) + return false; + if (!checkKeys(*Element, {"id", "symbol", "name"}, "assembly format")) + return false; + const yaml::Node *IDNode = requiredNode(*Element, "id", "assembly format"); + const auto Symbol = requiredScalar(*Element, "symbol", "assembly format"); + const auto Name = requiredScalar(*Element, "name", "assembly format"); + if (IDNode == nullptr || !Symbol || !Name) + return false; + const auto ID = unsignedInteger32(*IDNode, "assembly format id"); + if (!ID) + return false; + Result.push_back({.ID = *ID, .Symbol = *Symbol, .Name = *Name, .Range = Element->range()}); + } + return true; + } + + [[nodiscard]] bool parseCallingConventions(const yaml::Node &Node, + std::vector<SourceCallingConvention> &Result) { + if (!requireSequence(&Node, "calling_conventions")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "calling convention")) + return false; + if (!checkKeys(*Element, + {"id", "symbol", "name", "integer_register_class", "floating_register_class", + "integer_argument_registers", "floating_argument_registers", + "integer_return_registers", "floating_return_registers", "preserved_mask", + "stack_alignment_bytes", "stack_argument_alignment_bytes", + "shadow_space_bytes", "supports_varargs", "supports_tail_calls"}, + "calling convention")) { + return false; + } + const yaml::Node *IDNode = requiredNode(*Element, "id", "calling convention"); + const auto Symbol = requiredScalar(*Element, "symbol", "calling convention"); + const auto Name = requiredScalar(*Element, "name", "calling convention"); + const auto IntegerClass = + requiredScalar(*Element, "integer_register_class", "calling convention"); + const auto FloatingClass = + requiredScalar(*Element, "floating_register_class", "calling convention"); + const yaml::Node *IntegerArguments = + requiredNode(*Element, "integer_argument_registers", "calling convention"); + const yaml::Node *FloatingArguments = + requiredNode(*Element, "floating_argument_registers", "calling convention"); + const yaml::Node *IntegerReturns = + requiredNode(*Element, "integer_return_registers", "calling convention"); + const yaml::Node *FloatingReturns = + requiredNode(*Element, "floating_return_registers", "calling convention"); + const auto PreservedMask = requiredScalar(*Element, "preserved_mask", "calling convention"); + const yaml::Node *StackAlignment = + requiredNode(*Element, "stack_alignment_bytes", "calling convention"); + const yaml::Node *StackArgumentAlignment = + requiredNode(*Element, "stack_argument_alignment_bytes", "calling convention"); + const yaml::Node *ShadowSpace = + requiredNode(*Element, "shadow_space_bytes", "calling convention"); + const yaml::Node *SupportsVarArgs = + requiredNode(*Element, "supports_varargs", "calling convention"); + const yaml::Node *SupportsTailCalls = + requiredNode(*Element, "supports_tail_calls", "calling convention"); + if (IDNode == nullptr || !Symbol || !Name || !IntegerClass || !FloatingClass || + IntegerArguments == nullptr || FloatingArguments == nullptr || + IntegerReturns == nullptr || FloatingReturns == nullptr || !PreservedMask || + StackAlignment == nullptr || StackArgumentAlignment == nullptr || + ShadowSpace == nullptr || SupportsVarArgs == nullptr || SupportsTailCalls == nullptr) { + return false; + } + const auto ID = unsignedInteger32(*IDNode, "calling convention id"); + const auto IntegerArgumentList = + scalarSequence(*IntegerArguments, "calling convention integer arguments"); + const auto FloatingArgumentList = + scalarSequence(*FloatingArguments, "calling convention floating arguments"); + const auto IntegerReturnList = + scalarSequence(*IntegerReturns, "calling convention integer returns"); + const auto FloatingReturnList = + scalarSequence(*FloatingReturns, "calling convention floating returns"); + const auto StackAlignmentValue = + unsignedInteger32(*StackAlignment, "calling convention stack alignment"); + const auto StackArgumentAlignmentValue = + unsignedInteger32(*StackArgumentAlignment, "calling convention stack argument alignment"); + const auto ShadowSpaceValue = + unsignedInteger32(*ShadowSpace, "calling convention shadow space"); + const auto SupportsVarArgsValue = boolean(*SupportsVarArgs, "calling convention varargs"); + const auto SupportsTailCallsValue = + boolean(*SupportsTailCalls, "calling convention tail calls"); + if (!ID || !IntegerArgumentList || !FloatingArgumentList || !IntegerReturnList || + !FloatingReturnList || !StackAlignmentValue || !StackArgumentAlignmentValue || + !ShadowSpaceValue || !SupportsVarArgsValue || !SupportsTailCallsValue) { + return false; + } + Result.push_back({ + .ID = *ID, + .Symbol = *Symbol, + .Name = *Name, + .IntegerRegisterClassSymbol = *IntegerClass, + .FloatingRegisterClassSymbol = *FloatingClass, + .IntegerArgumentRegisterSymbols = *IntegerArgumentList, + .FloatingArgumentRegisterSymbols = *FloatingArgumentList, + .IntegerReturnRegisterSymbols = *IntegerReturnList, + .FloatingReturnRegisterSymbols = *FloatingReturnList, + .PreservedMaskName = *PreservedMask, + .StackAlignmentBytes = *StackAlignmentValue, + .StackArgumentAlignmentBytes = *StackArgumentAlignmentValue, + .ShadowSpaceBytes = *ShadowSpaceValue, + .SupportsVarArgs = *SupportsVarArgsValue, + .SupportsTailCalls = *SupportsTailCallsValue, + .Range = Element->range(), + }); + } + return true; + } + + [[nodiscard]] std::optional<SourceOperand> parseOperand(const yaml::Node &Node) { + if (!requireMapping(&Node, "instruction operand")) + return std::nullopt; + if (!checkKeys(Node, + {"kinds", "role", "register_class", "register_bank", "immediate_predicate", + "memory_role", "default_tied_operand", "early_clobber", "optional", + "variadic_group", "allow_subreg", "name", "allowed_target_flags"}, + "instruction operand")) { + return std::nullopt; + } + const yaml::Node *KindsNode = requiredNode(Node, "kinds", "instruction operand"); + if (KindsNode == nullptr) + return std::nullopt; + const auto Kinds = scalarSequence(*KindsNode, "instruction operand kinds"); + if (!Kinds) + return std::nullopt; + + SourceOperand Result; + Result.Kinds = *Kinds; + Result.Range = Node.range(); + if (const yaml::Node *Role = optionalNode(Node, "role")) { + const auto Value = scalar(*Role, "instruction operand role"); + if (!Value) + return std::nullopt; + Result.RegisterRole = *Value; + } + if (const yaml::Node *RegisterClass = optionalNode(Node, "register_class")) { + const auto Value = scalar(*RegisterClass, "instruction operand register_class"); + if (!Value) + return std::nullopt; + Result.RegisterClassSymbol = *Value; + } + if (const yaml::Node *RegisterBank = optionalNode(Node, "register_bank")) { + const auto Value = scalar(*RegisterBank, "instruction operand register_bank"); + if (!Value) + return std::nullopt; + Result.RegisterBankSymbol = *Value; + } + if (const yaml::Node *Predicate = optionalNode(Node, "immediate_predicate")) { + const auto Value = scalar(*Predicate, "instruction operand immediate_predicate"); + if (!Value) + return std::nullopt; + Result.ImmediatePredicateSymbol = *Value; + } + if (const yaml::Node *MemoryRole = optionalNode(Node, "memory_role")) { + const auto Value = scalar(*MemoryRole, "instruction operand memory_role"); + if (!Value) + return std::nullopt; + Result.MemoryRole = *Value; + } + if (const yaml::Node *Tie = optionalNode(Node, "default_tied_operand")) { + const auto Value = unsignedInteger32(*Tie, "instruction operand default_tied_operand"); + if (!Value) + return std::nullopt; + Result.DefaultTiedOperand = *Value; + } + if (const yaml::Node *EarlyClobber = optionalNode(Node, "early_clobber")) { + const auto Value = boolean(*EarlyClobber, "instruction operand early_clobber"); + if (!Value) + return std::nullopt; + Result.EarlyClobber = *Value; + } + if (const yaml::Node *Optional = optionalNode(Node, "optional")) { + const auto Value = boolean(*Optional, "instruction operand optional"); + if (!Value) + return std::nullopt; + Result.Optional = *Value; + } + if (const yaml::Node *VariadicGroup = optionalNode(Node, "variadic_group")) { + const auto Value = boolean(*VariadicGroup, "instruction operand variadic_group"); + if (!Value) + return std::nullopt; + Result.VariadicGroup = *Value; + } + if (const yaml::Node *AllowSubReg = optionalNode(Node, "allow_subreg")) { + const auto Value = boolean(*AllowSubReg, "instruction operand allow_subreg"); + if (!Value) + return std::nullopt; + Result.AllowSubReg = *Value; + } + if (const yaml::Node *Name = optionalNode(Node, "name")) { + const auto Value = scalar(*Name, "instruction operand name"); + if (!Value) + return std::nullopt; + Result.NameSymbol = *Value; + } + if (const yaml::Node *TargetFlags = optionalNode(Node, "allowed_target_flags")) { + const auto Value = + unsignedInteger32(*TargetFlags, "instruction operand allowed_target_flags"); + if (!Value) + return std::nullopt; + Result.AllowedTargetFlags = *Value; + } + return Result; + } + + [[nodiscard]] std::optional<std::vector<SourceOperand>> parseOperands(const yaml::Node &Node) { + if (!requireSequence(&Node, "instruction operands")) + return std::nullopt; + std::vector<SourceOperand> Result; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (Element == nullptr) + return std::nullopt; + const auto Operand = parseOperand(*Element); + if (!Operand) + return std::nullopt; + Result.push_back(*Operand); + } + return Result; + } + + [[nodiscard]] std::optional<SourceImplicitRegister> + parseImplicitRegister(const yaml::Node &Node, std::string_view Context) { + if (!requireMapping(&Node, Context)) + return std::nullopt; + if (!checkKeys(Node, {"register", "early_clobber", "renamable"}, Context)) + return std::nullopt; + const auto Register = requiredScalar(Node, "register", Context); + if (!Register) + return std::nullopt; + SourceImplicitRegister Result{ + .RegisterSymbol = *Register, + .Range = Node.range(), + }; + if (const yaml::Node *EarlyClobber = optionalNode(Node, "early_clobber")) { + const auto Value = boolean(*EarlyClobber, std::string(Context) + " early_clobber"); + if (!Value) + return std::nullopt; + Result.EarlyClobber = *Value; + } + if (const yaml::Node *Renamable = optionalNode(Node, "renamable")) { + const auto Value = boolean(*Renamable, std::string(Context) + " renamable"); + if (!Value) + return std::nullopt; + Result.Renamable = *Value; + } + return Result; + } + + [[nodiscard]] std::optional<std::vector<SourceImplicitRegister>> + parseImplicitRegisters(const yaml::Node &Node, std::string_view Context) { + if (!requireSequence(&Node, Context)) + return std::nullopt; + std::vector<SourceImplicitRegister> Result; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (Element == nullptr) + return std::nullopt; + const auto Register = parseImplicitRegister(*Element, Context); + if (!Register) + return std::nullopt; + Result.push_back(*Register); + } + return Result; + } + + [[nodiscard]] bool parseInstructions(const yaml::Node &Node, + std::vector<SourceInstruction> &Result) { + if (!requireSequence(&Node, "instructions")) + return false; + for (const yaml::NodeID ElementID : Node.sequence()) { + const yaml::Node *Element = Input.node(ElementID); + if (!requireMapping(Element, "instruction")) + return false; + if (!checkKeys(*Element, + {"id", "symbol", "name", "assembly_mnemonic", "operands", "num_explicit_defs", + "variadic", "implicit_defs", "implicit_uses", "allow_extra_implicit_operands", + "flags", "scheduling_class", "encoding_category", "assembly_format", + "requires_memory_operands", "owner", "deadline"}, + "instruction")) { + return false; + } + const yaml::Node *IDNode = requiredNode(*Element, "id", "instruction"); + const auto Symbol = requiredScalar(*Element, "symbol", "instruction"); + const auto Name = requiredScalar(*Element, "name", "instruction"); + const yaml::Node *OperandsNode = requiredNode(*Element, "operands", "instruction"); + const yaml::Node *DefsNode = requiredNode(*Element, "num_explicit_defs", "instruction"); + const yaml::Node *FlagsNode = requiredNode(*Element, "flags", "instruction"); + if (IDNode == nullptr || !Symbol || !Name || OperandsNode == nullptr || DefsNode == nullptr || + FlagsNode == nullptr) { + return false; + } + const auto ID = unsignedInteger32(*IDNode, "instruction id"); + const auto Defs = unsignedInteger32(*DefsNode, "instruction num_explicit_defs"); + const auto Operands = parseOperands(*OperandsNode); + const auto Flags = scalarSequence(*FlagsNode, "instruction flags"); + if (!ID || !Defs || !Operands || !Flags) + return false; + SourceInstruction Instruction; + Instruction.ID = *ID; + Instruction.Symbol = *Symbol; + Instruction.Name = *Name; + Instruction.Operands = *Operands; + Instruction.NumExplicitDefs = *Defs; + Instruction.Flags = *Flags; + Instruction.Range = Element->range(); + if (const yaml::Node *Mnemonic = optionalNode(*Element, "assembly_mnemonic")) { + const auto Value = scalar(*Mnemonic, "instruction assembly_mnemonic"); + if (!Value) + return false; + Instruction.AssemblyMnemonic = *Value; + } + if (const yaml::Node *SchedulingClass = optionalNode(*Element, "scheduling_class")) { + const auto Value = scalar(*SchedulingClass, "instruction scheduling_class"); + if (!Value) + return false; + Instruction.SchedulingClassSymbol = *Value; + } + if (const yaml::Node *EncodingCategory = optionalNode(*Element, "encoding_category")) { + const auto Value = scalar(*EncodingCategory, "instruction encoding_category"); + if (!Value) + return false; + Instruction.EncodingCategorySymbol = *Value; + } + if (const yaml::Node *AssemblyFormat = optionalNode(*Element, "assembly_format")) { + const auto Value = scalar(*AssemblyFormat, "instruction assembly_format"); + if (!Value) + return false; + Instruction.AssemblyFormatSymbol = *Value; + } + if (const yaml::Node *Variadic = optionalNode(*Element, "variadic")) { + const auto Value = boolean(*Variadic, "instruction variadic"); + if (!Value) + return false; + Instruction.Variadic = *Value; + } + if (const yaml::Node *ImplicitDefs = optionalNode(*Element, "implicit_defs")) { + const auto Values = parseImplicitRegisters(*ImplicitDefs, "instruction implicit_defs"); + if (!Values) + return false; + Instruction.ImplicitDefs = *Values; + } + if (const yaml::Node *ImplicitUses = optionalNode(*Element, "implicit_uses")) { + const auto Values = parseImplicitRegisters(*ImplicitUses, "instruction implicit_uses"); + if (!Values) + return false; + Instruction.ImplicitUses = *Values; + } + if (const yaml::Node *AllowExtra = optionalNode(*Element, "allow_extra_implicit_operands")) { + const auto Value = boolean(*AllowExtra, "instruction allow_extra_implicit_operands"); + if (!Value) + return false; + Instruction.AllowExtraImplicitOperands = *Value; + } + if (const yaml::Node *MemoryOperands = optionalNode(*Element, "requires_memory_operands")) { + const auto Value = boolean(*MemoryOperands, "instruction requires_memory_operands"); + if (!Value) + return false; + Instruction.RequiresMemoryOperands = *Value; + } + if (const yaml::Node *Owner = optionalNode(*Element, "owner")) { + const auto Value = scalar(*Owner, "instruction owner"); + if (!Value) + return false; + Instruction.Owner = *Value; + } + if (const yaml::Node *Deadline = optionalNode(*Element, "deadline")) { + const auto Value = scalar(*Deadline, "instruction deadline"); + if (!Value) + return false; + Instruction.Deadline = *Value; + } + Result.push_back(std::move(Instruction)); + } + return true; + } + [[nodiscard]] const yaml::Node *optionalNode(const yaml::Node &Mapping, std::string_view Key) const noexcept { const std::optional<yaml::NodeID> Value = Mapping.mappingValue(Key); @@ -694,6 +1588,146 @@ private: std::vector<TextDiagnostic> Diagnostics; }; +[[nodiscard]] std::optional<std::string_view> +operandKindEnumerator(std::string_view Value) noexcept { + static constexpr std::array<std::pair<std::string_view, std::string_view>, 22> Kinds = {{ + {"register", "Register"}, + {"immediate", "Immediate"}, + {"integer_immediate", "IntegerImmediate"}, + {"floating_immediate", "FloatingImmediate"}, + {"basic_block", "BasicBlock"}, + {"frame_index", "FrameIndex"}, + {"constant_pool_index", "ConstantPoolIndex"}, + {"jump_table_index", "JumpTableIndex"}, + {"global_symbol", "GlobalSymbol"}, + {"external_symbol", "ExternalSymbol"}, + {"block_address", "BlockAddress"}, + {"register_mask", "RegisterMask"}, + {"live_out_register_mask", "LiveOutRegisterMask"}, + {"metadata", "Metadata"}, + {"target_index", "TargetIndex"}, + {"mc_symbol", "MCSymbol"}, + {"cfi_index", "CFIIndex"}, + {"intrinsic", "Intrinsic"}, + {"predicate", "Predicate"}, + {"shuffle_mask", "ShuffleMask"}, + {"debug_instr_ref", "DebugInstrRef"}, + {"lane_mask", "LaneMask"}, + }}; + const auto Position = std::ranges::find(Kinds, Value, &decltype(Kinds)::value_type::first); + if (Position == Kinds.end()) + return std::nullopt; + return Position->second; +} + +[[nodiscard]] std::optional<std::string_view> +registerRoleEnumerator(std::string_view Value) noexcept { + if (Value == "none") + return "None"; + if (Value == "def") + return "Def"; + if (Value == "use") + return "Use"; + if (Value == "def_use") + return "DefUse"; + return std::nullopt; +} + +[[nodiscard]] std::optional<std::string_view> +memoryRoleEnumerator(std::string_view Value) noexcept { + if (Value == "none") + return "None"; + if (Value == "address") + return "Address"; + if (Value == "value") + return "Value"; + if (Value == "size") + return "Size"; + if (Value == "ordering") + return "Ordering"; + return std::nullopt; +} + +[[nodiscard]] std::optional<std::string_view> +instructionFlagEnumerator(std::string_view Value) noexcept { + static constexpr std::array<std::pair<std::string_view, std::string_view>, 23> Flags = {{ + {"terminator", "Terminator"}, + {"branch", "Branch"}, + {"indirect_branch", "IndirectBranch"}, + {"call", "Call"}, + {"return", "Return"}, + {"barrier", "Barrier"}, + {"may_load", "MayLoad"}, + {"may_store", "MayStore"}, + {"has_side_effects", "HasSideEffects"}, + {"pseudo", "Pseudo"}, + {"meta", "Meta"}, + {"allowed_pre_legalizer", "AllowedPreLegalizer"}, + {"produces_code", "ProducesCode"}, + {"commutable", "Commutable"}, + {"rematerializable", "Rematerializable"}, + {"predicable", "Predicable"}, + {"not_duplicable", "NotDuplicable"}, + {"convergent", "Convergent"}, + {"unmodeled_side_effects", "UnmodeledSideEffects"}, + {"phi", "Phi"}, + {"fake_use", "FakeUse"}, + {"generic", "Generic"}, + {"terminal_emission", "TerminalEmission"}, + }}; + const auto Position = std::ranges::find(Flags, Value, &decltype(Flags)::value_type::first); + if (Position == Flags.end()) + return std::nullopt; + return Position->second; +} + +[[nodiscard]] std::optional<std::string_view> +pseudoOwnerEnumerator(std::string_view Value) noexcept { + static constexpr std::array<std::pair<std::string_view, std::string_view>, 11> Owners = {{ + {"none", "None"}, + {"legalizer", "Legalizer"}, + {"register_bank_select", "RegisterBankSelect"}, + {"instruction_select", "InstructionSelect"}, + {"phi_elimination", "PhiElimination"}, + {"two_address_rewrite", "TwoAddressRewrite"}, + {"register_allocator", "RegisterAllocator"}, + {"pre_pei_expansion", "PrePEIExpansion"}, + {"prologue_epilogue_insertion", "PrologueEpilogueInsertion"}, + {"post_ra_expansion", "PostRAExpansion"}, + {"finalization", "Finalization"}, + }}; + if (Value == "asm_printer") + return "AsmPrinter"; + const auto Position = std::ranges::find(Owners, Value, &decltype(Owners)::value_type::first); + if (Position == Owners.end()) + return std::nullopt; + return Position->second; +} + +[[nodiscard]] std::optional<std::string_view> +pipelineStageEnumerator(std::string_view Value) noexcept { + static constexpr std::array<std::pair<std::string_view, std::string_view>, 10> Stages = {{ + {"machine_ir_input", "MachineIRInput"}, + {"legalized", "Legalized"}, + {"reg_bank_selected", "RegBankSelected"}, + {"selected", "Selected"}, + {"ssa_eliminated", "SSAEliminated"}, + {"tied_ops_rewritten", "TiedOpsRewritten"}, + {"register_allocated", "RegisterAllocated"}, + {"frame_finalized", "FrameFinalized"}, + {"post_ra_finalized", "PostRAFinalized"}, + {"emission", "Emission"}, + }}; + const auto Position = std::ranges::find(Stages, Value, &decltype(Stages)::value_type::first); + if (Position == Stages.end()) + return std::nullopt; + return Position->second; +} + +[[nodiscard]] bool isPowerOfTwo(std::uint64_t Value) noexcept { + return Value != 0 && (Value & (Value - 1U)) == 0; +} + class ModelNormalizer final { public: ModelNormalizer(const DescriptionAST &Input, std::string SourceName) @@ -706,11 +1740,26 @@ public: NormalizedTargetModel Result; Result.Target = Input.Target; Result.RegisterUnits = Input.RegisterUnits; + Result.MIROperandFlags = Input.MIROperandFlags; if (!normalizeRegisterUnits() || !normalizeRegisters(Result) || !normalizeRegisterBanks(Result) || !normalizeRegisterClasses(Result) || - !normalizeRegisterMasks(Result)) { + !normalizeRegisterMasks(Result) || !normalizeMIROperandFlags(Result) || + !normalizeCallingConventions(Result) || !normalizeNamedOperands(Result) || + !normalizeImmediatePredicates(Result) || !normalizeSchedulingClasses(Result) || + !normalizeEncodingCategories(Result) || !normalizeAssemblyFormats(Result) || + !normalizeInstructions(Result)) { return std::nullopt; } + std::ranges::sort(Result.RegisterUnits, {}, &SourceRegisterUnit::ID); + std::ranges::sort(Result.Registers, {}, &NormalizedRegister::ID); + std::ranges::sort(Result.RegisterBanks, {}, &NormalizedRegisterBank::ID); + std::ranges::sort(Result.RegisterClasses, {}, &NormalizedRegisterClass::ID); + std::ranges::sort(Result.CallingConventions, {}, &NormalizedCallingConvention::ID); + std::ranges::sort(Result.NamedOperands, {}, &NormalizedNamedOperand::ID); + std::ranges::sort(Result.ImmediatePredicates, {}, &NormalizedImmediatePredicate::ID); + std::ranges::sort(Result.SchedulingClasses, {}, &NormalizedSchedulingClass::ID); + std::ranges::sort(Result.EncodingCategories, {}, &NormalizedEncodingCategory::ID); + std::ranges::sort(Result.AssemblyFormats, {}, &NormalizedAssemblyFormat::ID); return Result; } @@ -946,12 +1995,597 @@ private: return true; } + [[nodiscard]] bool normalizeMIROperandFlags(NormalizedTargetModel &Result) { + const SourceMIROperandFlags &Flags = Result.MIROperandFlags; + if (Flags.Direct.empty() != (Flags.DirectMask == 0)) { + fail(Flags.Range, "direct MIR operand flags and their direct mask must be present together"); + return false; + } + + std::unordered_set<std::string> Names; + std::unordered_set<std::uint32_t> DirectValues; + for (const SourceMIROperandFlag &Flag : Flags.Direct) { + if (Flag.Name.empty() || Flag.Value == 0 || (Flag.Value & ~Flags.DirectMask) != 0 || + !Names.insert(Flag.Name).second || !DirectValues.insert(Flag.Value).second) { + fail(Flag.Range, + "direct MIR operand flags require unique names and nonzero values inside the mask"); + return false; + } + } + + std::uint32_t BitmaskValues = 0; + for (const SourceMIROperandFlag &Flag : Flags.Bitmask) { + if (Flag.Name.empty() || !std::has_single_bit(Flag.Value) || + (Flag.Value & Flags.DirectMask) != 0 || !Names.insert(Flag.Name).second || + (BitmaskValues & Flag.Value) != 0) { + fail(Flag.Range, + "bitmask MIR operand flags require unique names and distinct bits outside the " + "direct mask"); + return false; + } + BitmaskValues |= Flag.Value; + } + return true; + } + + [[nodiscard]] bool normalizeCallingConventions(NormalizedTargetModel &Result) { + if (Input.CallingConventions.empty()) { + fail(Input.Target.Range, "target description requires at least one calling convention"); + return false; + } + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceCallingConvention &Convention : Input.CallingConventions) { + const auto IntegerClass = ClassBySymbol.find(Convention.IntegerRegisterClassSymbol); + const auto FloatingClass = ClassBySymbol.find(Convention.FloatingRegisterClassSymbol); + const auto PreservedMask = std::ranges::find( + Result.RegisterMasks, Convention.PreservedMaskName, &NormalizedRegisterMask::Name); + if (Convention.ID == 0 || !isIdentifier(Convention.Symbol) || Convention.Name.empty() || + IntegerClass == ClassBySymbol.end() || FloatingClass == ClassBySymbol.end() || + PreservedMask == Result.RegisterMasks.end() || Convention.StackAlignmentBytes == 0 || + Convention.StackArgumentAlignmentBytes == 0 || + !isPowerOfTwo(Convention.StackAlignmentBytes) || + !isPowerOfTwo(Convention.StackArgumentAlignmentBytes) || + Convention.StackAlignmentBytes % Convention.StackArgumentAlignmentBytes != 0 || + Convention.ShadowSpaceBytes % Convention.StackArgumentAlignmentBytes != 0 || + !IDs.insert(Convention.ID).second || !Symbols.insert(Convention.Symbol).second || + !Names.insert(Convention.Name).second) { + fail( + Convention.Range, + "calling conventions require unique IDs, symbols, names, declared register classes and " + "preserved masks, compatible power-of-two stack alignments, and aligned shadow space"); + return false; + } + const auto IntegerClassDescription = std::ranges::find( + Result.RegisterClasses, IntegerClass->second, &NormalizedRegisterClass::ID); + const auto FloatingClassDescription = std::ranges::find( + Result.RegisterClasses, FloatingClass->second, &NormalizedRegisterClass::ID); + if (IntegerClassDescription == Result.RegisterClasses.end() || + FloatingClassDescription == Result.RegisterClasses.end()) { + fail(Convention.Range, "calling convention register classes must resolve"); + return false; + } + const auto normalizeRegisterList = [this, + &Convention](const std::vector<std::string> &Symbols, + const NormalizedRegisterClass &RegisterClass, + std::vector<std::uint32_t> &Output) { + std::unordered_set<std::uint32_t> Registers; + for (const std::string &Symbol : Symbols) { + const auto Register = RegisterBySymbol.find(Symbol); + if (Register == RegisterBySymbol.end() || + !std::ranges::contains(RegisterClass.Registers, Register->second) || + !Registers.insert(Register->second).second) { + fail(Convention.Range, + "calling convention register lists must contain distinct members of their class"); + return false; + } + Output.push_back(Register->second); + } + return true; + }; + NormalizedCallingConvention Normalized{ + .ID = Convention.ID, + .Symbol = Convention.Symbol, + .Name = Convention.Name, + .IntegerRegisterClass = IntegerClass->second, + .FloatingRegisterClass = FloatingClass->second, + .IntegerArgumentRegisters = {}, + .FloatingArgumentRegisters = {}, + .IntegerReturnRegisters = {}, + .FloatingReturnRegisters = {}, + .PreservedMaskName = Convention.PreservedMaskName, + .StackAlignmentBytes = Convention.StackAlignmentBytes, + .StackArgumentAlignmentBytes = Convention.StackArgumentAlignmentBytes, + .ShadowSpaceBytes = Convention.ShadowSpaceBytes, + .SupportsVarArgs = Convention.SupportsVarArgs, + .SupportsTailCalls = Convention.SupportsTailCalls, + }; + if (!normalizeRegisterList(Convention.IntegerArgumentRegisterSymbols, + *IntegerClassDescription, Normalized.IntegerArgumentRegisters) || + !normalizeRegisterList(Convention.FloatingArgumentRegisterSymbols, + *FloatingClassDescription, Normalized.FloatingArgumentRegisters) || + !normalizeRegisterList(Convention.IntegerReturnRegisterSymbols, *IntegerClassDescription, + Normalized.IntegerReturnRegisters) || + !normalizeRegisterList(Convention.FloatingReturnRegisterSymbols, + *FloatingClassDescription, Normalized.FloatingReturnRegisters)) { + return false; + } + CallingConventionBySymbol.emplace(Convention.Symbol, Convention.ID); + Result.CallingConventions.push_back(std::move(Normalized)); + } + return true; + } + + [[nodiscard]] bool normalizeNamedOperands(NormalizedTargetModel &Result) { + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceNamedOperand &Operand : Input.NamedOperands) { + if (Operand.ID == 0 || !isIdentifier(Operand.Symbol) || Operand.Name.empty() || + !IDs.insert(Operand.ID).second || !Symbols.insert(Operand.Symbol).second || + !Names.insert(Operand.Name).second) { + fail(Operand.Range, "named operands require nonzero unique IDs, symbols, and names"); + return false; + } + NamedOperandBySymbol.emplace(Operand.Symbol, Operand.ID); + Result.NamedOperands.push_back({ + .ID = Operand.ID, + .Symbol = Operand.Symbol, + .Name = Operand.Name, + }); + } + return true; + } + + [[nodiscard]] bool normalizeImmediatePredicates(NormalizedTargetModel &Result) { + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceImmediatePredicate &Predicate : Input.ImmediatePredicates) { + const bool IsSigned = Predicate.Kind == "signed"; + const bool IsUnsigned = Predicate.Kind == "unsigned"; + if (Predicate.ID == 0 || !isIdentifier(Predicate.Symbol) || Predicate.Name.empty() || + (!IsSigned && !IsUnsigned) || Predicate.Bits == 0 || Predicate.Bits > 63 || + !isPowerOfTwo(Predicate.Alignment) || !IDs.insert(Predicate.ID).second || + !Symbols.insert(Predicate.Symbol).second || !Names.insert(Predicate.Name).second) { + fail(Predicate.Range, + "immediate predicates require nonzero unique IDs, symbols, names, a signed or " + "unsigned kind, a width in [1, 63], and power-of-two alignment"); + return false; + } + const std::int64_t PositiveLimit = std::int64_t{1} << (Predicate.Bits - 1U); + const std::int64_t Minimum = IsSigned ? -PositiveLimit : 0; + const std::int64_t Maximum = + IsSigned ? PositiveLimit - 1 + : static_cast<std::int64_t>((std::uint64_t{1} << Predicate.Bits) - 1U); + std::unordered_set<std::int64_t> AllowedValues; + for (const std::int64_t Value : Predicate.AllowedValues) { + if (Value < Minimum || Value > Maximum || (Predicate.NonZero && Value == 0) || + !AllowedValues.insert(Value).second) { + fail(Predicate.Range, + "immediate predicate allowed_values must be unique, in range, and satisfy nonzero"); + return false; + } + } + ImmediatePredicateBySymbol.emplace(Predicate.Symbol, Predicate.ID); + Result.ImmediatePredicates.push_back({ + .ID = Predicate.ID, + .Symbol = Predicate.Symbol, + .Name = Predicate.Name, + .IsSigned = IsSigned, + .Bits = Predicate.Bits, + .Alignment = Predicate.Alignment, + .NonZero = Predicate.NonZero, + .AllowedValues = Predicate.AllowedValues, + }); + } + return true; + } + + [[nodiscard]] bool normalizeSchedulingClasses(NormalizedTargetModel &Result) { + if (Input.SchedulingClasses.empty()) { + fail(Input.Target.Range, "target description requires at least one scheduling class"); + return false; + } + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceSchedulingClass &Class : Input.SchedulingClasses) { + if (Class.ID == 0 || !isIdentifier(Class.Symbol) || Class.Name.empty() || + Class.MicroOps == 0 || Class.Latency == 0 || !IDs.insert(Class.ID).second || + !Symbols.insert(Class.Symbol).second || !Names.insert(Class.Name).second) { + fail(Class.Range, + "scheduling classes require nonzero unique IDs, symbols, names, micro-op counts, " + "and latencies"); + return false; + } + SchedulingClassBySymbol.emplace(Class.Symbol, Class.ID); + Result.SchedulingClasses.push_back({ + .ID = Class.ID, + .Symbol = Class.Symbol, + .Name = Class.Name, + .MicroOps = Class.MicroOps, + .Latency = Class.Latency, + }); + } + return true; + } + + [[nodiscard]] bool normalizeEncodingCategories(NormalizedTargetModel &Result) { + if (Input.EncodingCategories.empty()) { + fail(Input.Target.Range, "target description requires at least one encoding category"); + return false; + } + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceEncodingCategory &Category : Input.EncodingCategories) { + if (Category.ID == 0 || !isIdentifier(Category.Symbol) || Category.Name.empty() || + Category.SizeInBytes == 0 || !IDs.insert(Category.ID).second || + !Symbols.insert(Category.Symbol).second || !Names.insert(Category.Name).second) { + fail(Category.Range, + "encoding categories require nonzero unique IDs, symbols, names, and sizes"); + return false; + } + EncodingCategoryBySymbol.emplace(Category.Symbol, Category.ID); + Result.EncodingCategories.push_back({ + .ID = Category.ID, + .Symbol = Category.Symbol, + .Name = Category.Name, + .SizeInBytes = Category.SizeInBytes, + }); + } + return true; + } + + [[nodiscard]] bool normalizeAssemblyFormats(NormalizedTargetModel &Result) { + if (Input.AssemblyFormats.empty()) { + fail(Input.Target.Range, "target description requires at least one assembly format"); + return false; + } + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceAssemblyFormat &Format : Input.AssemblyFormats) { + if (Format.ID == 0 || !isIdentifier(Format.Symbol) || Format.Name.empty() || + !IDs.insert(Format.ID).second || !Symbols.insert(Format.Symbol).second || + !Names.insert(Format.Name).second) { + fail(Format.Range, "assembly formats require nonzero unique IDs, symbols, and names"); + return false; + } + AssemblyFormatBySymbol.emplace(Format.Symbol, Format.ID); + Result.AssemblyFormats.push_back({ + .ID = Format.ID, + .Symbol = Format.Symbol, + .Name = Format.Name, + }); + } + return true; + } + + [[nodiscard]] bool normalizeOperand(const SourceOperand &InputOperand, + NormalizedOperand &Result) { + if (InputOperand.Kinds.empty()) { + fail(InputOperand.Range, "instruction operand requires at least one kind"); + return false; + } + std::unordered_set<std::string> Kinds; + bool HasRegisterKind = false; + for (const std::string &Kind : InputOperand.Kinds) { + const auto Enumerator = operandKindEnumerator(Kind); + if (!Enumerator || !Kinds.insert(std::string(*Enumerator)).second) { + fail(InputOperand.Range, "instruction operand kinds must be known and unique"); + return false; + } + HasRegisterKind |= *Enumerator == "Register"; + Result.Kinds.push_back(std::string(*Enumerator)); + } + + const auto Role = registerRoleEnumerator(InputOperand.RegisterRole); + const auto MemoryRole = memoryRoleEnumerator(InputOperand.MemoryRole); + if (!Role || !MemoryRole || HasRegisterKind != (*Role != "None")) { + fail(InputOperand.Range, + "instruction operand register role and memory role must match its declared kinds"); + return false; + } + Result.RegisterRole = std::string(*Role); + Result.MemoryRole = std::string(*MemoryRole); + + const bool IsDefRole = *Role == "Def" || *Role == "DefUse"; + const bool IsRegisterOnly = Result.Kinds.size() == 1 && Result.Kinds.front() == "Register"; + if (IsDefRole && !IsRegisterOnly) { + fail(InputOperand.Range, "register definition operands must accept only registers"); + return false; + } + if (!HasRegisterKind && (InputOperand.RegisterClassSymbol || InputOperand.RegisterBankSymbol || + InputOperand.EarlyClobber || InputOperand.AllowSubReg)) { + fail(InputOperand.Range, "non-register operands cannot have register constraints"); + return false; + } + if (InputOperand.EarlyClobber && !IsDefRole) { + fail(InputOperand.Range, "early-clobber operands must define a register"); + return false; + } + + if (InputOperand.RegisterClassSymbol) { + const auto Position = ClassBySymbol.find(*InputOperand.RegisterClassSymbol); + if (Position == ClassBySymbol.end()) { + fail(InputOperand.Range, "instruction operand names an unknown register class"); + return false; + } + Result.RegisterClass = Position->second; + } + if (InputOperand.RegisterBankSymbol) { + const auto Position = BankBySymbol.find(*InputOperand.RegisterBankSymbol); + if (Position == BankBySymbol.end()) { + fail(InputOperand.Range, "instruction operand names an unknown register bank"); + return false; + } + Result.RegisterBank = Position->second; + } + if (InputOperand.ImmediatePredicateSymbol) { + const auto Position = ImmediatePredicateBySymbol.find(*InputOperand.ImmediatePredicateSymbol); + if (Position == ImmediatePredicateBySymbol.end() || Result.Kinds.size() != 1 || + Result.Kinds.front() != "Immediate") { + fail(InputOperand.Range, + "instruction immediate predicates must name a declaration and constrain an immediate"); + return false; + } + Result.ImmediatePredicate = Position->second; + } + if (InputOperand.NameSymbol) { + const auto Position = NamedOperandBySymbol.find(*InputOperand.NameSymbol); + if (Position == NamedOperandBySymbol.end()) { + fail(InputOperand.Range, "instruction operand names an unknown named operand"); + return false; + } + Result.Name = Position->second; + } + + Result.DefaultTiedOperand = InputOperand.DefaultTiedOperand; + Result.EarlyClobber = InputOperand.EarlyClobber; + Result.Optional = InputOperand.Optional; + Result.VariadicGroup = InputOperand.VariadicGroup; + Result.AllowSubReg = InputOperand.AllowSubReg; + Result.AllowedTargetFlags = InputOperand.AllowedTargetFlags; + return true; + } + + [[nodiscard]] bool + normalizeImplicitRegisters(const std::vector<SourceImplicitRegister> &InputRegisters, bool IsDef, + std::vector<NormalizedImplicitRegister> &Result) { + std::unordered_set<std::uint32_t> Registers; + for (const SourceImplicitRegister &Register : InputRegisters) { + const auto Position = RegisterBySymbol.find(Register.RegisterSymbol); + if (Position == RegisterBySymbol.end() || !Registers.insert(Position->second).second || + (!IsDef && Register.EarlyClobber)) { + fail(Register.Range, + "implicit registers must be declared and unique; implicit uses cannot early-clobber"); + return false; + } + Result.push_back({ + .Register = Position->second, + .EarlyClobber = Register.EarlyClobber, + .Renamable = Register.Renamable, + }); + } + return true; + } + + [[nodiscard]] bool normalizeInstructions(NormalizedTargetModel &Result) { + if (Input.Instructions.empty()) { + fail(Input.Target.Range, "target description requires at least one instruction"); + return false; + } + std::unordered_set<std::uint32_t> IDs; + std::unordered_set<std::string> Symbols; + std::unordered_set<std::string> Names; + for (const SourceInstruction &Instruction : Input.Instructions) { + const bool HasMnemonic = !Instruction.AssemblyMnemonic.empty(); + const bool HasSchedulingClass = !Instruction.SchedulingClassSymbol.empty(); + const bool HasEncodingCategory = !Instruction.EncodingCategorySymbol.empty(); + const bool HasAssemblyFormat = !Instruction.AssemblyFormatSymbol.empty(); + const bool HasAllMachineFacts = + HasMnemonic && HasSchedulingClass && HasEncodingCategory && HasAssemblyFormat; + const bool HasAnyMachineFact = + HasMnemonic || HasSchedulingClass || HasEncodingCategory || HasAssemblyFormat; + const bool IsPseudoSource = + std::ranges::find(Instruction.Flags, "pseudo") != Instruction.Flags.end(); + const bool IsTerminalEmissionSource = + std::ranges::find(Instruction.Flags, "terminal_emission") != Instruction.Flags.end(); + if (HasAnyMachineFact != HasAllMachineFacts || + ((!IsPseudoSource || IsTerminalEmissionSource) && !HasAllMachineFacts)) { + fail(Instruction.Range, + "encoded instructions and terminal-emission pseudos require complete scheduling, " + "encoding, mnemonic, and assembly-format facts"); + return false; + } + const auto SchedulingClass = SchedulingClassBySymbol.find(Instruction.SchedulingClassSymbol); + const auto EncodingCategory = + EncodingCategoryBySymbol.find(Instruction.EncodingCategorySymbol); + const auto AssemblyFormat = AssemblyFormatBySymbol.find(Instruction.AssemblyFormatSymbol); + const auto Owner = pseudoOwnerEnumerator(Instruction.Owner); + const auto Deadline = pipelineStageEnumerator(Instruction.Deadline); + if (Instruction.ID == 0 || !isIdentifier(Instruction.Symbol) || Instruction.Name.empty() || + (HasMnemonic && !isAssemblyMnemonic(Instruction.AssemblyMnemonic)) || + (HasSchedulingClass && SchedulingClass == SchedulingClassBySymbol.end()) || + (HasEncodingCategory && EncodingCategory == EncodingCategoryBySymbol.end()) || + (HasAssemblyFormat && AssemblyFormat == AssemblyFormatBySymbol.end()) || !Owner || + !Deadline || !IDs.insert(Instruction.ID).second || + !Symbols.insert(Instruction.Symbol).second || !Names.insert(Instruction.Name).second) { + fail(Instruction.Range, + "instructions require nonzero unique IDs, symbols, lowercase assembly mnemonics, and " + "declared format IDs"); + return false; + } + if (Instruction.NumExplicitDefs > Instruction.Operands.size()) { + fail(Instruction.Range, "instruction explicit def count is outside its operand range"); + return false; + } + + NormalizedInstruction Normalized{ + .ID = Instruction.ID, + .Symbol = Instruction.Symbol, + .Name = Instruction.Name, + .AssemblyMnemonic = Instruction.AssemblyMnemonic, + .Operands = {}, + .NumExplicitDefs = Instruction.NumExplicitDefs, + .Variadic = Instruction.Variadic, + .ImplicitDefs = {}, + .ImplicitUses = {}, + .AllowExtraImplicitOperands = Instruction.AllowExtraImplicitOperands, + .Flags = {}, + .SchedulingClass = HasSchedulingClass ? SchedulingClass->second : 0, + .EncodingCategory = HasEncodingCategory ? EncodingCategory->second : 0, + .AssemblyFormat = HasAssemblyFormat ? AssemblyFormat->second : 0, + .RequiresMemoryOperands = Instruction.RequiresMemoryOperands, + .Owner = std::string(*Owner), + .Deadline = std::string(*Deadline), + }; + Normalized.Operands.reserve(Instruction.Operands.size()); + bool SawOptional = false; + for (std::size_t Index = 0; Index < Instruction.Operands.size(); ++Index) { + NormalizedOperand Operand; + if (!normalizeOperand(Instruction.Operands[Index], Operand)) + return false; + const bool IsDef = Operand.RegisterRole == "Def" || Operand.RegisterRole == "DefUse"; + if ((Index < Instruction.NumExplicitDefs) != IsDef) { + fail(Instruction.Operands[Index].Range, + "instruction explicit register definitions must form the leading operand prefix"); + return false; + } + if (Instruction.Variadic && Operand.Optional) { + fail(Instruction.Operands[Index].Range, + "variadic instructions cannot contain optional operands"); + return false; + } + if (Operand.Optional) + SawOptional = true; + else if (SawOptional && !Operand.VariadicGroup) { + fail(Instruction.Operands[Index].Range, + "optional instruction operands must form a trailing suffix"); + return false; + } + if (Operand.VariadicGroup && + (!Instruction.Variadic || Index + 1 != Instruction.Operands.size())) { + fail(Instruction.Operands[Index].Range, + "a variadic operand group must be the final instruction operand"); + return false; + } + if (Operand.VariadicGroup && (Operand.Optional || Operand.DefaultTiedOperand)) { + fail(Instruction.Operands[Index].Range, + "a variadic operand group cannot be optional or have a default tie"); + return false; + } + Normalized.Operands.push_back(std::move(Operand)); + } + if (Instruction.Variadic && + (Normalized.Operands.empty() || !Normalized.Operands.back().VariadicGroup)) { + fail(Instruction.Range, "variadic instructions require a final variadic operand group"); + return false; + } + if (!Instruction.Variadic && + std::ranges::any_of(Normalized.Operands, [](const NormalizedOperand &Operand) { + return Operand.VariadicGroup; + })) { + fail(Instruction.Range, "non-variadic instructions cannot have a variadic operand group"); + return false; + } + + std::unordered_set<std::uint32_t> NamedOperands; + for (std::size_t Index = 0; Index < Normalized.Operands.size(); ++Index) { + const NormalizedOperand &Operand = Normalized.Operands[Index]; + if (Operand.Name && !NamedOperands.insert(*Operand.Name).second) { + fail(Instruction.Operands[Index].Range, + "instruction operands must use distinct named operand IDs"); + return false; + } + if (!Operand.DefaultTiedOperand) + continue; + const std::uint32_t OtherIndex = *Operand.DefaultTiedOperand; + if (OtherIndex >= Normalized.Operands.size() || OtherIndex == Index || + !Normalized.Operands[OtherIndex].DefaultTiedOperand || + *Normalized.Operands[OtherIndex].DefaultTiedOperand != Index) { + fail(Instruction.Operands[Index].Range, + "instruction default ties must be reciprocal and in range"); + return false; + } + const NormalizedOperand &Other = Normalized.Operands[OtherIndex]; + const bool IsRegisterOnly = + Operand.Kinds.size() == 1 && Operand.Kinds.front() == "Register"; + const bool OtherIsRegisterOnly = + Other.Kinds.size() == 1 && Other.Kinds.front() == "Register"; + const bool IsDefUsePair = (Operand.RegisterRole == "Def" && Other.RegisterRole == "Use") || + (Operand.RegisterRole == "Use" && Other.RegisterRole == "Def"); + if (Operand.Optional || Other.Optional || !IsRegisterOnly || !OtherIsRegisterOnly || + !IsDefUsePair) { + fail(Instruction.Operands[Index].Range, + "instruction default ties must connect required register defs and uses"); + return false; + } + } + + std::unordered_set<std::string> Flags; + for (const std::string &Flag : Instruction.Flags) { + const auto Enumerator = instructionFlagEnumerator(Flag); + if (!Enumerator || !Flags.insert(std::string(*Enumerator)).second) { + fail(Instruction.Range, "instruction flags must be known and unique"); + return false; + } + Normalized.Flags.push_back(std::string(*Enumerator)); + } + const auto HasFlag = [&Normalized](std::string_view Flag) { + return std::ranges::find(Normalized.Flags, Flag) != Normalized.Flags.end(); + }; + const bool IsTerminator = HasFlag("Terminator"); + if ((HasFlag("Branch") || HasFlag("Return") || HasFlag("Barrier") || + HasFlag("IndirectBranch")) && + !IsTerminator) { + fail(Instruction.Range, "branch, return, and barrier instructions must be terminators"); + return false; + } + if (HasFlag("IndirectBranch") && !HasFlag("Branch")) { + fail(Instruction.Range, "indirect branch instructions must also be branches"); + return false; + } + const bool IsPseudo = HasFlag("Pseudo"); + const bool IsMeta = HasFlag("Meta"); + if ((IsMeta && (!IsPseudo || HasFlag("ProducesCode"))) || + (!IsPseudo && Normalized.Owner != "None") || + (IsPseudo && !IsMeta && Normalized.Owner == "None") || + (HasFlag("TerminalEmission") && + (!IsPseudo || Normalized.Owner != "AsmPrinter" || !HasFlag("ProducesCode")))) { + fail(Instruction.Range, "instruction pseudo flags, owner, and deadline are inconsistent"); + return false; + } + if (Normalized.RequiresMemoryOperands && !HasFlag("MayLoad") && !HasFlag("MayStore")) { + fail(Instruction.Range, + "memory operand requirements need a load or store instruction flag"); + return false; + } + if (!normalizeImplicitRegisters(Instruction.ImplicitDefs, true, Normalized.ImplicitDefs) || + !normalizeImplicitRegisters(Instruction.ImplicitUses, false, Normalized.ImplicitUses)) { + return false; + } + Result.Instructions.push_back(std::move(Normalized)); + } + std::ranges::sort(Result.Instructions, {}, &NormalizedInstruction::ID); + return true; + } + const DescriptionAST &Input; std::string SourceName; std::unordered_map<std::string, std::uint32_t> UnitBySymbol; std::unordered_map<std::string, std::uint32_t> RegisterBySymbol; std::unordered_map<std::string, std::uint32_t> BankBySymbol; std::unordered_map<std::string, std::uint32_t> ClassBySymbol; + std::unordered_map<std::string, std::uint32_t> NamedOperandBySymbol; + std::unordered_map<std::string, std::uint32_t> ImmediatePredicateBySymbol; + std::unordered_map<std::string, std::uint32_t> SchedulingClassBySymbol; + std::unordered_map<std::string, std::uint32_t> EncodingCategoryBySymbol; + std::unordered_map<std::string, std::uint32_t> AssemblyFormatBySymbol; + std::unordered_map<std::string, std::uint32_t> CallingConventionBySymbol; std::vector<TextDiagnostic> Diagnostics; }; @@ -1024,12 +2658,152 @@ private: return Output.str(); } +[[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-backend-descgen 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(); +} + void emitRegisterIDList(std::ostream &Output, const NormalizedTargetModel &Model, std::span<const std::uint32_t> IDs) { for (const std::uint32_t ID : IDs) Output << "PhysicalRegisterID::" << findRegister(Model, ID).Symbol << ", "; } +void emitPhysicalRegisterArray(std::ostream &Output, const NormalizedTargetModel &Model, + std::string_view Name, std::span<const std::uint32_t> IDs) { + Output << "const std::array<PhysicalRegister, " << IDs.size() << "> " << Name << " = {{\n"; + for (const std::uint32_t ID : IDs) + Output << " physical(PhysicalRegisterID::" << findRegister(Model, ID).Symbol << "),\n"; + Output << "}};\n"; +} + +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"; +} + [[nodiscard]] std::string emitTargetTables(const NormalizedTargetModel &Model, std::string_view SourceName) { std::ostringstream Output; @@ -1089,6 +2863,20 @@ void emitRegisterIDList(std::ostream &Output, const NormalizedTargetModel &Model } Output << " };\n}\n\n"; Output << "void appendGeneratedMIRTextInfo(TargetMIRTextInfoDesc &Description) {\n"; + Output << " Description.DirectOperandFlagMask = " << Model.MIROperandFlags.DirectMask + << ";\n Description.DirectOperandFlags = {\n"; + for (const SourceMIROperandFlag &Flag : Model.MIROperandFlags.Direct) { + Output << " {"; + appendQuoted(Output, Flag.Name); + Output << ", " << Flag.Value << "},\n"; + } + Output << " };\n Description.BitmaskOperandFlags = {\n"; + for (const SourceMIROperandFlag &Flag : Model.MIROperandFlags.Bitmask) { + Output << " {"; + appendQuoted(Output, Flag.Name); + Output << ", " << Flag.Value << "},\n"; + } + Output << " };\n"; Output << " Description.RegisterMasks = {\n"; for (const NormalizedRegisterMask &Mask : Model.RegisterMasks) { Output << " {"; @@ -1102,7 +2890,115 @@ void emitRegisterIDList(std::ostream &Output, const NormalizedTargetModel &Model Output << " {physical(PhysicalRegisterID::" << Register.Symbol << "), " << Register.DwarfRegister << ", true},\n"; } - Output << " };\n}\n"; + Output << " };\n}\n\n"; + + 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"; + + Output << "constexpr std::array<SchedulingClassInfo, " << Model.SchedulingClasses.size() + << "> GeneratedSchedulingClasses = {{\n"; + for (const NormalizedSchedulingClass &Class : Model.SchedulingClasses) { + Output << " {SchedulingClassID::fromValue(" << Class.ID << "), "; + appendQuoted(Output, Class.Name); + Output << ", " << Class.MicroOps << ", " << Class.Latency << "},\n"; + } + Output << "}};\n\n"; + + Output << "constexpr std::array<EncodingCategoryInfo, " << Model.EncodingCategories.size() + << "> GeneratedEncodingCategories = {{\n"; + for (const NormalizedEncodingCategory &Category : Model.EncodingCategories) { + Output << " {EncodingCategoryID::fromValue(" << Category.ID << "), "; + appendQuoted(Output, Category.Name); + Output << ", " << Category.SizeInBytes << "},\n"; + } + Output << "}};\n\n"; + + Output << "constexpr std::array<AssemblyFormatInfo, " << Model.AssemblyFormats.size() + << "> GeneratedAssemblyFormats = {{\n"; + for (const NormalizedAssemblyFormat &Format : Model.AssemblyFormats) { + Output << " {AssemblyFormatID::fromValue(" << Format.ID << "), "; + appendQuoted(Output, Format.Name); + Output << "},\n"; + } + Output << "}};\n\n"; + + const auto AssemblyInstructionCount = + std::ranges::count_if(Model.Instructions, [](const NormalizedInstruction &Instruction) { + return !Instruction.AssemblyMnemonic.empty(); + }); + Output << "constexpr std::array<AssemblyInstructionInfo, " << AssemblyInstructionCount + << "> GeneratedAssemblyInstructions = {{\n"; + for (const NormalizedInstruction &Instruction : Model.Instructions) { + if (Instruction.AssemblyMnemonic.empty()) + continue; + Output << " {Opcode::fromValue(" << Instruction.ID << "), "; + appendQuoted(Output, Instruction.AssemblyMnemonic); + Output << ", AssemblyFormatID::fromValue(" << Instruction.AssemblyFormat << ")},\n"; + } + Output << "}};\n\n"; + + for (const NormalizedCallingConvention &Convention : Model.CallingConventions) { + const std::string Prefix = "CC" + std::to_string(Convention.ID); + emitPhysicalRegisterArray(Output, Model, Prefix + "IntegerArguments", + Convention.IntegerArgumentRegisters); + emitPhysicalRegisterArray(Output, Model, Prefix + "FloatingArguments", + Convention.FloatingArgumentRegisters); + emitPhysicalRegisterArray(Output, Model, Prefix + "IntegerReturns", + Convention.IntegerReturnRegisters); + emitPhysicalRegisterArray(Output, Model, Prefix + "FloatingReturns", + Convention.FloatingReturnRegisters); + } + Output << "const std::array<CallingConventionInfo, " << Model.CallingConventions.size() + << "> GeneratedCallingConventions = {{\n"; + for (const NormalizedCallingConvention &Convention : Model.CallingConventions) { + const std::string Prefix = "CC" + std::to_string(Convention.ID); + Output << " {CallingConvention::" << Convention.Symbol << ", "; + appendQuoted(Output, Convention.Name); + Output << ", RegisterClassID::fromValue(" << Convention.IntegerRegisterClass + << "), RegisterClassID::fromValue(" << Convention.FloatingRegisterClass << "), " + << Prefix << "IntegerArguments, " << Prefix << "FloatingArguments, " << Prefix + << "IntegerReturns, " << Prefix << "FloatingReturns, "; + appendQuoted(Output, Convention.PreservedMaskName); + Output << ", " << Convention.StackAlignmentBytes << ", " + << Convention.StackArgumentAlignmentBytes << ", " << Convention.ShadowSpaceBytes << ", " + << (Convention.SupportsVarArgs ? "true" : "false") << ", " + << (Convention.SupportsTailCalls ? "true" : "false") << "},\n"; + } + Output << "}};\n"; return Output.str(); } @@ -1141,6 +3037,7 @@ DescriptionGenerationResult generateDescription(std::string SourceName, std::str .Output = GeneratedDescription{ .RegisterHeader = emitRegisterHeader(*Model, DisplayName), + .InstructionHeader = emitInstructionHeader(*Model, DisplayName), .TargetTables = emitTargetTables(*Model, DisplayName), }, .Diagnostics = {}, diff --git a/backend/lib/Target/Description/TargetDescriptionGenerator.h b/backend/lib/Target/Description/TargetDescriptionGenerator.h index 54cbf3c..c0d8ed5 100644 --- a/backend/lib/Target/Description/TargetDescriptionGenerator.h +++ b/backend/lib/Target/Description/TargetDescriptionGenerator.h @@ -14,6 +14,7 @@ namespace rcc::targetgen { struct GeneratedDescription final { std::string RegisterHeader; + std::string InstructionHeader; std::string TargetTables; }; diff --git a/backend/lib/Target/RISCV/CMakeLists.txt b/backend/lib/Target/RISCV/CMakeLists.txt index 2c744c0..a77494a 100644 --- a/backend/lib/Target/RISCV/CMakeLists.txt +++ b/backend/lib/Target/RISCV/CMakeLists.txt @@ -2,20 +2,28 @@ set(RCCBackendRISCVDescription "${CMAKE_CURRENT_SOURCE_DIR}/RISCV.rccdesc") set( - RCCBackendRISCVGeneratedHeader + RCCBackendRISCVGeneratedRegisterHeader "${RCC_BACKEND_BINARY_DIR}/generated/include/rcc/Target/RISCV/RISCVRegisters.h" ) set( + RCCBackendRISCVGeneratedInstructionHeader + "${RCC_BACKEND_BINARY_DIR}/generated/include/rcc/Target/RISCV/RISCVInstructions.h" +) +set( RCCBackendRISCVGeneratedTables "${RCC_BACKEND_BINARY_DIR}/generated/lib/Target/RISCV/RISCVGenTargetDescription.inc" ) add_custom_command( - OUTPUT "${RCCBackendRISCVGeneratedHeader}" "${RCCBackendRISCVGeneratedTables}" + OUTPUT + "${RCCBackendRISCVGeneratedRegisterHeader}" + "${RCCBackendRISCVGeneratedInstructionHeader}" + "${RCCBackendRISCVGeneratedTables}" COMMAND "$<TARGET_FILE:RCCBackendDescriptionGenerator>" --input "${RCCBackendRISCVDescription}" - --header "${RCCBackendRISCVGeneratedHeader}" + --register-header "${RCCBackendRISCVGeneratedRegisterHeader}" + --instruction-header "${RCCBackendRISCVGeneratedInstructionHeader}" --tables "${RCCBackendRISCVGeneratedTables}" DEPENDS RCCBackendDescriptionGenerator "${RCCBackendRISCVDescription}" COMMENT "Generating RCC RV64GC target tables" @@ -24,18 +32,24 @@ add_custom_command( add_custom_target( RCCBackendRISCVGeneratedTablesTarget - DEPENDS "${RCCBackendRISCVGeneratedHeader}" "${RCCBackendRISCVGeneratedTables}" + DEPENDS + "${RCCBackendRISCVGeneratedRegisterHeader}" + "${RCCBackendRISCVGeneratedInstructionHeader}" + "${RCCBackendRISCVGeneratedTables}" ) set_source_files_properties( - "${RCCBackendRISCVGeneratedHeader}" "${RCCBackendRISCVGeneratedTables}" + "${RCCBackendRISCVGeneratedRegisterHeader}" + "${RCCBackendRISCVGeneratedInstructionHeader}" + "${RCCBackendRISCVGeneratedTables}" PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE ) add_library( RCCBackendRISCV RISCVTarget.cpp - "${RCCBackendRISCVGeneratedHeader}" + "${RCCBackendRISCVGeneratedRegisterHeader}" + "${RCCBackendRISCVGeneratedInstructionHeader}" "${RCCBackendRISCVGeneratedTables}" ) add_library(RCCBackend::RISCV ALIAS RCCBackendRISCV) @@ -68,7 +82,9 @@ install( RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ) install( - FILES "${RCCBackendRISCVGeneratedHeader}" + FILES + "${RCCBackendRISCVGeneratedRegisterHeader}" + "${RCCBackendRISCVGeneratedInstructionHeader}" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rcc/Target/RISCV" ) @@ -76,4 +92,6 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/Target/RISCV/RISCVTarget.h" ) -rcc_backend_register_tidy_files("${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp") +rcc_backend_register_tidy_files( + "${CMAKE_CURRENT_SOURCE_DIR}/RISCVTarget.cpp" +) diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index 54093e6..a8dfdde 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-3.0-or-later -schema: rcc-target-description-v1 +schema: rcc-target-description-v2 target: namespace: riscv name: RISCV @@ -213,8 +213,2985 @@ register_classes: lanes: 1 registers: [F8, F9, F10, F11, F12, F13, F14, F15] allocation_order: [F10, F11, F12, F13, F14, F15, F8, F9] + - + id: 7 + symbol: GPR_NX0 + name: GPR_NX0 + bank: GPR + size_bits: 64 + spill_size_bits: 64 + spill_alignment_bits: 64 + lanes: 1 + registers: [X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31] + allocation_order: [X5, X6, X7, X28, X29, X30, X31, X10, X11, X12, X13, X14, X15, X16, X17, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X1] + - + id: 8 + symbol: GPR_NX0_NX2 + name: GPR_NX0_NX2 + bank: GPR + size_bits: 64 + spill_size_bits: 64 + spill_alignment_bits: 64 + lanes: 1 + registers: [X1, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31] + allocation_order: [X5, X6, X7, X28, X29, X30, X31, X10, X11, X12, X13, X14, X15, X16, X17, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X1] register_masks: - name: CSR_ILP32D_LP64D preserved: [X1, X8, X9, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, F8, F9, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27] + +mir_operand_flags: + direct_mask: 31 + direct: + - { name: riscv-call, value: 1 } + bitmask: [] + +calling_conventions: + - + id: 1 + symbol: LP64D + name: lp64d + integer_register_class: GPR + floating_register_class: FPR64 + integer_argument_registers: [X10, X11, X12, X13, X14, X15, X16, X17] + floating_argument_registers: [F10, F11, F12, F13, F14, F15, F16, F17] + integer_return_registers: [X10, X11] + floating_return_registers: [F10, F11] + preserved_mask: CSR_ILP32D_LP64D + stack_alignment_bytes: 16 + stack_argument_alignment_bytes: 16 + shadow_space_bytes: 0 + supports_varargs: true + supports_tail_calls: true + +named_operands: + - { id: 1, symbol: RD, name: rd } + - { id: 2, symbol: RS1, name: rs1 } + - { id: 3, symbol: RS2, name: rs2 } + - { id: 4, symbol: IMM, name: imm } + - { id: 5, symbol: TARGET, name: target } + - { id: 6, symbol: CSR, name: csr } + - { id: 7, symbol: ZIMM, name: zimm } + - { id: 8, symbol: PRED, name: pred } + - { id: 9, symbol: SUCC, name: succ } + - { id: 10, symbol: FRD, name: frd } + - { id: 11, symbol: FRS1, name: frs1 } + - { id: 12, symbol: FRS2, name: frs2 } + - { id: 13, symbol: FRS3, name: frs3 } + - { id: 14, symbol: RM, name: rm } + +immediate_predicates: + - { id: 1, symbol: SIMM12, name: simm12, kind: signed, bits: 12 } + - { id: 2, symbol: SIMM20, name: simm20, kind: signed, bits: 20 } + - { id: 3, symbol: UIMM5, name: uimm5, kind: unsigned, bits: 5 } + - { id: 4, symbol: UIMM6, name: uimm6, kind: unsigned, bits: 6 } + - { id: 5, symbol: UIMM12, name: uimm12, kind: unsigned, bits: 12 } + - { id: 6, symbol: UIMM4, name: uimm4, kind: unsigned, bits: 4 } + - { id: 7, symbol: RM, name: rm, kind: unsigned, bits: 3, allowed_values: [0, 1, 2, 3, 4, 7] } + - { id: 8, symbol: C_UIMM10_NZ_A4, name: c-uimm10-nz-a4, kind: unsigned, bits: 10, alignment: 4, nonzero: true } + - { id: 9, symbol: C_UIMM7_A4, name: c-uimm7-a4, kind: unsigned, bits: 7, alignment: 4 } + - { id: 10, symbol: C_UIMM8_A8, name: c-uimm8-a8, kind: unsigned, bits: 8, alignment: 8 } + - { id: 11, symbol: C_UIMM8_A4, name: c-uimm8-a4, kind: unsigned, bits: 8, alignment: 4 } + - { id: 12, symbol: C_UIMM9_A8, name: c-uimm9-a8, kind: unsigned, bits: 9, alignment: 8 } + - { id: 13, symbol: C_SIMM6, name: c-simm6, kind: signed, bits: 6 } + - { id: 14, symbol: C_SIMM6_NZ, name: c-simm6-nz, kind: signed, bits: 6, nonzero: true } + - { id: 15, symbol: C_SIMM9_A2, name: c-simm9-a2, kind: signed, bits: 9, alignment: 2 } + - { id: 16, symbol: C_SIMM12_A2, name: c-simm12-a2, kind: signed, bits: 12, alignment: 2 } + - { id: 17, symbol: C_SIMM10_A16_NZ, name: c-simm10-a16-nz, kind: signed, bits: 10, alignment: 16, nonzero: true } + +scheduling_classes: + - { id: 1, symbol: ALU, name: alu, micro_ops: 1, latency: 1 } + - { id: 2, symbol: LOAD, name: load, micro_ops: 1, latency: 3 } + - { id: 3, symbol: STORE, name: store, micro_ops: 1, latency: 1 } + - { id: 4, symbol: BRANCH, name: branch, micro_ops: 1, latency: 1 } + - { id: 5, symbol: SYSTEM, name: system, micro_ops: 1, latency: 1 } + - { id: 6, symbol: MUL, name: mul, micro_ops: 1, latency: 3 } + - { id: 7, symbol: DIV, name: div, micro_ops: 1, latency: 20 } + - { id: 8, symbol: FENCE, name: fence, micro_ops: 1, latency: 1 } + - { id: 9, symbol: ATOMIC, name: atomic, micro_ops: 1, latency: 4 } + - { id: 10, symbol: FP_ADD, name: fp-add, micro_ops: 1, latency: 4 } + - { id: 11, symbol: FP_MUL, name: fp-mul, micro_ops: 1, latency: 4 } + - { id: 12, symbol: FP_DIV, name: fp-div, micro_ops: 1, latency: 20 } + - { id: 13, symbol: FP_SQRT, name: fp-sqrt, micro_ops: 1, latency: 20 } + - { id: 14, symbol: FP_CONVERT, name: fp-convert, micro_ops: 1, latency: 4 } + - { id: 15, symbol: COMPRESSED, name: compressed, micro_ops: 1, latency: 1 } + +encoding_categories: + - { id: 1, symbol: R, name: r, size_bytes: 4 } + - { id: 2, symbol: I, name: i, size_bytes: 4 } + - { id: 3, symbol: S, name: s, size_bytes: 4 } + - { id: 4, symbol: B, name: b, size_bytes: 4 } + - { id: 5, symbol: U, name: u, size_bytes: 4 } + - { id: 6, symbol: J, name: j, size_bytes: 4 } + - { id: 7, symbol: SYSTEM, name: system, size_bytes: 4 } + - { id: 8, symbol: AMO, name: amo, size_bytes: 4 } + - { id: 9, symbol: R4, name: r4, size_bytes: 4 } + - { id: 10, symbol: C, name: c, size_bytes: 2 } + +assembly_formats: + - { id: 1, symbol: RD_IMM, name: rd-imm } + - { id: 2, symbol: RD_RS1_IMM, name: rd-rs1-imm } + - { id: 3, symbol: RD_RS1_RS2, name: rd-rs1-rs2 } + - { id: 4, symbol: RD_OFFSET_RS1, name: rd-offset-rs1 } + - { id: 5, symbol: RS2_OFFSET_RS1, name: rs2-offset-rs1 } + - { id: 6, symbol: RS1_RS2_TARGET, name: rs1-rs2-target } + - { id: 7, symbol: RD_TARGET, name: rd-target } + - { id: 8, symbol: NONE, name: none } + - { id: 9, symbol: IMM_IMM, name: imm-imm } + - { id: 10, symbol: RD_CSR_RS1, name: rd-csr-rs1 } + - { id: 11, symbol: RD_CSR_IMM, name: rd-csr-imm } + - { id: 12, symbol: RD_PAREN_RS1, name: rd-paren-rs1 } + - { id: 13, symbol: RD_RS2_PAREN_RS1, name: rd-rs2-paren-rs1 } + - { id: 14, symbol: FRD_OFFSET_RS1, name: frd-offset-rs1 } + - { id: 15, symbol: FRS2_OFFSET_RS1, name: frs2-offset-rs1 } + - { id: 16, symbol: FRD_FRS1_FRS2_RM, name: frd-frs1-frs2-rm } + - { id: 17, symbol: FRD_FRS1_FRS2_FRS3_RM, name: frd-frs1-frs2-frs3-rm } + - { id: 18, symbol: FRD_FRS1_RM, name: frd-frs1-rm } + - { id: 19, symbol: FRD_FRS1_FRS2, name: frd-frs1-frs2 } + - { id: 20, symbol: RD_FRS1_RM, name: rd-frs1-rm } + - { id: 21, symbol: RD_FRS1, name: rd-frs1 } + - { id: 22, symbol: RD_FRS1_FRS2, name: rd-frs1-frs2 } + - { id: 23, symbol: FRD_RS1_RM, name: frd-rs1-rm } + - { id: 24, symbol: FRD_RS1, name: frd-rs1 } + - { id: 25, symbol: TARGET, name: target } + - { id: 26, symbol: RS1_TARGET, name: rs1-target } + - { id: 27, symbol: RS1, name: rs1 } + - { id: 28, symbol: RD_RS2, name: rd-rs2 } + - { id: 29, symbol: IMM_SP, name: imm-sp } + - { id: 30, symbol: RD_IMM_SP, name: rd-imm-sp } + - { id: 31, symbol: RD_OFFSET_SP, name: rd-offset-sp } + - { id: 32, symbol: RS2_OFFSET_SP, name: rs2-offset-sp } + - { id: 33, symbol: FRD_OFFSET_SP, name: frd-offset-sp } + - { id: 34, symbol: FRS2_OFFSET_SP, name: frs2-offset-sp } + +instructions: + - + id: 1024 + symbol: LUI + name: LUI + assembly_mnemonic: lui + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: SIMM20, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: U + assembly_format: RD_IMM + - + id: 1025 + symbol: AUIPC + name: AUIPC + assembly_mnemonic: auipc + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: SIMM20, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: U + assembly_format: RD_IMM + - + id: 1026 + symbol: ADDI + name: ADDI + assembly_mnemonic: addi + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1042 + symbol: SRLI + name: SRLI + assembly_mnemonic: srli + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1043 + symbol: SRAI + name: SRAI + assembly_mnemonic: srai + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1044 + symbol: ADDIW + name: ADDIW + assembly_mnemonic: addiw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1045 + symbol: SLLIW + name: SLLIW + assembly_mnemonic: slliw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM5, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1046 + symbol: SRLIW + name: SRLIW + assembly_mnemonic: srliw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM5, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1047 + symbol: SRAIW + name: SRAIW + assembly_mnemonic: sraiw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM5, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1048 + symbol: SLL + name: SLL + assembly_mnemonic: sll + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1049 + symbol: SLT + name: SLT + assembly_mnemonic: slt + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1050 + symbol: SLTU + name: SLTU + assembly_mnemonic: sltu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1051 + symbol: XOR + name: XOR + assembly_mnemonic: xor + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1052 + symbol: SRL + name: SRL + assembly_mnemonic: srl + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1053 + symbol: SRA + name: SRA + assembly_mnemonic: sra + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1054 + symbol: OR + name: OR + assembly_mnemonic: or + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1055 + symbol: AND + name: AND + assembly_mnemonic: and + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1056 + symbol: ADDW + name: ADDW + assembly_mnemonic: addw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1057 + symbol: SUBW + name: SUBW + assembly_mnemonic: subw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1058 + symbol: SLLW + name: SLLW + assembly_mnemonic: sllw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1059 + symbol: SRLW + name: SRLW + assembly_mnemonic: srlw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1060 + symbol: SRAW + name: SRAW + assembly_mnemonic: sraw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1061 + symbol: LB + name: LB + assembly_mnemonic: lb + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1062 + symbol: LH + name: LH + assembly_mnemonic: lh + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1063 + symbol: LW + name: LW + assembly_mnemonic: lw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1064 + symbol: LBU + name: LBU + assembly_mnemonic: lbu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1065 + symbol: LHU + name: LHU + assembly_mnemonic: lhu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1066 + symbol: LWU + name: LWU + assembly_mnemonic: lwu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1067 + symbol: SB + name: SB + assembly_mnemonic: sb + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: S + assembly_format: RS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1068 + symbol: SH + name: SH + assembly_mnemonic: sh + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: S + assembly_format: RS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1069 + symbol: SW + name: SW + assembly_mnemonic: sw + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: S + assembly_format: RS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1070 + symbol: BLT + name: BLT + assembly_mnemonic: blt + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: B + assembly_format: RS1_RS2_TARGET + - + id: 1071 + symbol: BGE + name: BGE + assembly_mnemonic: bge + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: B + assembly_format: RS1_RS2_TARGET + - + id: 1072 + symbol: BLTU + name: BLTU + assembly_mnemonic: bltu + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: B + assembly_format: RS1_RS2_TARGET + - + id: 1073 + symbol: BGEU + name: BGEU + assembly_mnemonic: bgeu + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: B + assembly_format: RS1_RS2_TARGET + - + id: 1074 + symbol: JALR + name: JALR + assembly_mnemonic: jalr + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [terminator, branch, indirect_branch, produces_code] + scheduling_class: BRANCH + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1075 + symbol: FENCE + name: FENCE + assembly_mnemonic: fence + operands: + - { kinds: [immediate], immediate_predicate: UIMM4, name: PRED } + - { kinds: [immediate], immediate_predicate: UIMM4, name: SUCC } + num_explicit_defs: 0 + flags: [has_side_effects, produces_code] + scheduling_class: FENCE + encoding_category: I + assembly_format: IMM_IMM + - + id: 1076 + symbol: FENCE_I + name: FENCE_I + assembly_mnemonic: fence.i + operands: [] + num_explicit_defs: 0 + flags: [has_side_effects, produces_code] + scheduling_class: FENCE + encoding_category: I + assembly_format: NONE + - + id: 1077 + symbol: CSRRW + name: CSRRW + assembly_mnemonic: csrrw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: RD_CSR_RS1 + - + id: 1078 + symbol: CSRRS + name: CSRRS + assembly_mnemonic: csrrs + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: RD_CSR_RS1 + - + id: 1079 + symbol: CSRRC + name: CSRRC + assembly_mnemonic: csrrc + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: RD_CSR_RS1 + - + id: 1080 + symbol: CSRRWI + name: CSRRWI + assembly_mnemonic: csrrwi + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } + - { kinds: [immediate], immediate_predicate: UIMM5, name: ZIMM } + num_explicit_defs: 1 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: RD_CSR_IMM + - + id: 1083 + symbol: MUL + name: MUL + assembly_mnemonic: mul + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: MUL + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1084 + symbol: MULH + name: MULH + assembly_mnemonic: mulh + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: MUL + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1085 + symbol: MULHSU + name: MULHSU + assembly_mnemonic: mulhsu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: MUL + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1086 + symbol: MULHU + name: MULHU + assembly_mnemonic: mulhu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: MUL + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1087 + symbol: DIV + name: DIV + assembly_mnemonic: div + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1088 + symbol: DIVU + name: DIVU + assembly_mnemonic: divu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1089 + symbol: REM + name: REM + assembly_mnemonic: rem + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1090 + symbol: REMU + name: REMU + assembly_mnemonic: remu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1091 + symbol: MULW + name: MULW + assembly_mnemonic: mulw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code, commutable] + scheduling_class: MUL + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1092 + symbol: DIVW + name: DIVW + assembly_mnemonic: divw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1093 + symbol: DIVUW + name: DIVUW + assembly_mnemonic: divuw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1094 + symbol: REMW + name: REMW + assembly_mnemonic: remw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1095 + symbol: REMUW + name: REMUW + assembly_mnemonic: remuw + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: DIV + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1081 + symbol: CSRRSI + name: CSRRSI + assembly_mnemonic: csrrsi + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } + - { kinds: [immediate], immediate_predicate: UIMM5, name: ZIMM } + num_explicit_defs: 1 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: RD_CSR_IMM + - + id: 1082 + symbol: CSRRCI + name: CSRRCI + assembly_mnemonic: csrrci + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM12, name: CSR } + - { kinds: [immediate], immediate_predicate: UIMM5, name: ZIMM } + num_explicit_defs: 1 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: RD_CSR_IMM + - + id: 1027 + symbol: ADD + name: ADD + assembly_mnemonic: add + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1028 + symbol: SUB + name: SUB + assembly_mnemonic: sub + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: R + assembly_format: RD_RS1_RS2 + - + id: 1029 + symbol: LD + name: LD + assembly_mnemonic: ld + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1030 + symbol: SD + name: SD + assembly_mnemonic: sd + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: S + assembly_format: RS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1031 + symbol: BEQ + name: BEQ + assembly_mnemonic: beq + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: B + assembly_format: RS1_RS2_TARGET + - + id: 1032 + symbol: BNE + name: BNE + assembly_mnemonic: bne + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS2 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: B + assembly_format: RS1_RS2_TARGET + - + id: 1033 + symbol: JAL + name: JAL + assembly_mnemonic: jal + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 1 + flags: [terminator, branch, produces_code] + scheduling_class: BRANCH + encoding_category: J + assembly_format: RD_TARGET + - + id: 1034 + symbol: ECALL + name: ECALL + assembly_mnemonic: ecall + operands: [] + num_explicit_defs: 0 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: NONE + - + id: 1035 + symbol: EBREAK + name: EBREAK + assembly_mnemonic: ebreak + operands: [] + num_explicit_defs: 0 + flags: [has_side_effects, produces_code] + scheduling_class: SYSTEM + encoding_category: SYSTEM + assembly_format: NONE + - + id: 1036 + symbol: SLTI + name: SLTI + assembly_mnemonic: slti + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1037 + symbol: SLTIU + name: SLTIU + assembly_mnemonic: sltiu + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1038 + symbol: XORI + name: XORI + assembly_mnemonic: xori + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1039 + symbol: ORI + name: ORI + assembly_mnemonic: ori + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1040 + symbol: ANDI + name: ANDI + assembly_mnemonic: andi + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1041 + symbol: SLLI + name: SLLI + assembly_mnemonic: slli + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: ALU + encoding_category: I + assembly_format: RD_RS1_IMM + - + id: 1096 + symbol: LR_W + name: LR_W + assembly_mnemonic: lr.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_PAREN_RS1 + requires_memory_operands: true + - + id: 1097 + symbol: SC_W + name: SC_W + assembly_mnemonic: sc.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1098 + symbol: AMOSWAP_W + name: AMOSWAP_W + assembly_mnemonic: amoswap.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1118 + symbol: FLW + name: FLW + assembly_mnemonic: flw + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, memory_role: value, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: FRD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1119 + symbol: FSW + name: FSW + assembly_mnemonic: fsw + operands: + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, memory_role: value, name: FRS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: S + assembly_format: FRS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1120 + symbol: FMADD_S + name: FMADD_S + assembly_mnemonic: fmadd.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1121 + symbol: FMSUB_S + name: FMSUB_S + assembly_mnemonic: fmsub.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1122 + symbol: FNMSUB_S + name: FNMSUB_S + assembly_mnemonic: fnmsub.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1123 + symbol: FNMADD_S + name: FNMADD_S + assembly_mnemonic: fnmadd.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1124 + symbol: FADD_S + name: FADD_S + assembly_mnemonic: fadd.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1125 + symbol: FSUB_S + name: FSUB_S + assembly_mnemonic: fsub.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1126 + symbol: FMUL_S + name: FMUL_S + assembly_mnemonic: fmul.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1127 + symbol: FDIV_S + name: FDIV_S + assembly_mnemonic: fdiv.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_DIV + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1128 + symbol: FSQRT_S + name: FSQRT_S + assembly_mnemonic: fsqrt.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_SQRT + encoding_category: R + assembly_format: FRD_FRS1_RM + - + id: 1129 + symbol: FSGNJ_S + name: FSGNJ_S + assembly_mnemonic: fsgnj.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1130 + symbol: FSGNJN_S + name: FSGNJN_S + assembly_mnemonic: fsgnjn.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1131 + symbol: FSGNJX_S + name: FSGNJX_S + assembly_mnemonic: fsgnjx.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1132 + symbol: FMIN_S + name: FMIN_S + assembly_mnemonic: fmin.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1133 + symbol: FMAX_S + name: FMAX_S + assembly_mnemonic: fmax.s + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1134 + symbol: FCVT_W_S + name: FCVT_W_S + assembly_mnemonic: fcvt.w.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1135 + symbol: FCVT_WU_S + name: FCVT_WU_S + assembly_mnemonic: fcvt.wu.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1136 + symbol: FCVT_L_S + name: FCVT_L_S + assembly_mnemonic: fcvt.l.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1137 + symbol: FCVT_LU_S + name: FCVT_LU_S + assembly_mnemonic: fcvt.lu.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1138 + symbol: FMV_X_W + name: FMV_X_W + assembly_mnemonic: fmv.x.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1 + - + id: 1139 + symbol: FEQ_S + name: FEQ_S + assembly_mnemonic: feq.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: RD_FRS1_FRS2 + - + id: 1140 + symbol: FLT_S + name: FLT_S + assembly_mnemonic: flt.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: RD_FRS1_FRS2 + - + id: 1141 + symbol: FLE_S + name: FLE_S + assembly_mnemonic: fle.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: RD_FRS1_FRS2 + - + id: 1142 + symbol: FCLASS_S + name: FCLASS_S + assembly_mnemonic: fclass.s + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1 + - + id: 1143 + symbol: FCVT_S_W + name: FCVT_S_W + assembly_mnemonic: fcvt.s.w + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1144 + symbol: FCVT_S_WU + name: FCVT_S_WU + assembly_mnemonic: fcvt.s.wu + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1145 + symbol: FCVT_S_L + name: FCVT_S_L + assembly_mnemonic: fcvt.s.l + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1146 + symbol: FCVT_S_LU + name: FCVT_S_LU + assembly_mnemonic: fcvt.s.lu + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1147 + symbol: FMV_W_X + name: FMV_W_X + assembly_mnemonic: fmv.w.x + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1 + - + id: 1148 + symbol: FLD + name: FLD + assembly_mnemonic: fld + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, memory_role: value, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: I + assembly_format: FRD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1149 + symbol: FSD + name: FSD + assembly_mnemonic: fsd + operands: + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, memory_role: value, name: FRS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: SIMM12, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: S + assembly_format: FRS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1150 + symbol: FMADD_D + name: FMADD_D + assembly_mnemonic: fmadd.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1151 + symbol: FMSUB_D + name: FMSUB_D + assembly_mnemonic: fmsub.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1152 + symbol: FNMSUB_D + name: FNMSUB_D + assembly_mnemonic: fnmsub.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1153 + symbol: FNMADD_D + name: FNMADD_D + assembly_mnemonic: fnmadd.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS3 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R4 + assembly_format: FRD_FRS1_FRS2_FRS3_RM + - + id: 1154 + symbol: FADD_D + name: FADD_D + assembly_mnemonic: fadd.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1155 + symbol: FSUB_D + name: FSUB_D + assembly_mnemonic: fsub.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1156 + symbol: FMUL_D + name: FMUL_D + assembly_mnemonic: fmul.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_MUL + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1157 + symbol: FDIV_D + name: FDIV_D + assembly_mnemonic: fdiv.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_DIV + encoding_category: R + assembly_format: FRD_FRS1_FRS2_RM + - + id: 1158 + symbol: FSQRT_D + name: FSQRT_D + assembly_mnemonic: fsqrt.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_SQRT + encoding_category: R + assembly_format: FRD_FRS1_RM + - + id: 1159 + symbol: FSGNJ_D + name: FSGNJ_D + assembly_mnemonic: fsgnj.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1160 + symbol: FSGNJN_D + name: FSGNJN_D + assembly_mnemonic: fsgnjn.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1161 + symbol: FSGNJX_D + name: FSGNJX_D + assembly_mnemonic: fsgnjx.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1162 + symbol: FMIN_D + name: FMIN_D + assembly_mnemonic: fmin.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1163 + symbol: FMAX_D + name: FMAX_D + assembly_mnemonic: fmax.d + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: FRD_FRS1_FRS2 + - + id: 1164 + symbol: FCVT_W_D + name: FCVT_W_D + assembly_mnemonic: fcvt.w.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1165 + symbol: FCVT_WU_D + name: FCVT_WU_D + assembly_mnemonic: fcvt.wu.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1166 + symbol: FCVT_L_D + name: FCVT_L_D + assembly_mnemonic: fcvt.l.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1167 + symbol: FCVT_LU_D + name: FCVT_LU_D + assembly_mnemonic: fcvt.lu.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1_RM + - + id: 1168 + symbol: FMV_X_D + name: FMV_X_D + assembly_mnemonic: fmv.x.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1 + - + id: 1169 + symbol: FEQ_D + name: FEQ_D + assembly_mnemonic: feq.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: RD_FRS1_FRS2 + - + id: 1170 + symbol: FLT_D + name: FLT_D + assembly_mnemonic: flt.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: RD_FRS1_FRS2 + - + id: 1171 + symbol: FLE_D + name: FLE_D + assembly_mnemonic: fle.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_ADD + encoding_category: R + assembly_format: RD_FRS1_FRS2 + - + id: 1172 + symbol: FCLASS_D + name: FCLASS_D + assembly_mnemonic: fclass.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: RD_FRS1 + - + id: 1173 + symbol: FCVT_D_W + name: FCVT_D_W + assembly_mnemonic: fcvt.d.w + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1174 + symbol: FCVT_D_WU + name: FCVT_D_WU + assembly_mnemonic: fcvt.d.wu + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1175 + symbol: FCVT_D_L + name: FCVT_D_L + assembly_mnemonic: fcvt.d.l + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1176 + symbol: FCVT_D_LU + name: FCVT_D_LU + assembly_mnemonic: fcvt.d.lu + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1_RM + - + id: 1177 + symbol: FMV_D_X + name: FMV_D_X + assembly_mnemonic: fmv.d.x + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, name: RS1 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_RS1 + - + id: 1178 + symbol: FCVT_S_D + name: FCVT_S_D + assembly_mnemonic: fcvt.s.d + operands: + - { kinds: [register], role: def, register_class: FPR32, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_FRS1_RM + - + id: 1180 + symbol: C_ADDI4SPN + name: C_ADDI4SPN + assembly_mnemonic: c.addi4spn + operands: + - { kinds: [register], role: def, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: C_UIMM10_NZ_A4, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM_SP + - + id: 1181 + symbol: C_FLD + name: C_FLD + assembly_mnemonic: c.fld + operands: + - { kinds: [register], role: def, register_class: FPR64C, register_bank: FPR, memory_role: value, name: FRD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: C_UIMM8_A8, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: C + assembly_format: FRD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1182 + symbol: C_LW + name: C_LW + assembly_mnemonic: c.lw + operands: + - { kinds: [register], role: def, register_class: GPRC, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: C_UIMM7_A4, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: C + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1183 + symbol: C_LD + name: C_LD + assembly_mnemonic: c.ld + operands: + - { kinds: [register], role: def, register_class: GPRC, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: C_UIMM8_A8, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: LOAD + encoding_category: C + assembly_format: RD_OFFSET_RS1 + requires_memory_operands: true + - + id: 1184 + symbol: C_FSD + name: C_FSD + assembly_mnemonic: c.fsd + operands: + - { kinds: [register], role: use, register_class: FPR64C, register_bank: FPR, memory_role: value, name: FRS2 } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: C_UIMM8_A8, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: C + assembly_format: FRS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1185 + symbol: C_SW + name: C_SW + assembly_mnemonic: c.sw + operands: + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: C_UIMM7_A4, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: C + assembly_format: RS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1186 + symbol: C_SD + name: C_SD + assembly_mnemonic: c.sd + operands: + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, memory_role: address, name: RS1 } + - { kinds: [immediate], immediate_predicate: C_UIMM8_A8, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + scheduling_class: STORE + encoding_category: C + assembly_format: RS2_OFFSET_RS1 + requires_memory_operands: true + - + id: 1187 + symbol: C_ADDI + name: C_ADDI + assembly_mnemonic: c.addi + operands: + - { kinds: [register], role: def_use, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: C_SIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1188 + symbol: C_ADDIW + name: C_ADDIW + assembly_mnemonic: c.addiw + operands: + - { kinds: [register], role: def_use, register_class: GPR_NX0, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: C_SIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1189 + symbol: C_LI + name: C_LI + assembly_mnemonic: c.li + operands: + - { kinds: [register], role: def, register_class: GPR_NX0, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: C_SIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1190 + symbol: C_ADDI16SP + name: C_ADDI16SP + assembly_mnemonic: c.addi16sp + operands: + - { kinds: [immediate], immediate_predicate: C_SIMM10_A16_NZ, name: IMM } + num_explicit_defs: 0 + flags: [produces_code] + implicit_defs: [{ register: X2 }] + implicit_uses: [{ register: X2 }] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: IMM_SP + - + id: 1191 + symbol: C_LUI + name: C_LUI + assembly_mnemonic: c.lui + operands: + - { kinds: [register], role: def, register_class: GPR_NX0_NX2, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: C_SIMM6_NZ, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1192 + symbol: C_SRLI + name: C_SRLI + assembly_mnemonic: c.srli + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1193 + symbol: C_SRAI + name: C_SRAI + assembly_mnemonic: c.srai + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1194 + symbol: C_ANDI + name: C_ANDI + assembly_mnemonic: c.andi + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: C_SIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1195 + symbol: C_SUB + name: C_SUB + assembly_mnemonic: c.sub + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1196 + symbol: C_XOR + name: C_XOR + assembly_mnemonic: c.xor + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1197 + symbol: C_OR + name: C_OR + assembly_mnemonic: c.or + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1198 + symbol: C_AND + name: C_AND + assembly_mnemonic: c.and + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1199 + symbol: C_SUBW + name: C_SUBW + assembly_mnemonic: c.subw + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1200 + symbol: C_ADDW + name: C_ADDW + assembly_mnemonic: c.addw + operands: + - { kinds: [register], role: def_use, register_class: GPRC, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1201 + symbol: C_J + name: C_J + assembly_mnemonic: c.j + operands: + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: TARGET + - + id: 1202 + symbol: C_BEQZ + name: C_BEQZ + assembly_mnemonic: c.beqz + operands: + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS1 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RS1_TARGET + - + id: 1203 + symbol: C_BNEZ + name: C_BNEZ + assembly_mnemonic: c.bnez + operands: + - { kinds: [register], role: use, register_class: GPRC, register_bank: GPR, name: RS1 } + - { kinds: [basic_block], name: TARGET } + num_explicit_defs: 0 + flags: [terminator, branch, produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RS1_TARGET + - + id: 1204 + symbol: C_SLLI + name: C_SLLI + assembly_mnemonic: c.slli + operands: + - { kinds: [register], role: def_use, register_class: GPR_NX0, register_bank: GPR, name: RD } + - { kinds: [immediate], immediate_predicate: UIMM6, name: IMM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_IMM + - + id: 1205 + symbol: C_FLDSP + name: C_FLDSP + assembly_mnemonic: c.fldsp + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, memory_role: value, name: FRD } + - { kinds: [immediate], immediate_predicate: C_UIMM9_A8, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: LOAD + encoding_category: C + assembly_format: FRD_OFFSET_SP + requires_memory_operands: true + - + id: 1206 + symbol: C_LWSP + name: C_LWSP + assembly_mnemonic: c.lwsp + operands: + - { kinds: [register], role: def, register_class: GPR_NX0, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [immediate], immediate_predicate: C_UIMM8_A4, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: LOAD + encoding_category: C + assembly_format: RD_OFFSET_SP + requires_memory_operands: true + - + id: 1207 + symbol: C_LDSP + name: C_LDSP + assembly_mnemonic: c.ldsp + operands: + - { kinds: [register], role: def, register_class: GPR_NX0, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [immediate], immediate_predicate: C_UIMM9_A8, name: IMM } + num_explicit_defs: 1 + flags: [may_load, produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: LOAD + encoding_category: C + assembly_format: RD_OFFSET_SP + requires_memory_operands: true + - + id: 1208 + symbol: C_JR + name: C_JR + assembly_mnemonic: c.jr + operands: + - { kinds: [register], role: use, register_class: GPR_NX0, register_bank: GPR, name: RS1 } + num_explicit_defs: 0 + flags: [terminator, branch, indirect_branch, produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RS1 + - + id: 1209 + symbol: C_MV + name: C_MV + assembly_mnemonic: c.mv + operands: + - { kinds: [register], role: def, register_class: GPR_NX0, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR_NX0, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1210 + symbol: C_EBREAK + name: C_EBREAK + assembly_mnemonic: c.ebreak + operands: [] + num_explicit_defs: 0 + flags: [has_side_effects, produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: NONE + - + id: 1211 + symbol: C_JALR + name: C_JALR + assembly_mnemonic: c.jalr + operands: + - { kinds: [register], role: use, register_class: GPR_NX0, register_bank: GPR, name: RS1 } + num_explicit_defs: 0 + flags: [terminator, branch, indirect_branch, produces_code] + implicit_defs: [{ register: X1 }] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RS1 + - + id: 1212 + symbol: C_ADD + name: C_ADD + assembly_mnemonic: c.add + operands: + - { kinds: [register], role: def_use, register_class: GPR_NX0, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR_NX0, register_bank: GPR, name: RS2 } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: COMPRESSED + encoding_category: C + assembly_format: RD_RS2 + - + id: 1213 + symbol: C_FSDSP + name: C_FSDSP + assembly_mnemonic: c.fsdsp + operands: + - { kinds: [register], role: use, register_class: FPR64, register_bank: FPR, memory_role: value, name: FRS2 } + - { kinds: [immediate], immediate_predicate: C_UIMM9_A8, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: STORE + encoding_category: C + assembly_format: FRS2_OFFSET_SP + requires_memory_operands: true + - + id: 1214 + symbol: C_SWSP + name: C_SWSP + assembly_mnemonic: c.swsp + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [immediate], immediate_predicate: C_UIMM8_A4, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: STORE + encoding_category: C + assembly_format: RS2_OFFSET_SP + requires_memory_operands: true + - + id: 1215 + symbol: C_SDSP + name: C_SDSP + assembly_mnemonic: c.sdsp + operands: + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [immediate], immediate_predicate: C_UIMM9_A8, name: IMM } + num_explicit_defs: 0 + flags: [may_store, produces_code] + implicit_uses: [{ register: X2 }] + scheduling_class: STORE + encoding_category: C + assembly_format: RS2_OFFSET_SP + requires_memory_operands: true + - + id: 1179 + symbol: FCVT_D_S + name: FCVT_D_S + assembly_mnemonic: fcvt.d.s + operands: + - { kinds: [register], role: def, register_class: FPR64, register_bank: FPR, name: FRD } + - { kinds: [register], role: use, register_class: FPR32, register_bank: FPR, name: FRS1 } + - { kinds: [immediate], immediate_predicate: RM, name: RM } + num_explicit_defs: 1 + flags: [produces_code] + scheduling_class: FP_CONVERT + encoding_category: R + assembly_format: FRD_FRS1_RM + - + id: 1099 + symbol: AMOADD_W + name: AMOADD_W + assembly_mnemonic: amoadd.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1100 + symbol: AMOXOR_W + name: AMOXOR_W + assembly_mnemonic: amoxor.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1101 + symbol: AMOAND_W + name: AMOAND_W + assembly_mnemonic: amoand.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1102 + symbol: AMOOR_W + name: AMOOR_W + assembly_mnemonic: amoor.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1103 + symbol: AMOMIN_W + name: AMOMIN_W + assembly_mnemonic: amomin.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1104 + symbol: AMOMAX_W + name: AMOMAX_W + assembly_mnemonic: amomax.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1105 + symbol: AMOMINU_W + name: AMOMINU_W + assembly_mnemonic: amominu.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1106 + symbol: AMOMAXU_W + name: AMOMAXU_W + assembly_mnemonic: amomaxu.w + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1107 + symbol: LR_D + name: LR_D + assembly_mnemonic: lr.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_PAREN_RS1 + requires_memory_operands: true + - + id: 1108 + symbol: SC_D + name: SC_D + assembly_mnemonic: sc.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1109 + symbol: AMOSWAP_D + name: AMOSWAP_D + assembly_mnemonic: amoswap.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1110 + symbol: AMOADD_D + name: AMOADD_D + assembly_mnemonic: amoadd.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1111 + symbol: AMOXOR_D + name: AMOXOR_D + assembly_mnemonic: amoxor.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1112 + symbol: AMOAND_D + name: AMOAND_D + assembly_mnemonic: amoand.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1113 + symbol: AMOOR_D + name: AMOOR_D + assembly_mnemonic: amoor.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1114 + symbol: AMOMIN_D + name: AMOMIN_D + assembly_mnemonic: amomin.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1115 + symbol: AMOMAX_D + name: AMOMAX_D + assembly_mnemonic: amomax.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1116 + symbol: AMOMINU_D + name: AMOMINU_D + assembly_mnemonic: amominu.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1117 + symbol: AMOMAXU_D + name: AMOMAXU_D + assembly_mnemonic: amomaxu.d + operands: + - { kinds: [register], role: def, register_class: GPR, register_bank: GPR, memory_role: value, name: RD } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: value, name: RS2 } + - { kinds: [register], role: use, register_class: GPR, register_bank: GPR, memory_role: address, name: RS1 } + num_explicit_defs: 1 + flags: [may_load, may_store, produces_code] + scheduling_class: ATOMIC + encoding_category: AMO + assembly_format: RD_RS2_PAREN_RS1 + requires_memory_operands: true + - + id: 1216 + symbol: PseudoCC_COPY + name: PseudoCC_COPY + operands: + - { kinds: [register], role: def } + - { kinds: [register], role: use } + - { kinds: [immediate] } + num_explicit_defs: 1 + flags: [pseudo, produces_code, allowed_pre_legalizer] + owner: instruction_select + deadline: selected + - + id: 1217 + symbol: PseudoLOAD_STACK_ARG + name: PseudoLOAD_STACK_ARG + operands: + - { kinds: [register], role: def, memory_role: value } + - { kinds: [frame_index] } + - { kinds: [immediate, integer_immediate] } + - { kinds: [immediate] } + num_explicit_defs: 1 + flags: [pseudo, produces_code, allowed_pre_legalizer, may_load] + requires_memory_operands: true + owner: instruction_select + deadline: selected + - + id: 1218 + symbol: PseudoSTORE_STACK_ARG + name: PseudoSTORE_STACK_ARG + operands: + - { kinds: [register], role: use, memory_role: value } + - { kinds: [frame_index] } + - { kinds: [immediate, integer_immediate] } + - { kinds: [immediate] } + num_explicit_defs: 0 + flags: [pseudo, produces_code, allowed_pre_legalizer, may_store] + requires_memory_operands: true + owner: instruction_select + deadline: selected + - + id: 1219 + symbol: PseudoBYVAL_COPY + name: PseudoBYVAL_COPY + operands: + - { kinds: [register], role: def } + - { kinds: [register], role: use, memory_role: address } + - { kinds: [frame_index] } + - { kinds: [immediate, integer_immediate] } + - { kinds: [immediate, integer_immediate] } + num_explicit_defs: 1 + flags: [pseudo, produces_code, allowed_pre_legalizer, may_load, may_store] + requires_memory_operands: true + owner: instruction_select + deadline: selected + - + id: 1220 + symbol: ADJCALLSTACKDOWN + name: ADJCALLSTACKDOWN + operands: + - { kinds: [immediate, integer_immediate] } + - { kinds: [immediate, integer_immediate] } + num_explicit_defs: 0 + flags: [pseudo, allowed_pre_legalizer, has_side_effects] + owner: prologue_epilogue_insertion + deadline: frame_finalized + - + id: 1221 + symbol: ADJCALLSTACKUP + name: ADJCALLSTACKUP + operands: + - { kinds: [immediate, integer_immediate] } + - { kinds: [immediate, integer_immediate] } + num_explicit_defs: 0 + flags: [pseudo, allowed_pre_legalizer, has_side_effects] + owner: prologue_epilogue_insertion + deadline: frame_finalized + - + id: 1222 + symbol: PseudoCALL + name: PseudoCALL + operands: + - { kinds: [global_symbol, external_symbol, register], role: use, allowed_target_flags: 1 } + - { kinds: [immediate, integer_immediate] } + - { kinds: [register_mask] } + num_explicit_defs: 0 + implicit_defs: [{ register: X1 }] + allow_extra_implicit_operands: true + flags: [pseudo, produces_code, allowed_pre_legalizer, call, may_load, may_store, has_side_effects, not_duplicable, unmodeled_side_effects] + owner: post_ra_expansion + deadline: post_ra_finalized + - + id: 1223 + symbol: PseudoTAIL + name: PseudoTAIL + operands: + - { kinds: [global_symbol, external_symbol, register], role: use, allowed_target_flags: 1 } + - { kinds: [immediate, integer_immediate] } + - { kinds: [register_mask] } + num_explicit_defs: 0 + allow_extra_implicit_operands: true + flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, branch, call, barrier, may_load, may_store, has_side_effects, not_duplicable, unmodeled_side_effects] + owner: post_ra_expansion + deadline: post_ra_finalized + - + id: 1224 + symbol: PseudoRET + name: PseudoRET + operands: [] + num_explicit_defs: 0 + implicit_uses: [{ register: X1 }] + allow_extra_implicit_operands: true + flags: [pseudo, produces_code, allowed_pre_legalizer, terminator, return, barrier] + owner: post_ra_expansion + deadline: post_ra_finalized diff --git a/backend/lib/Target/RISCV/RISCVTarget.cpp b/backend/lib/Target/RISCV/RISCVTarget.cpp index bbad827..8b3741a 100644 --- a/backend/lib/Target/RISCV/RISCVTarget.cpp +++ b/backend/lib/Target/RISCV/RISCVTarget.cpp @@ -2,11 +2,15 @@ #include "rcc/Target/RISCV/RISCVTarget.h" +#include "rcc/CodeGen/GenericOpcodes.h" + +#include <array> #include <cassert> #include <cstddef> #include <cstdint> #include <initializer_list> #include <memory> +#include <span> #include <utility> #include <vector> @@ -93,6 +97,27 @@ Expected<TargetMIRTextInfo> createMIRTextInfo() { return TargetMIRTextInfo::create(std::move(Description), *Registers); } +Expected<TargetDescription> createTargetDescription() { + auto Registers = createRegisterInfo(); + if (!Registers) + return std::unexpected(Registers.error()); + + std::vector<InstructionDescriptor> Descriptors; + std::vector<rcc::ImmediatePredicate> Predicates; + appendGeneratedInstructionInfo(Descriptors, Predicates); + auto GenericInfo = appendGenericInstructionInfo(Descriptors, Predicates); + if (!GenericInfo) + return std::unexpected(GenericInfo.error()); + auto Instructions = InstructionSet::create(std::move(Descriptors), std::move(Predicates)); + if (!Instructions) + return std::unexpected(Instructions.error()); + + TargetMIRTextInfoDesc MIRText; + appendGeneratedMIRTextInfo(MIRText); + return TargetDescription::create(std::move(*Instructions), std::move(*Registers), + std::move(MIRText)); +} + std::shared_ptr<const RegisterMask> createCallPreservedMask() { TargetMIRTextInfoDesc Description; appendGeneratedMIRTextInfo(Description); @@ -100,4 +125,40 @@ std::shared_ptr<const RegisterMask> createCallPreservedMask() { return Description.RegisterMasks.front().Mask; } +std::span<const SchedulingClassInfo> schedulingClasses() noexcept { + return GeneratedSchedulingClasses; +} + +std::span<const EncodingCategoryInfo> encodingCategories() noexcept { + return GeneratedEncodingCategories; +} + +std::span<const AssemblyFormatInfo> assemblyFormats() noexcept { + return GeneratedAssemblyFormats; +} + +std::span<const AssemblyInstructionInfo> assemblyInstructions() noexcept { + return GeneratedAssemblyInstructions; +} + +const AssemblyInstructionInfo *assemblyInstruction(Opcode InstructionOpcode) noexcept { + for (const AssemblyInstructionInfo &Info : GeneratedAssemblyInstructions) { + if (Info.InstructionOpcode == InstructionOpcode) + return &Info; + } + return nullptr; +} + +std::span<const CallingConventionInfo> callingConventions() noexcept { + return GeneratedCallingConventions; +} + +const CallingConventionInfo *callingConvention(CallingConvention ID) noexcept { + for (const CallingConventionInfo &Info : GeneratedCallingConventions) { + if (Info.ID == ID) + return &Info; + } + return nullptr; +} + } // namespace rcc::riscv |
