diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-01 12:05:36 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-01 12:05:36 +0800 |
| commit | fd8770b01a7a3ae85ba85fb43b21803c88593ad7 (patch) | |
| tree | 89b0e50e83e174a7ecd2a30fc517f431ca270612 /backend/include/rcc/CodeGen | |
| parent | c759cebef15bdac2ef160065efd116fe6ed540a7 (diff) | |
| download | rcc-project-fd8770b01a7a3ae85ba85fb43b21803c88593ad7.tar.gz rcc-project-fd8770b01a7a3ae85ba85fb43b21803c88593ad7.tar.xz | |
[CodeGen] Add machine instruction descriptors
Introduce an immutable instruction registry with exact operand, implicit register, tie, pseudo lifecycle, and memory constraints. Validate descriptor tables before publication and use the same rules to verify MachineInstr instances.
Diffstat (limited to 'backend/include/rcc/CodeGen')
| -rw-r--r-- | backend/include/rcc/CodeGen/InstructionDescriptor.h | 264 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineIRTypes.h | 10 | ||||
| -rw-r--r-- | backend/include/rcc/CodeGen/MachineOperand.h | 1 |
3 files changed, 275 insertions, 0 deletions
diff --git a/backend/include/rcc/CodeGen/InstructionDescriptor.h b/backend/include/rcc/CodeGen/InstructionDescriptor.h new file mode 100644 index 0000000..c6049b9 --- /dev/null +++ b/backend/include/rcc/CodeGen/InstructionDescriptor.h @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_INSTRUCTIONDESCRIPTOR_H +#define RCC_CODEGEN_INSTRUCTIONDESCRIPTOR_H + +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/MachineOperand.h" +#include "rcc/CodeGen/Register.h" +#include "rcc/Support/Error.h" + +#include <cstddef> +#include <cstdint> +#include <functional> +#include <initializer_list> +#include <optional> +#include <span> +#include <string> +#include <string_view> +#include <unordered_map> +#include <utility> +#include <vector> + +namespace rcc { + +class MachineInstr; +class MachineRegisterInfo; + +class OperandKindSet final { +public: + static_assert(static_cast<std::uint32_t>(MachineOperand::Kind::Count) <= 32); + + constexpr OperandKindSet() noexcept = default; + + OperandKindSet(std::initializer_list<MachineOperand::Kind> Kinds) noexcept; + + [[nodiscard]] constexpr bool empty() const noexcept { + return Mask == 0; + } + + [[nodiscard]] constexpr bool contains(MachineOperand::Kind Kind) const noexcept { + const auto Index = static_cast<std::uint32_t>(Kind); + if (Index >= static_cast<std::uint32_t>(MachineOperand::Kind::Count)) + return false; + return (Mask & (std::uint32_t{1} << Index)) != 0; + } + + constexpr void add(MachineOperand::Kind Kind) noexcept { + const auto Index = static_cast<std::uint32_t>(Kind); + if (Index < static_cast<std::uint32_t>(MachineOperand::Kind::Count)) + Mask |= std::uint32_t{1} << Index; + } + + [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { + return Mask; + } + + friend constexpr bool operator==(OperandKindSet Left, OperandKindSet Right) noexcept = default; + +private: + std::uint32_t Mask = 0; +}; + +enum class RegisterOperandRole : std::uint8_t { + None, + Def, + Use, + DefUse, +}; + +enum class MemoryOperandRole : std::uint8_t { + None, + Address, + Value, + Size, + Ordering, +}; + +enum class InstructionFlag : std::uint8_t { + Terminator, + Branch, + IndirectBranch, + Call, + Return, + Barrier, + MayLoad, + MayStore, + HasSideEffects, + Pseudo, + Meta, + AllowedPreLegalizer, + ProducesCode, + Commutable, + Rematerializable, + Predicable, + NotDuplicable, + Convergent, + UnmodeledSideEffects, + Phi, + Generic, + TerminalEmission, + Count, +}; + +class InstructionFlags final { +public: + static_assert(static_cast<std::uint32_t>(InstructionFlag::Count) <= 32); + + constexpr InstructionFlags() noexcept = default; + + InstructionFlags(std::initializer_list<InstructionFlag> Flags) noexcept; + + [[nodiscard]] constexpr bool has(InstructionFlag Flag) const noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + if (Index >= static_cast<std::uint32_t>(InstructionFlag::Count)) + return false; + return (Mask & (std::uint32_t{1} << Index)) != 0; + } + + constexpr void set(InstructionFlag Flag) noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + if (Index < static_cast<std::uint32_t>(InstructionFlag::Count)) + Mask |= std::uint32_t{1} << Index; + } + + constexpr void clear(InstructionFlag Flag) noexcept { + const auto Index = static_cast<std::uint32_t>(Flag); + if (Index < static_cast<std::uint32_t>(InstructionFlag::Count)) + Mask &= ~(std::uint32_t{1} << Index); + } + + [[nodiscard]] constexpr std::uint32_t rawValue() const noexcept { + return Mask; + } + + friend constexpr bool operator==(InstructionFlags Left, + InstructionFlags Right) noexcept = default; + +private: + std::uint32_t Mask = 0; +}; + +enum class PseudoOwner : std::uint8_t { + None, + Legalizer, + RegisterBankSelect, + InstructionSelect, + PhiElimination, + TwoAddressRewrite, + RegisterAllocator, + PrePEIExpansion, + PrologueEpilogueInsertion, + PostRAExpansion, + Finalization, + AsmPrinter, +}; + +enum class PipelineStage : std::uint8_t { + MachineIRInput, + Legalized, + RegBankSelected, + Selected, + SSAEliminated, + TiedOpsRewritten, + RegisterAllocated, + FrameFinalized, + PostRAFinalized, + Emission, +}; + +struct OperandDescriptor final { + OperandKindSet Kinds; + RegisterOperandRole RegisterRole = RegisterOperandRole::None; + std::optional<RegisterClassID> RegClass; + std::optional<RegisterBankID> RegBank; + std::optional<ImmediatePredicateID> ImmediatePredicate; + MemoryOperandRole MemoryRole = MemoryOperandRole::None; + std::optional<std::size_t> DefaultTiedOperand; + bool EarlyClobber = false; + bool Optional = false; + bool VariadicGroup = false; + bool AllowSubReg = false; + std::optional<NamedOperandID> Name; + std::optional<TargetOperandTypeID> TargetOperandType; + std::uint32_t AllowedTargetFlags = 0; +}; + +struct ImplicitRegisterDescriptor final { + PhysicalRegister Reg; + bool EarlyClobber = false; + bool Renamable = false; + + friend bool operator==(const ImplicitRegisterDescriptor &Left, + const ImplicitRegisterDescriptor &Right) = default; +}; + +struct InstructionDescriptor final { + Opcode InstructionOpcode; + std::string Name; + std::vector<OperandDescriptor> Operands; + std::size_t NumExplicitDefs = 0; + bool Variadic = false; + std::vector<ImplicitRegisterDescriptor> ImplicitDefs; + std::vector<ImplicitRegisterDescriptor> ImplicitUses; + bool AllowExtraImplicitOperands = false; + InstructionFlags Flags; + SchedulingClassID SchedulingClass; + EncodingCategoryID EncodingCategory; + AssemblyFormatID AssemblyFormat; + bool RequiresMemoryOperands = false; + PseudoOwner Owner = PseudoOwner::None; + PipelineStage Deadline = PipelineStage::Emission; +}; + +struct ImmediatePredicate final { + ImmediatePredicateID ID; + std::string Name; + std::function<bool(const MachineOperand &)> Predicate; +}; + +class InstructionSet final { +public: + [[nodiscard]] static Expected<InstructionSet> + create(std::vector<InstructionDescriptor> Descriptors, + std::vector<ImmediatePredicate> ImmediatePredicates = {}); + + [[nodiscard]] const InstructionDescriptor *descriptor(Opcode InstructionOpcode) const noexcept; + [[nodiscard]] const InstructionDescriptor *descriptor(std::string_view Name) const noexcept; + [[nodiscard]] std::span<const InstructionDescriptor> descriptors() const noexcept { + return Descriptors; + } + + [[nodiscard]] Expected<void> validateExplicitOperands(Opcode InstructionOpcode, + std::span<const MachineOperand> Operands, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected<void> validateInstruction(const MachineInstr &Instruction, + const MachineRegisterInfo &RegInfo) const; + + [[nodiscard]] Expected<std::vector<MachineOperand>> + createDefaultImplicitOperands(const InstructionDescriptor &Descriptor) const; + +private: + InstructionSet(std::vector<InstructionDescriptor> Descriptors, + std::vector<ImmediatePredicate> ImmediatePredicates) + : Descriptors(std::move(Descriptors)), ImmediatePredicates(std::move(ImmediatePredicates)) {} + + [[nodiscard]] const ImmediatePredicate * + immediatePredicate(ImmediatePredicateID ID) const noexcept; + [[nodiscard]] Expected<void> validateExplicitOperands(const InstructionDescriptor &Descriptor, + std::span<const MachineOperand> Operands, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected<void> validateOperand(const OperandDescriptor &Descriptor, + const MachineOperand &Operand, + const MachineRegisterInfo &RegInfo) const; + + std::vector<InstructionDescriptor> Descriptors; + std::vector<ImmediatePredicate> ImmediatePredicates; + std::unordered_map<Opcode, std::size_t> OpcodeToIndex; + std::unordered_map<std::string, std::size_t> NameToIndex; + std::unordered_map<ImmediatePredicateID, std::size_t> PredicateToIndex; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_INSTRUCTIONDESCRIPTOR_H diff --git a/backend/include/rcc/CodeGen/MachineIRTypes.h b/backend/include/rcc/CodeGen/MachineIRTypes.h index 6d2a710..de6be5a 100644 --- a/backend/include/rcc/CodeGen/MachineIRTypes.h +++ b/backend/include/rcc/CodeGen/MachineIRTypes.h @@ -47,6 +47,11 @@ struct SubRegIndexTag; struct RegisterBankIDTag; struct RegisterClassIDTag; struct SchedulingClassIDTag; +struct ImmediatePredicateIDTag; +struct NamedOperandIDTag; +struct TargetOperandTypeIDTag; +struct EncodingCategoryIDTag; +struct AssemblyFormatIDTag; struct SyncScopeIDTag; struct MemoryAliasSourceIDTag; struct OriginIDTag; @@ -61,6 +66,11 @@ using SubRegIndex = MachineIndex<detail::SubRegIndexTag>; using RegisterBankID = MachineIndex<detail::RegisterBankIDTag>; using RegisterClassID = MachineIndex<detail::RegisterClassIDTag>; using SchedulingClassID = MachineIndex<detail::SchedulingClassIDTag>; +using ImmediatePredicateID = MachineIndex<detail::ImmediatePredicateIDTag>; +using NamedOperandID = MachineIndex<detail::NamedOperandIDTag>; +using TargetOperandTypeID = MachineIndex<detail::TargetOperandTypeIDTag>; +using EncodingCategoryID = MachineIndex<detail::EncodingCategoryIDTag>; +using AssemblyFormatID = MachineIndex<detail::AssemblyFormatIDTag>; using SyncScopeID = MachineIndex<detail::SyncScopeIDTag>; using MemoryAliasSourceID = MachineIndex<detail::MemoryAliasSourceIDTag, std::uint64_t>; using OriginID = MachineIndex<detail::OriginIDTag, std::uint64_t>; diff --git a/backend/include/rcc/CodeGen/MachineOperand.h b/backend/include/rcc/CodeGen/MachineOperand.h index 0da9f25..35cf45b 100644 --- a/backend/include/rcc/CodeGen/MachineOperand.h +++ b/backend/include/rcc/CodeGen/MachineOperand.h @@ -213,6 +213,7 @@ public: Metadata, TargetIndex, MCSymbol, + Count, }; MachineOperand(const MachineOperand &) = delete; |
