From 924dcd36ebed84f04729de05ec08b311a36a04c1 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sat, 1 Aug 2026 16:07:24 +0800 Subject: [CodeGen] Add target register descriptions Introduce an immutable register topology for units, subregisters, classes, banks, and preserved masks. Bind instruction descriptors to this topology through TargetDescription so builders, cloning, and verification share one target-aware contract. Add the test-only TestTarget model and positive and negative target fact coverage. --- .../include/rcc/CodeGen/MachineFunctionCloner.h | 6 +- backend/include/rcc/CodeGen/MachineIRBuilder.h | 12 +- backend/include/rcc/CodeGen/MachineIRTypes.h | 2 + backend/include/rcc/CodeGen/MachineVerifier.h | 4 +- backend/include/rcc/CodeGen/TargetDescription.h | 98 +++++++++++ backend/include/rcc/CodeGen/TargetRegisterInfo.h | 192 +++++++++++++++++++++ 6 files changed, 303 insertions(+), 11 deletions(-) create mode 100644 backend/include/rcc/CodeGen/TargetDescription.h create mode 100644 backend/include/rcc/CodeGen/TargetRegisterInfo.h (limited to 'backend/include/rcc/CodeGen') diff --git a/backend/include/rcc/CodeGen/MachineFunctionCloner.h b/backend/include/rcc/CodeGen/MachineFunctionCloner.h index 658614f..09877d2 100644 --- a/backend/include/rcc/CodeGen/MachineFunctionCloner.h +++ b/backend/include/rcc/CodeGen/MachineFunctionCloner.h @@ -15,10 +15,10 @@ namespace rcc { -class InstructionSet; class MachineBasicBlock; class MachineFunction; class MachineInstr; +class TargetDescription; struct MachineFunctionCloneOptions final { MachineFunctionStableID NewStableID; @@ -81,12 +81,12 @@ private: const std::unordered_map &Instructions; friend Expected - cloneMachineFunction(const MachineFunction &Source, const InstructionSet &Instructions, + cloneMachineFunction(const MachineFunction &Source, const TargetDescription &Target, MachineFunctionCloneOptions Options); }; [[nodiscard]] Expected -cloneMachineFunction(const MachineFunction &Source, const InstructionSet &Instructions, +cloneMachineFunction(const MachineFunction &Source, const TargetDescription &Target, MachineFunctionCloneOptions Options); } // namespace rcc diff --git a/backend/include/rcc/CodeGen/MachineIRBuilder.h b/backend/include/rcc/CodeGen/MachineIRBuilder.h index 47fd63c..08ec9ba 100644 --- a/backend/include/rcc/CodeGen/MachineIRBuilder.h +++ b/backend/include/rcc/CodeGen/MachineIRBuilder.h @@ -3,10 +3,10 @@ #ifndef RCC_CODEGEN_MACHINEIRBUILDER_H #define RCC_CODEGEN_MACHINEIRBUILDER_H -#include "rcc/CodeGen/InstructionDescriptor.h" #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/Register.h" +#include "rcc/CodeGen/TargetDescription.h" #include "rcc/Support/Error.h" #include @@ -90,7 +90,7 @@ public: [[nodiscard]] Expected build(); private: - MachineInstrBuilder(MachineFunction &Function, const InstructionSet &Instructions, + MachineInstrBuilder(MachineFunction &Function, const TargetDescription &Target, const InstructionDescriptor &Descriptor, MachineBasicBlock &InsertBlock, MachineInstr *InsertBefore) noexcept; @@ -106,7 +106,7 @@ private: bool IsImplicit); MachineFunction *Function; - const InstructionSet *Instructions; + const TargetDescription *Target; const InstructionDescriptor *Descriptor; MachineBasicBlock *InsertBlock; MachineInstr *InsertBefore; @@ -124,8 +124,8 @@ private: class MachineIRBuilder final { public: - MachineIRBuilder(MachineFunction &Function, const InstructionSet &Instructions) noexcept - : Function(&Function), Instructions(&Instructions) {} + MachineIRBuilder(MachineFunction &Function, const TargetDescription &Target) noexcept + : Function(&Function), Target(&Target) {} MachineIRBuilder(const MachineIRBuilder &) = delete; MachineIRBuilder &operator=(const MachineIRBuilder &) = delete; MachineIRBuilder(MachineIRBuilder &&) = delete; @@ -154,7 +154,7 @@ private: [[nodiscard]] Expected validateInstruction(const MachineInstr &Instruction) const; MachineFunction *Function; - const InstructionSet *Instructions; + const TargetDescription *Target; MachineBasicBlock *InsertBlock = nullptr; MachineInstr *InsertBefore = nullptr; }; diff --git a/backend/include/rcc/CodeGen/MachineIRTypes.h b/backend/include/rcc/CodeGen/MachineIRTypes.h index 058cacb..8906bbe 100644 --- a/backend/include/rcc/CodeGen/MachineIRTypes.h +++ b/backend/include/rcc/CodeGen/MachineIRTypes.h @@ -44,6 +44,7 @@ struct ConstantPoolIndexTag; struct JumpTableIndexTag; struct TargetIndexTag; struct SubRegIndexTag; +struct RegisterUnitIDTag; struct RegisterBankIDTag; struct RegisterClassIDTag; struct SchedulingClassIDTag; @@ -66,6 +67,7 @@ using ConstantPoolIndex = MachineIndex; using JumpTableIndex = MachineIndex; using TargetIndex = MachineIndex; using SubRegIndex = MachineIndex; +using RegisterUnitID = MachineIndex; using RegisterBankID = MachineIndex; using RegisterClassID = MachineIndex; using SchedulingClassID = MachineIndex; diff --git a/backend/include/rcc/CodeGen/MachineVerifier.h b/backend/include/rcc/CodeGen/MachineVerifier.h index b1035a2..efe430e 100644 --- a/backend/include/rcc/CodeGen/MachineVerifier.h +++ b/backend/include/rcc/CodeGen/MachineVerifier.h @@ -3,7 +3,7 @@ #ifndef RCC_CODEGEN_MACHINEVERIFIER_H #define RCC_CODEGEN_MACHINEVERIFIER_H -#include "rcc/CodeGen/InstructionDescriptor.h" +#include "rcc/CodeGen/TargetDescription.h" #include "rcc/Support/Error.h" #include @@ -27,7 +27,7 @@ struct MachineVerifierOptions final { class MachineVerifier final { public: [[nodiscard]] static Expected verify(const MachineFunction &Function, - const InstructionSet &Instructions, + const TargetDescription &Target, MachineVerifierOptions Options = {}); }; diff --git a/backend/include/rcc/CodeGen/TargetDescription.h b/backend/include/rcc/CodeGen/TargetDescription.h new file mode 100644 index 0000000..51a820a --- /dev/null +++ b/backend/include/rcc/CodeGen/TargetDescription.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_TARGETDESCRIPTION_H +#define RCC_CODEGEN_TARGETDESCRIPTION_H + +#include "rcc/CodeGen/InstructionDescriptor.h" +#include "rcc/CodeGen/TargetRegisterInfo.h" +#include "rcc/Support/Error.h" + +#include +#include +#include +#include + +namespace rcc { + +class MachineBasicBlock; +class MachineInstr; +class MachineMemOperand; +class MachineRegisterInfo; +struct VirtualRegisterInfo; + +class TargetDescription final { +public: + TargetDescription(const TargetDescription &) = delete; + TargetDescription &operator=(const TargetDescription &) = delete; + TargetDescription(TargetDescription &&) noexcept = default; + TargetDescription &operator=(TargetDescription &&) noexcept = default; + ~TargetDescription() = default; + + [[nodiscard]] static Expected create(InstructionSet Instructions, + TargetRegisterInfo Registers); + + [[nodiscard]] const InstructionSet &instructions() const noexcept { + return Instructions; + } + + [[nodiscard]] const TargetRegisterInfo ®isters() const noexcept { + return Registers; + } + + [[nodiscard]] const InstructionDescriptor * + instructionDescriptor(Opcode InstructionOpcode) const noexcept { + return Instructions.descriptor(InstructionOpcode); + } + + [[nodiscard]] Expected validateExplicitOperands(Opcode InstructionOpcode, + std::span Operands, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected validateOperandTies(Opcode InstructionOpcode, + std::span ExplicitOperands, + std::span Ties, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected + validateImplicitOperands(Opcode InstructionOpcode, + std::span ImplicitOperands, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected + validateEarlyClobber(std::span ExplicitOperands, + std::span ImplicitOperands, + std::span Ties) const; + [[nodiscard]] Expected + validateMemOperands(Opcode InstructionOpcode, + std::span MemOperands) const { + return Instructions.validateMemOperands(InstructionOpcode, MemOperands); + } + [[nodiscard]] Expected validateInstruction(const MachineInstr &Instruction, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected validateRegisterInfo(const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected validateBlockLiveIns(const MachineBasicBlock &Block) const; + + [[nodiscard]] Expected> + createDefaultImplicitOperands(const InstructionDescriptor &Descriptor) const { + return Instructions.createDefaultImplicitOperands(Descriptor); + } + +private: + TargetDescription(InstructionSet Instructions, TargetRegisterInfo Registers) + : Instructions(std::move(Instructions)), Registers(std::move(Registers)) {} + + [[nodiscard]] Expected validateTargetOperand(const OperandDescriptor *Descriptor, + const MachineOperand &Operand, + const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected validateVirtualRegister(Register Reg, + const VirtualRegisterInfo &Info) const; + [[nodiscard]] std::optional + effectiveRegisterClass(const MachineOperand &Operand, const MachineRegisterInfo &RegInfo) const; + [[nodiscard]] Expected validateTieCompatibility(const MachineOperand &Def, + const MachineOperand &Use, + const MachineRegisterInfo &RegInfo) const; + + InstructionSet Instructions; + TargetRegisterInfo Registers; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_TARGETDESCRIPTION_H diff --git a/backend/include/rcc/CodeGen/TargetRegisterInfo.h b/backend/include/rcc/CodeGen/TargetRegisterInfo.h new file mode 100644 index 0000000..5d7de2c --- /dev/null +++ b/backend/include/rcc/CodeGen/TargetRegisterInfo.h @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef RCC_CODEGEN_TARGETREGISTERINFO_H +#define RCC_CODEGEN_TARGETREGISTERINFO_H + +#include "rcc/CodeGen/MachineIRTypes.h" +#include "rcc/CodeGen/Register.h" +#include "rcc/CodeGen/RegisterMask.h" +#include "rcc/Support/Error.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace rcc { + +struct RegisterUnitDesc final { + RegisterUnitID ID; + std::string Name; +}; + +struct RegisterUnitLane final { + RegisterUnitID Unit; + LaneMask Lanes; +}; + +struct PhysicalRegisterDesc final { + PhysicalRegister Reg; + std::string Name; + std::uint32_t Encoding = 0; + std::vector Units; + bool IsConstant = false; + bool IsArtificial = false; +}; + +struct SubRegIndexDesc final { + SubRegIndex ID; + std::string Name; + LaneMask Lanes; + std::uint32_t SizeInBits = 0; + std::uint32_t OffsetInBits = 0; +}; + +struct PhysicalSubRegisterDesc final { + PhysicalRegister SuperReg; + SubRegIndex Index; + PhysicalRegister SubReg; +}; + +struct SubRegIndexComposition final { + SubRegIndex First; + SubRegIndex Second; + SubRegIndex Result; +}; + +struct RegisterClassDesc final { + RegisterClassID ID; + std::string Name; + std::vector Registers; + std::vector AllocationOrder; + std::uint32_t SizeInBits = 0; + std::uint32_t SpillSizeInBits = 0; + std::uint32_t SpillAlignmentInBits = 0; + LaneMask Lanes; + std::vector SupportedSubRegs; + std::vector SuperClasses; + RegisterBankID DefaultBank; + bool Allocatable = true; + std::uint32_t CopyCost = 1; + bool CoveredBySubRegs = false; +}; + +struct SubRegClassMapping final { + RegisterClassID SourceClass; + SubRegIndex Index; + RegisterClassID ResultClass; +}; + +struct RegisterBankDesc final { + RegisterBankID ID; + std::string Name; + std::uint32_t MaximumSizeInBits = 0; + std::vector RegisterClasses; +}; + +struct TargetRegisterInfoDesc final { + std::vector RegisterUnits; + std::vector PhysicalRegisters; + std::vector SubRegIndices; + std::vector PhysicalSubRegisters; + std::vector SubRegCompositions; + std::vector RegisterClasses; + std::vector SubRegClassMappings; + std::vector RegisterBanks; +}; + +class TargetRegisterInfo final { +public: + [[nodiscard]] static Expected create(TargetRegisterInfoDesc Description); + + [[nodiscard]] std::span registerUnits() const noexcept { + return Description.RegisterUnits; + } + + [[nodiscard]] std::span physicalRegisters() const noexcept { + return Description.PhysicalRegisters; + } + + [[nodiscard]] std::span subRegIndices() const noexcept { + return Description.SubRegIndices; + } + + [[nodiscard]] std::span registerClasses() const noexcept { + return Description.RegisterClasses; + } + + [[nodiscard]] std::span registerBanks() const noexcept { + return Description.RegisterBanks; + } + + [[nodiscard]] const RegisterUnitDesc *registerUnit(RegisterUnitID ID) const noexcept; + [[nodiscard]] const PhysicalRegisterDesc *physicalRegister(PhysicalRegister Reg) const noexcept; + [[nodiscard]] const PhysicalRegisterDesc *physicalRegister(std::string_view Name) const noexcept; + [[nodiscard]] const SubRegIndexDesc *subRegIndex(SubRegIndex Index) const noexcept; + [[nodiscard]] const RegisterClassDesc *registerClass(RegisterClassID ID) const noexcept; + [[nodiscard]] const RegisterBankDesc *registerBank(RegisterBankID ID) const noexcept; + + [[nodiscard]] bool isKnownPhysicalRegister(PhysicalRegister Reg) const noexcept { + return physicalRegister(Reg) != nullptr; + } + + [[nodiscard]] LaneMask registerLaneMask(PhysicalRegister Reg) const noexcept; + [[nodiscard]] bool isValidLaneMask(PhysicalRegister Reg, LaneMask Lanes) const noexcept; + [[nodiscard]] bool regsOverlap(PhysicalRegister Left, PhysicalRegister Right) const noexcept; + [[nodiscard]] std::span aliases(PhysicalRegister Reg) const noexcept; + + [[nodiscard]] std::optional subRegister(PhysicalRegister SuperReg, + SubRegIndex Index) const noexcept; + [[nodiscard]] bool isSubRegister(PhysicalRegister SuperReg, + PhysicalRegister SubReg) const noexcept; + [[nodiscard]] std::span + superRegisters(PhysicalRegister Reg) const noexcept; + [[nodiscard]] std::optional composeSubRegIndices(SubRegIndex First, + SubRegIndex Second) const noexcept; + + [[nodiscard]] bool registerClassContains(RegisterClassID Class, + PhysicalRegister Reg) const noexcept; + [[nodiscard]] bool isSubclass(RegisterClassID Candidate, RegisterClassID Required) const noexcept; + [[nodiscard]] bool registerClassesOverlap(RegisterClassID Left, + RegisterClassID Right) const noexcept; + [[nodiscard]] std::optional subRegClass(RegisterClassID Source, + SubRegIndex Index) const noexcept; + + [[nodiscard]] bool bankCoversClass(RegisterBankID Bank, RegisterClassID Class) const noexcept; + [[nodiscard]] bool bankContainsRegister(RegisterBankID Bank, PhysicalRegister Reg) const noexcept; + [[nodiscard]] bool registerBanksOverlap(RegisterBankID Left, RegisterBankID Right) const noexcept; + + [[nodiscard]] Expected validateRegisterMask(const RegisterMask &Mask) const; + +private: + explicit TargetRegisterInfo(TargetRegisterInfoDesc Description) + : Description(std::move(Description)) {} + + [[nodiscard]] static std::uint64_t pairKey(std::uint32_t First, std::uint32_t Second) noexcept { + return (static_cast(First) << 32U) | Second; + } + + TargetRegisterInfoDesc Description; + std::unordered_map UnitToIndex; + std::unordered_map RegisterToIndex; + std::unordered_map RegisterNameToIndex; + std::unordered_map SubRegIndexToIndex; + std::unordered_map ClassToIndex; + std::unordered_map BankToIndex; + std::unordered_map SubRegisterMap; + std::unordered_map CompositionMap; + std::unordered_map SubRegClassMap; + std::unordered_set SubclassRelations; + std::vector> Aliases; + std::vector> SuperRegisters; +}; + +} // namespace rcc + +#endif // RCC_CODEGEN_TARGETREGISTERINFO_H -- cgit v1.2.3