aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/CMakeLists.txt4
-rw-r--r--backend/lib/CodeGen/MachineFrameInfo.cpp51
-rw-r--r--backend/lib/CodeGen/MachineFunctionCloner.cpp6
-rw-r--r--backend/lib/CodeGen/MachineRegisterInfo.cpp13
-rw-r--r--backend/lib/CodeGen/MachineVerifier.cpp13
-rw-r--r--backend/lib/CodeGen/TargetDescription.cpp134
-rw-r--r--backend/lib/CodeGen/TargetMIRTextInfo.cpp368
-rw-r--r--backend/lib/CodeGen/TargetRegisterInfo.cpp75
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)