diff options
Diffstat (limited to 'backend/lib/CodeGen')
| -rw-r--r-- | backend/lib/CodeGen/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineFrameInfo.cpp | 51 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineFunctionCloner.cpp | 6 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineRegisterInfo.cpp | 13 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineVerifier.cpp | 13 | ||||
| -rw-r--r-- | backend/lib/CodeGen/TargetDescription.cpp | 134 | ||||
| -rw-r--r-- | backend/lib/CodeGen/TargetMIRTextInfo.cpp | 368 | ||||
| -rw-r--r-- | backend/lib/CodeGen/TargetRegisterInfo.cpp | 75 |
8 files changed, 643 insertions, 21 deletions
diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt index d0f725d..ce53cd2 100644 --- a/backend/lib/CodeGen/CMakeLists.txt +++ b/backend/lib/CodeGen/CMakeLists.txt @@ -32,6 +32,7 @@ set( TargetConstant.cpp TargetDescription.cpp TargetFunctionState.cpp + TargetMIRTextInfo.cpp TargetRegisterInfo.cpp ) set( @@ -67,6 +68,7 @@ set( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/TargetConstant.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/TargetDescription.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/TargetFunctionState.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/TargetMIRTextInfo.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/TargetRegisterInfo.h" ) @@ -129,6 +131,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/TargetConstant.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TargetDescription.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TargetFunctionState.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/TargetMIRTextInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterInfo.cpp" ${RCCBackendCodeGenHeaders} ) @@ -163,5 +166,6 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/TargetConstant.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TargetDescription.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TargetFunctionState.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/TargetMIRTextInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/TargetRegisterInfo.cpp" ) diff --git a/backend/lib/CodeGen/MachineFrameInfo.cpp b/backend/lib/CodeGen/MachineFrameInfo.cpp index c4d3cda..23f9852 100644 --- a/backend/lib/CodeGen/MachineFrameInfo.cpp +++ b/backend/lib/CodeGen/MachineFrameInfo.cpp @@ -5,17 +5,49 @@ #include <cstddef> #include <cstdint> #include <limits> +#include <string_view> #include <unordered_set> #include <utility> namespace rcc { -Expected<StackID> StackID::targetStack(std::uint32_t Value) { - if (Value < FirstTargetStackValue) { - return makeUnexpected(ErrorCode::InvalidArgument, - "target stack ID must not overlap a built-in stack ID"); - } - return StackID(Value); +Expected<StackID> StackID::fromValue(std::uint32_t Value) { + StackID Result(Value); + if (!Result.isValid()) + return makeUnexpected(ErrorCode::InvalidArgument, "stack ID is not serializable in LLVM MIR"); + return Result; +} + +std::optional<StackID> parseStackIDName(std::string_view Name) noexcept { + if (Name == "default") + return StackID::defaultStack(); + if (Name == "sgpr-spill") + return StackID::sgprSpillStack(); + if (Name == "scalable-vector") + return StackID::scalableVectorStack(); + if (Name == "scalable-predicate-vector") + return StackID::scalablePredicateVectorStack(); + if (Name == "wasm-local") + return StackID::wasmLocalStack(); + if (Name == "noalloc") + return StackID::noAllocStack(); + return std::nullopt; +} + +std::string_view getStackIDName(StackID ID) noexcept { + if (ID == StackID::defaultStack()) + return "default"; + if (ID == StackID::sgprSpillStack()) + return "sgpr-spill"; + if (ID == StackID::scalableVectorStack()) + return "scalable-vector"; + if (ID == StackID::scalablePredicateVectorStack()) + return "scalable-predicate-vector"; + if (ID == StackID::wasmLocalStack()) + return "wasm-local"; + if (ID == StackID::noAllocStack()) + return "noalloc"; + return "unknown"; } bool StackObject::isSpill() const noexcept { @@ -59,10 +91,11 @@ Expected<void> MachineFrameInfo::verifyDescription(const StackObjectDesc &Descri return makeUnexpected(ErrorCode::InvalidArgument, "fixed ABI stack objects require a fixed offset"); } - if (Description.Kind == StackObjectKind::Target && !Description.Stack.isTargetStack() && + if (Description.Kind == StackObjectKind::Target && !Description.Stack.isSpecialStack() && Description.TargetFlags == 0) { - return makeUnexpected(ErrorCode::InvalidArgument, - "target stack objects require a target stack ID or nonzero target flags"); + return makeUnexpected( + ErrorCode::InvalidArgument, + "target stack objects require a special stack ID or nonzero target flags"); } std::unordered_set<MachineInstrStableID> LifetimeBoundaries; diff --git a/backend/lib/CodeGen/MachineFunctionCloner.cpp b/backend/lib/CodeGen/MachineFunctionCloner.cpp index b769f7d..7dcf5e2 100644 --- a/backend/lib/CodeGen/MachineFunctionCloner.cpp +++ b/backend/lib/CodeGen/MachineFunctionCloner.cpp @@ -214,6 +214,12 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { if (!SetResult) return std::unexpected(SetResult.error()); } + if (SourceInfo.TargetFlags != 0) { + auto SetResult = State.Destination.registerInfo().setTargetRegisterFlags( + *DestinationReg, SourceInfo.TargetFlags); + if (!SetResult) + return std::unexpected(SetResult.error()); + } for (const PhysicalRegister Hint : SourceInfo.AllocationHints) { auto AddResult = State.Destination.registerInfo().addAllocationHint(*DestinationReg, Hint); if (!AddResult) diff --git a/backend/lib/CodeGen/MachineRegisterInfo.cpp b/backend/lib/CodeGen/MachineRegisterInfo.cpp index c31b38b..3784b22 100644 --- a/backend/lib/CodeGen/MachineRegisterInfo.cpp +++ b/backend/lib/CodeGen/MachineRegisterInfo.cpp @@ -94,6 +94,7 @@ Expected<void> MachineRegisterInfo::eraseVirtualRegister(Register Reg) { Info->get().Bank.reset(); Info->get().RegClass.reset(); Info->get().AllocationHints.clear(); + Info->get().TargetFlags = 0; return {}; } @@ -188,6 +189,18 @@ Expected<void> MachineRegisterInfo::addAllocationHint(Register Reg, PhysicalRegi return {}; } +Expected<void> MachineRegisterInfo::setTargetRegisterFlags(Register Reg, std::uint8_t Flags) { + auto Info = virtualRegisterInfo(Reg); + if (!Info) + return std::unexpected(Info.error()); + Info->get().TargetFlags = Flags; + return {}; +} + +Expected<void> MachineRegisterInfo::clearTargetRegisterFlags(Register Reg) { + return setTargetRegisterFlags(Reg, 0); +} + void MachineRegisterInfo::clearAllVirtualRegisterTypes() noexcept { for (VirtualRegisterInfo &Info : VirtualRegisters) { if (!Info.IsTombstone) diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index 98fb9f7..fd027fe 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -43,10 +43,17 @@ public: auto CFIResult = Function.cfiInfo().verify(); if (!CFIResult) return failWith("CFI information", CFIResult.error()); + auto TargetCFIResult = Target.validateCFIInfo(Function.cfiInfo()); + if (!TargetCFIResult) + return failWith("target CFI information", TargetCFIResult.error()); if (Function.targetState().hasValue()) { auto TargetStateResult = Function.targetState().verify(); if (!TargetStateResult) return failWith("target function state", TargetStateResult.error()); + const auto RequiredType = Target.mirText().functionStateType(); + if (RequiredType && Function.targetState().typeID() != RequiredType) { + return fail("target function state does not match the target MIR schema"); + } } auto CatalogResult = catalogArenaObjects(); if (!CatalogResult) @@ -54,6 +61,9 @@ public: auto FrameResult = Function.frameInfo().verify(); if (!FrameResult) return failWith("frame info", FrameResult.error()); + auto TargetFrameResult = Target.validateFrameInfo(Function.frameInfo()); + if (!TargetFrameResult) + return failWith("target frame info", TargetFrameResult.error()); auto ConstantPoolResult = Function.constantPool().verify(); if (!ConstantPoolResult) return failWith("constant pool", ConstantPoolResult.error()); @@ -652,7 +662,8 @@ private: for (const VirtualRegisterInfo &Info : RegInfo.virtualRegisters()) { if (Info.IsTombstone) { - if (Info.Type || Info.Bank || Info.RegClass || !Info.AllocationHints.empty()) { + if (Info.Type || Info.Bank || Info.RegClass || !Info.AllocationHints.empty() || + Info.TargetFlags != 0) { return fail("virtual-register tombstone retains semantic state"); } continue; diff --git a/backend/lib/CodeGen/TargetDescription.cpp b/backend/lib/CodeGen/TargetDescription.cpp index a32534d..b9f7606 100644 --- a/backend/lib/CodeGen/TargetDescription.cpp +++ b/backend/lib/CodeGen/TargetDescription.cpp @@ -4,7 +4,10 @@ #include "rcc/CodeGen/LowLevelType.h" #include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineCFIInfo.h" +#include "rcc/CodeGen/MachineFrameInfo.h" #include "rcc/CodeGen/MachineInstr.h" +#include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/MachineOperand.h" #include "rcc/CodeGen/MachineRegisterInfo.h" @@ -47,9 +50,19 @@ namespace { } // namespace Expected<TargetDescription> TargetDescription::create(InstructionSet Instructions, - TargetRegisterInfo Registers) { + TargetRegisterInfo Registers, + TargetMIRTextInfoDesc MIRTextDescription) { + auto MIRText = TargetMIRTextInfo::create(std::move(MIRTextDescription), Registers); + if (!MIRText) + return std::unexpected(MIRText.error()); + for (const InstructionDescriptor &Instruction : Instructions.descriptors()) { for (const OperandDescriptor &Operand : Instruction.Operands) { + if ((Operand.AllowedTargetFlags & ~MIRText->serializableOperandFlagMask()) != 0) { + return makeUnexpected( + ErrorCode::InvalidArgument, + "instruction operand allows a target flag outside the MIR text schema"); + } if (Operand.RegClass && Registers.registerClass(*Operand.RegClass) == nullptr) { return makeUnexpected(ErrorCode::InvalidArgument, "instruction operand references an unknown target register class"); @@ -103,7 +116,7 @@ Expected<TargetDescription> TargetDescription::create(InstructionSet Instruction } } - return TargetDescription(std::move(Instructions), std::move(Registers)); + return TargetDescription(std::move(Instructions), std::move(Registers), std::move(*MIRText)); } Expected<void> TargetDescription::validateVirtualRegister(Register Reg, @@ -113,6 +126,10 @@ Expected<void> TargetDescription::validateVirtualRegister(Register Reg, "target virtual-register validation received a non-virtual register"); } + auto TargetFlagValidation = MIRText.validateVirtualRegisterFlags(Info.TargetFlags); + if (!TargetFlagValidation) + return std::unexpected(TargetFlagValidation.error()); + const RegisterBankDesc *Bank = nullptr; if (Info.Bank) { Bank = Registers.registerBank(*Info.Bank); @@ -196,6 +213,21 @@ TargetDescription::effectiveRegisterClass(const MachineOperand &Operand, Expected<void> TargetDescription::validateTargetOperand(const OperandDescriptor *Descriptor, const MachineOperand &Operand, const MachineRegisterInfo &RegInfo) const { + auto TargetFlagValidation = MIRText.validateOperandFlags(Operand.targetFlags()); + if (!TargetFlagValidation) + return std::unexpected(TargetFlagValidation.error()); + + if (const auto *Index = Operand.getIf<TargetIndexOperand>(); + Index != nullptr && !MIRText.targetIndexName(Index->Index)) { + return makeUnexpected(ErrorCode::VerificationError, + "target-index operand is not registered for MIR serialization"); + } + if (const auto *Intrinsic = Operand.getIf<IntrinsicOperand>(); + Intrinsic != nullptr && !MIRText.intrinsicName(Intrinsic->ID)) { + return makeUnexpected(ErrorCode::VerificationError, + "intrinsic operand is not registered for MIR serialization"); + } + if (const auto *Mask = Operand.getIf<RegisterMaskOperand>(); Mask != nullptr) { if (!Mask->Mask) { return makeUnexpected(ErrorCode::VerificationError, @@ -301,6 +333,104 @@ Expected<void> TargetDescription::validateTargetOperand(const OperandDescriptor return {}; } +Expected<void> TargetDescription::validateMemOperands( + Opcode InstructionOpcode, std::span<const MachineMemOperand *const> MemOperands) const { + auto DescriptorValidation = Instructions.validateMemOperands(InstructionOpcode, MemOperands); + if (!DescriptorValidation) + return std::unexpected(DescriptorValidation.error()); + for (const MachineMemOperand *MemOperand : MemOperands) { + if (MemOperand == nullptr) + continue; + auto TargetFlagValidation = + MIRText.validateMachineMemOperandFlags(MemOperand->description().TargetFlags); + if (!TargetFlagValidation) + return std::unexpected(TargetFlagValidation.error()); + } + return {}; +} + +Expected<void> TargetDescription::validateCFIInfo(const MachineCFIInfo &Info) const { + auto ValidateRegister = [this](DwarfRegisterNumber Register) -> Expected<void> { + if (!MIRText.physicalRegister(Register.value())) { + return makeUnexpected(ErrorCode::VerificationError, + "CFI instruction references an unmapped DWARF register"); + } + return {}; + }; + + for (const MachineCFIInstruction &Instruction : Info.instructions()) { + if (const auto *Rule = Instruction.getIf<MachineCFIRegisterRule>()) { + auto Result = ValidateRegister(Rule->Register); + if (!Result) + return Result; + } + if (const auto *Rule = Instruction.getIf<MachineCFIRegisterOffsetRule>()) { + auto Result = ValidateRegister(Rule->Register); + if (!Result) + return Result; + } + if (const auto *Rule = Instruction.getIf<MachineCFIRegisterRegisterRule>()) { + auto RegisterResult = ValidateRegister(Rule->Register); + if (!RegisterResult) + return RegisterResult; + auto SourceResult = ValidateRegister(Rule->SourceRegister); + if (!SourceResult) + return SourceResult; + } + if (const auto *Rule = Instruction.getIf<MachineCFIAddressSpaceCFARule>()) { + auto Result = ValidateRegister(Rule->Register); + if (!Result) + return Result; + } + if (const auto *Rule = Instruction.getIf<MachineCFIRegisterPairRule>()) { + for (const DwarfRegisterNumber Register : + {Rule->Register, Rule->FirstRegister, Rule->SecondRegister}) { + auto Result = ValidateRegister(Register); + if (!Result) + return Result; + } + } + if (const auto *Rule = Instruction.getIf<MachineCFIVectorRegistersRule>()) { + auto Result = ValidateRegister(Rule->Register); + if (!Result) + return Result; + for (const MachineCFIVectorRegisterLane &Lane : Rule->VectorRegisters) { + Result = ValidateRegister(Lane.Register); + if (!Result) + return Result; + } + } + if (const auto *Rule = Instruction.getIf<MachineCFIVectorOffsetRule>()) { + auto RegisterResult = ValidateRegister(Rule->Register); + if (!RegisterResult) + return RegisterResult; + auto MaskResult = ValidateRegister(Rule->MaskRegister); + if (!MaskResult) + return MaskResult; + } + if (const auto *Rule = Instruction.getIf<MachineCFIVectorRegisterMaskRule>()) { + for (const DwarfRegisterNumber Register : + {Rule->Register, Rule->SpillRegister, Rule->MaskRegister}) { + auto Result = ValidateRegister(Register); + if (!Result) + return Result; + } + } + } + return {}; +} + +Expected<void> TargetDescription::validateFrameInfo(const MachineFrameInfo &Info) const { + for (const StackObject &Object : Info.objects()) { + const StackObjectDesc *Description = Object.description(); + if (Description != nullptr && !MIRText.supportsStackID(Description->Stack)) { + return makeUnexpected(ErrorCode::VerificationError, + "stack object uses a stack ID unsupported by the target"); + } + } + return {}; +} + Expected<void> TargetDescription::validateExplicitOperands(Opcode InstructionOpcode, std::span<const MachineOperand> Operands, diff --git a/backend/lib/CodeGen/TargetMIRTextInfo.cpp b/backend/lib/CodeGen/TargetMIRTextInfo.cpp new file mode 100644 index 0000000..a349432 --- /dev/null +++ b/backend/lib/CodeGen/TargetMIRTextInfo.cpp @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/TargetMIRTextInfo.h" + +#include "rcc/CodeGen/TargetRegisterInfo.h" + +#include <bit> +#include <cstddef> +#include <cstdint> +#include <string> +#include <unordered_set> +#include <utility> +#include <vector> + +namespace rcc { +namespace { + +[[nodiscard]] std::unexpected<Error> invalidDescription(std::string Message) { + return makeUnexpected(ErrorCode::InvalidArgument, + "target MIR text description: " + std::move(Message)); +} + +[[nodiscard]] bool isASCIIAlpha(char Character) noexcept { + return (Character >= 'a' && Character <= 'z') || (Character >= 'A' && Character <= 'Z'); +} + +[[nodiscard]] bool isASCIIDigit(char Character) noexcept { + return Character >= '0' && Character <= '9'; +} + +[[nodiscard]] bool isMIRIdentifier(std::string_view Name) noexcept { + if (Name.empty() || (!isASCIIAlpha(Name.front()) && Name.front() != '_')) + return false; + for (const char Character : Name) { + if (!isASCIIAlpha(Character) && !isASCIIDigit(Character) && Character != '_' && + Character != '-' && Character != '.' && Character != '$') { + return false; + } + } + return true; +} + +[[nodiscard]] std::string lowerASCII(std::string_view Name) { + std::string Result(Name); + for (char &Character : Result) { + if (Character >= 'A' && Character <= 'Z') + Character = static_cast<char>(Character - 'A' + 'a'); + } + return Result; +} + +} // namespace + +Expected<TargetMIRTextInfo> TargetMIRTextInfo::create(TargetMIRTextInfoDesc Description, + const TargetRegisterInfo &Registers) { + TargetMIRTextInfo Result(std::move(Description)); + + for (std::size_t Index = 0; Index < Result.Description.RegisterMasks.size(); ++Index) { + MIRRegisterMaskDesc &Mask = Result.Description.RegisterMasks[Index]; + Mask.Name = lowerASCII(Mask.Name); + if (!isMIRIdentifier(Mask.Name) || Mask.Mask == nullptr) { + return invalidDescription("named register masks require an identifier and nonnull mask"); + } + auto Validation = Registers.validateRegisterMask(*Mask.Mask); + if (!Validation) + return invalidDescription("named register mask contains an unknown physical register"); + if (!Result.RegisterMaskNameToIndex.emplace(Mask.Name, Index).second) { + return invalidDescription("register mask names must be unique case-insensitively"); + } + for (std::size_t Previous = 0; Previous < Index; ++Previous) { + if (*Result.Description.RegisterMasks[Previous].Mask == *Mask.Mask) { + return invalidDescription("named register mask values must have one canonical name"); + } + } + } + + for (std::size_t Index = 0; Index < Result.Description.TargetIndices.size(); ++Index) { + const MIRTargetIndexDesc &TargetIndex = Result.Description.TargetIndices[Index]; + if (!isMIRIdentifier(TargetIndex.Name)) { + return invalidDescription("target index names must be MIR identifiers"); + } + if (!Result.TargetIndexNameToIndex.emplace(TargetIndex.Name, Index).second || + !Result.TargetIndexToIndex.emplace(TargetIndex.Index, Index).second) { + return invalidDescription("target index names and values must be unique"); + } + } + + if (Result.Description.DirectOperandFlags.empty() != + (Result.Description.DirectOperandFlagMask == 0)) { + return invalidDescription( + "direct operand flags and the direct operand flag mask must be present together"); + } + + std::unordered_set<std::string> OperandFlagNames; + for (std::size_t Index = 0; Index < Result.Description.DirectOperandFlags.size(); ++Index) { + const MIROperandFlagDesc &Flag = Result.Description.DirectOperandFlags[Index]; + if (!isMIRIdentifier(Flag.Name) || Flag.Value == 0 || + (Flag.Value & ~Result.Description.DirectOperandFlagMask) != 0) { + return invalidDescription( + "direct operand flags require an identifier and a nonzero value inside the direct mask"); + } + if (!OperandFlagNames.insert(Flag.Name).second || + !Result.DirectOperandFlagNameToIndex.emplace(Flag.Name, Index).second || + !Result.DirectOperandFlagToIndex.emplace(Flag.Value, Index).second) { + return invalidDescription("direct operand flag names and values must be unique"); + } + } + + std::uint32_t BitmaskOperandFlags = 0; + for (std::size_t Index = 0; Index < Result.Description.BitmaskOperandFlags.size(); ++Index) { + const MIROperandFlagDesc &Flag = Result.Description.BitmaskOperandFlags[Index]; + if (!isMIRIdentifier(Flag.Name) || !std::has_single_bit(Flag.Value) || + (Flag.Value & Result.Description.DirectOperandFlagMask) != 0) { + return invalidDescription( + "bitmask operand flags require an identifier and one bit outside the direct mask"); + } + if (!OperandFlagNames.insert(Flag.Name).second || + !Result.BitmaskOperandFlagNameToIndex.emplace(Flag.Name, Index).second || + (BitmaskOperandFlags & Flag.Value) != 0) { + return invalidDescription("operand flag names and bitmask values must be unique"); + } + BitmaskOperandFlags |= Flag.Value; + } + Result.SerializableOperandFlagMask = + Result.Description.DirectOperandFlagMask | BitmaskOperandFlags; + + for (std::size_t Index = 0; Index < Result.Description.MachineMemOperandFlags.size(); ++Index) { + const MIRMachineMemOperandFlagDesc &Flag = Result.Description.MachineMemOperandFlags[Index]; + if (!isMIRIdentifier(Flag.Name) || !std::has_single_bit(Flag.Value)) { + return invalidDescription( + "machine memory operand flags require an identifier and a single-bit value"); + } + if (!Result.MachineMemOperandFlagNameToIndex.emplace(Flag.Name, Index).second || + (Result.SerializableMachineMemOperandFlagMask & Flag.Value) != 0) { + return invalidDescription("machine memory operand flag names and values must be unique"); + } + Result.SerializableMachineMemOperandFlagMask |= Flag.Value; + } + + for (std::size_t Index = 0; Index < Result.Description.VirtualRegisterFlags.size(); ++Index) { + const MIRVirtualRegisterFlagDesc &Flag = Result.Description.VirtualRegisterFlags[Index]; + if (!isMIRIdentifier(Flag.Name) || !std::has_single_bit(Flag.Value)) { + return invalidDescription( + "virtual register flags require an identifier and a single-bit value"); + } + if (!Result.VirtualRegisterFlagNameToIndex.emplace(Flag.Name, Index).second || + (Result.SerializableVirtualRegisterFlagMask & Flag.Value) != 0) { + return invalidDescription("virtual register flag names and values must be unique"); + } + Result.SerializableVirtualRegisterFlagMask |= Flag.Value; + } + + for (std::size_t Index = 0; Index < Result.Description.Intrinsics.size(); ++Index) { + const MIRIntrinsicDesc &Intrinsic = Result.Description.Intrinsics[Index]; + if (!isMIRIdentifier(Intrinsic.Name) || !Intrinsic.Name.starts_with("llvm.") || + Intrinsic.ID.value() == 0) { + return invalidDescription("intrinsics require an llvm-prefixed MIR name and a nonzero ID"); + } + if (!Result.IntrinsicNameToIndex.emplace(Intrinsic.Name, Index).second || + !Result.IntrinsicToIndex.emplace(Intrinsic.ID, Index).second) { + return invalidDescription("intrinsic names and IDs must be unique"); + } + } + + std::unordered_set<std::uint32_t> ReferencedDwarfRegisters; + for (const MIRCFIRegisterMappingDesc &Mapping : Result.Description.CFIRegisters) { + if (!Registers.isKnownPhysicalRegister(Mapping.Register) || + !Result.RegisterToDwarf.emplace(Mapping.Register, Mapping.DwarfRegister).second) { + return invalidDescription("CFI register mappings require unique, known physical registers"); + } + ReferencedDwarfRegisters.insert(Mapping.DwarfRegister); + if (Mapping.IsCanonical && + !Result.DwarfToRegister.emplace(Mapping.DwarfRegister, Mapping.Register).second) { + return invalidDescription( + "each DWARF register must have exactly one canonical physical register"); + } + } + if (ReferencedDwarfRegisters.size() != Result.DwarfToRegister.size()) { + return invalidDescription( + "every referenced DWARF register requires a canonical physical register"); + } + + for (const StackID ID : Result.Description.SupportedStackIDs) { + if (!ID.isValid() || !Result.SupportedStackIDs.insert(ID.value()).second) + return invalidDescription("supported stack IDs must be valid and unique"); + } + if (!Result.SupportedStackIDs.contains(StackID::defaultStack().value()) || + !Result.SupportedStackIDs.contains(StackID::noAllocStack().value())) { + return invalidDescription("targets must support the default and noalloc stack IDs"); + } + + if (Result.Description.FunctionStateType && Result.Description.FunctionStateType->value() == 0) { + return invalidDescription("target function state TypeID must be nonzero"); + } + + return Result; +} + +std::shared_ptr<const RegisterMask> +TargetMIRTextInfo::registerMask(std::string_view Name) const noexcept { + const auto Position = RegisterMaskNameToIndex.find(std::string(Name)); + if (Position == RegisterMaskNameToIndex.end()) + return {}; + return Description.RegisterMasks[Position->second].Mask; +} + +std::optional<std::string_view> +TargetMIRTextInfo::registerMaskName(const RegisterMask &Mask) const noexcept { + for (const MIRRegisterMaskDesc &NamedMask : Description.RegisterMasks) { + if (*NamedMask.Mask == Mask) + return NamedMask.Name; + } + return std::nullopt; +} + +std::optional<TargetIndex> TargetMIRTextInfo::targetIndex(std::string_view Name) const noexcept { + const auto Position = TargetIndexNameToIndex.find(std::string(Name)); + if (Position == TargetIndexNameToIndex.end()) + return std::nullopt; + return Description.TargetIndices[Position->second].Index; +} + +std::optional<std::string_view> +TargetMIRTextInfo::targetIndexName(TargetIndex Index) const noexcept { + const auto Position = TargetIndexToIndex.find(Index); + if (Position == TargetIndexToIndex.end()) + return std::nullopt; + return Description.TargetIndices[Position->second].Name; +} + +std::optional<std::uint32_t> +TargetMIRTextInfo::directOperandFlag(std::string_view Name) const noexcept { + const auto Position = DirectOperandFlagNameToIndex.find(std::string(Name)); + if (Position == DirectOperandFlagNameToIndex.end()) + return std::nullopt; + return Description.DirectOperandFlags[Position->second].Value; +} + +std::optional<std::uint32_t> +TargetMIRTextInfo::bitmaskOperandFlag(std::string_view Name) const noexcept { + const auto Position = BitmaskOperandFlagNameToIndex.find(std::string(Name)); + if (Position == BitmaskOperandFlagNameToIndex.end()) + return std::nullopt; + return Description.BitmaskOperandFlags[Position->second].Value; +} + +Expected<void> TargetMIRTextInfo::validateOperandFlags(std::uint32_t Flags) const { + if ((Flags & ~SerializableOperandFlagMask) != 0) { + return makeUnexpected(ErrorCode::VerificationError, + "machine operand contains an unknown target flag bit"); + } + const std::uint32_t DirectFlag = Flags & Description.DirectOperandFlagMask; + if (DirectFlag != 0 && !DirectOperandFlagToIndex.contains(DirectFlag)) { + return makeUnexpected(ErrorCode::VerificationError, + "machine operand contains an unregistered direct target flag"); + } + return {}; +} + +Expected<std::vector<std::string_view>> +TargetMIRTextInfo::operandFlagNames(std::uint32_t Flags) const { + auto Validation = validateOperandFlags(Flags); + if (!Validation) + return std::unexpected(Validation.error()); + + std::vector<std::string_view> Names; + const std::uint32_t DirectFlag = Flags & Description.DirectOperandFlagMask; + if (DirectFlag != 0) { + Names.push_back(Description.DirectOperandFlags[DirectOperandFlagToIndex.at(DirectFlag)].Name); + } + for (const MIROperandFlagDesc &Flag : Description.BitmaskOperandFlags) { + if ((Flags & Flag.Value) != 0) + Names.push_back(Flag.Name); + } + return Names; +} + +std::optional<std::uint16_t> +TargetMIRTextInfo::machineMemOperandFlag(std::string_view Name) const noexcept { + const auto Position = MachineMemOperandFlagNameToIndex.find(std::string(Name)); + if (Position == MachineMemOperandFlagNameToIndex.end()) + return std::nullopt; + return Description.MachineMemOperandFlags[Position->second].Value; +} + +Expected<void> TargetMIRTextInfo::validateMachineMemOperandFlags(std::uint16_t Flags) const { + if ((Flags & static_cast<std::uint16_t>(~SerializableMachineMemOperandFlagMask)) != 0) { + return makeUnexpected(ErrorCode::VerificationError, + "machine memory operand contains an unknown target flag"); + } + return {}; +} + +Expected<std::vector<std::string_view>> +TargetMIRTextInfo::machineMemOperandFlagNames(std::uint16_t Flags) const { + auto Validation = validateMachineMemOperandFlags(Flags); + if (!Validation) + return std::unexpected(Validation.error()); + + std::vector<std::string_view> Names; + for (const MIRMachineMemOperandFlagDesc &Flag : Description.MachineMemOperandFlags) { + if ((Flags & Flag.Value) != 0) + Names.push_back(Flag.Name); + } + return Names; +} + +std::optional<std::uint8_t> +TargetMIRTextInfo::virtualRegisterFlag(std::string_view Name) const noexcept { + const auto Position = VirtualRegisterFlagNameToIndex.find(std::string(Name)); + if (Position == VirtualRegisterFlagNameToIndex.end()) + return std::nullopt; + return Description.VirtualRegisterFlags[Position->second].Value; +} + +Expected<void> TargetMIRTextInfo::validateVirtualRegisterFlags(std::uint8_t Flags) const { + if ((Flags & static_cast<std::uint8_t>(~SerializableVirtualRegisterFlagMask)) != 0) { + return makeUnexpected(ErrorCode::VerificationError, + "virtual register contains an unknown target flag"); + } + return {}; +} + +Expected<std::vector<std::string_view>> +TargetMIRTextInfo::virtualRegisterFlagNames(std::uint8_t Flags) const { + auto Validation = validateVirtualRegisterFlags(Flags); + if (!Validation) + return std::unexpected(Validation.error()); + + std::vector<std::string_view> Names; + for (const MIRVirtualRegisterFlagDesc &Flag : Description.VirtualRegisterFlags) { + if ((Flags & Flag.Value) != 0) + Names.push_back(Flag.Name); + } + return Names; +} + +std::optional<IntrinsicID> TargetMIRTextInfo::intrinsic(std::string_view Name) const noexcept { + const auto Position = IntrinsicNameToIndex.find(std::string(Name)); + if (Position == IntrinsicNameToIndex.end()) + return std::nullopt; + return Description.Intrinsics[Position->second].ID; +} + +std::optional<std::string_view> TargetMIRTextInfo::intrinsicName(IntrinsicID ID) const noexcept { + const auto Position = IntrinsicToIndex.find(ID); + if (Position == IntrinsicToIndex.end()) + return std::nullopt; + return Description.Intrinsics[Position->second].Name; +} + +std::optional<std::uint32_t> +TargetMIRTextInfo::dwarfRegister(PhysicalRegister Register) const noexcept { + const auto Position = RegisterToDwarf.find(Register); + if (Position == RegisterToDwarf.end()) + return std::nullopt; + return Position->second; +} + +std::optional<PhysicalRegister> +TargetMIRTextInfo::physicalRegister(std::uint32_t DwarfRegister) const noexcept { + const auto Position = DwarfToRegister.find(DwarfRegister); + if (Position == DwarfToRegister.end()) + return std::nullopt; + return Position->second; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/TargetRegisterInfo.cpp b/backend/lib/CodeGen/TargetRegisterInfo.cpp index 7c8af82..3ece639 100644 --- a/backend/lib/CodeGen/TargetRegisterInfo.cpp +++ b/backend/lib/CodeGen/TargetRegisterInfo.cpp @@ -26,6 +26,15 @@ namespace { return Value != 0 && std::has_single_bit(Value); } +[[nodiscard]] std::string lowerASCII(std::string_view Name) { + std::string Result(Name); + for (char &Character : Result) { + if (Character >= 'A' && Character <= 'Z') + Character = static_cast<char>(Character - 'A' + 'a'); + } + return Result; +} + template <typename RangeT, typename ValueT> [[nodiscard]] bool contains(const RangeT &Range, const ValueT &Value) { return std::ranges::find(Range, Value) != std::ranges::end(Range); @@ -64,10 +73,13 @@ Expected<TargetRegisterInfo> TargetRegisterInfo::create(TargetRegisterInfoDesc D if (!Register.Reg.isValid() || Register.Name.empty()) { return invalidDescription("physical register requires a valid number and name"); } + std::string MIRName = lowerASCII(Register.Name); if (!Result.RegisterToIndex.emplace(Register.Reg, Index).second || - !Result.RegisterNameToIndex.emplace(Register.Name, Index).second) { - return invalidDescription("physical register numbers and names must be unique"); + !Result.RegisterNameToIndex.emplace(MIRName, Index).second) { + return invalidDescription( + "physical register numbers and names must be unique case-insensitively"); } + Result.RegisterMIRNames.push_back(std::move(MIRName)); } std::unordered_set<std::string> SubRegNames; @@ -81,32 +93,36 @@ Expected<TargetRegisterInfo> TargetRegisterInfo::create(TargetRegisterInfoDesc D "subregister index requires a nonzero ID, name, lanes, and valid bit range"); } if (!Result.SubRegIndexToIndex.emplace(SubReg.ID, Index).second || - !SubRegNames.insert(SubReg.Name).second) { + !SubRegNames.insert(SubReg.Name).second || + !Result.SubRegNameToIndex.emplace(SubReg.Name, Index).second) { return invalidDescription("subregister index IDs and names must be unique"); } } - std::unordered_set<std::string> ClassNames; for (std::size_t Index = 0; Index < Result.Description.RegisterClasses.size(); ++Index) { const RegisterClassDesc &Class = Result.Description.RegisterClasses[Index]; if (Class.ID.value() == 0 || Class.Name.empty()) { return invalidDescription("register class requires a nonzero ID and name"); } + std::string MIRName = lowerASCII(Class.Name); if (!Result.ClassToIndex.emplace(Class.ID, Index).second || - !ClassNames.insert(Class.Name).second) { - return invalidDescription("register class IDs and names must be unique"); + !Result.ClassNameToIndex.emplace(MIRName, Index).second) { + return invalidDescription("register class IDs and names must be unique case-insensitively"); } + Result.ClassMIRNames.push_back(std::move(MIRName)); } - std::unordered_set<std::string> BankNames; for (std::size_t Index = 0; Index < Result.Description.RegisterBanks.size(); ++Index) { const RegisterBankDesc &Bank = Result.Description.RegisterBanks[Index]; if (Bank.ID.value() == 0 || Bank.Name.empty() || Bank.MaximumSizeInBits == 0) { return invalidDescription("register bank requires a nonzero ID, name, and maximum size"); } - if (!Result.BankToIndex.emplace(Bank.ID, Index).second || !BankNames.insert(Bank.Name).second) { - return invalidDescription("register bank IDs and names must be unique"); + std::string MIRName = lowerASCII(Bank.Name); + if (!Result.BankToIndex.emplace(Bank.ID, Index).second || + !Result.BankNameToIndex.emplace(MIRName, Index).second) { + return invalidDescription("register bank IDs and names must be unique case-insensitively"); } + Result.BankMIRNames.push_back(std::move(MIRName)); } std::unordered_set<RegisterUnitID> ReferencedUnits; @@ -443,16 +459,57 @@ const SubRegIndexDesc *TargetRegisterInfo::subRegIndex(SubRegIndex Index) const : &Description.SubRegIndices[Position->second]; } +const SubRegIndexDesc *TargetRegisterInfo::subRegIndex(std::string_view Name) const noexcept { + const auto Position = SubRegNameToIndex.find(std::string(Name)); + return Position == SubRegNameToIndex.end() ? nullptr + : &Description.SubRegIndices[Position->second]; +} + const RegisterClassDesc *TargetRegisterInfo::registerClass(RegisterClassID ID) const noexcept { const auto Position = ClassToIndex.find(ID); return Position == ClassToIndex.end() ? nullptr : &Description.RegisterClasses[Position->second]; } +const RegisterClassDesc *TargetRegisterInfo::registerClass(std::string_view Name) const noexcept { + const auto Position = ClassNameToIndex.find(std::string(Name)); + return Position == ClassNameToIndex.end() ? nullptr + : &Description.RegisterClasses[Position->second]; +} + const RegisterBankDesc *TargetRegisterInfo::registerBank(RegisterBankID ID) const noexcept { const auto Position = BankToIndex.find(ID); return Position == BankToIndex.end() ? nullptr : &Description.RegisterBanks[Position->second]; } +const RegisterBankDesc *TargetRegisterInfo::registerBank(std::string_view Name) const noexcept { + const auto Position = BankNameToIndex.find(std::string(Name)); + return Position == BankNameToIndex.end() ? nullptr : &Description.RegisterBanks[Position->second]; +} + +std::optional<std::string_view> +TargetRegisterInfo::physicalRegisterMIRName(PhysicalRegister Reg) const noexcept { + const auto Position = RegisterToIndex.find(Reg); + if (Position == RegisterToIndex.end()) + return std::nullopt; + return RegisterMIRNames[Position->second]; +} + +std::optional<std::string_view> +TargetRegisterInfo::registerClassMIRName(RegisterClassID ID) const noexcept { + const auto Position = ClassToIndex.find(ID); + if (Position == ClassToIndex.end()) + return std::nullopt; + return ClassMIRNames[Position->second]; +} + +std::optional<std::string_view> +TargetRegisterInfo::registerBankMIRName(RegisterBankID ID) const noexcept { + const auto Position = BankToIndex.find(ID); + if (Position == BankToIndex.end()) + return std::nullopt; + return BankMIRNames[Position->second]; +} + LaneMask TargetRegisterInfo::registerLaneMask(PhysicalRegister Reg) const noexcept { const PhysicalRegisterDesc *Register = physicalRegister(Reg); if (Register == nullptr) |
