From ce691f04c3eb1a972419187884f926de9632b7cf Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Wed, 12 Aug 2026 03:33:45 +0800 Subject: [RISCV] Describe vector tuple registers --- backend/lib/Target/RISCV/RISCV.rccdesc | 2 +- backend/lib/Target/RISCV/RISCVTarget.cpp | 86 ++++++++++++++++++++++++++++ backend/unittests/Target/RISCVTargetTest.cpp | 15 ++++- 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/backend/lib/Target/RISCV/RISCV.rccdesc b/backend/lib/Target/RISCV/RISCV.rccdesc index f41d11b..c4a87e9 100644 --- a/backend/lib/Target/RISCV/RISCV.rccdesc +++ b/backend/lib/Target/RISCV/RISCV.rccdesc @@ -246,7 +246,7 @@ register_banks: - { id: 1, symbol: GPR, name: GPRB, maximum_size_bits: 64 } - { id: 2, symbol: FPR, name: FPRB, maximum_size_bits: 64 } - { id: 3, symbol: CSR, name: CSRB, maximum_size_bits: 32 } - - { id: 4, symbol: VR, name: VRB, maximum_size_bits: 64 } + - { id: 4, symbol: VR, name: VRB, maximum_size_bits: 512 } register_classes: - diff --git a/backend/lib/Target/RISCV/RISCVTarget.cpp b/backend/lib/Target/RISCV/RISCVTarget.cpp index 090d0bc..8bdea20 100644 --- a/backend/lib/Target/RISCV/RISCVTarget.cpp +++ b/backend/lib/Target/RISCV/RISCVTarget.cpp @@ -5,6 +5,7 @@ #include "rcc/CodeGen/GenericOpcodes.h" #include "rcc/Target/RISCV/RISCVFunctionInfo.h" +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include @@ -98,6 +100,88 @@ physicalRegisters(std::initializer_list IDs) { return AddClassMapping(RegisterClass::FPR64C, RegisterClass::FPR32C); } +[[nodiscard]] Expected appendRISCVVectorTupleInfo(TargetRegisterInfoDesc &Description) { + constexpr std::uint32_t FirstVector = static_cast(PhysicalRegisterID::V0); + constexpr std::uint32_t LastVector = static_cast(PhysicalRegisterID::V31); + static_assert(LastVector - FirstVector == 31); + + const RegisterBankID VectorBankID = + RegisterBankID::fromValue(static_cast(RegisterBank::VR)); + auto VectorBank = + std::ranges::find(Description.RegisterBanks, VectorBankID, &RegisterBankDesc::ID); + if (VectorBank == Description.RegisterBanks.end()) + return makeUnexpected(ErrorCode::InternalError, "RISC-V vector register bank is missing"); + + std::uint32_t NextRegisterID = 1; + for (const PhysicalRegisterDesc &Register : Description.PhysicalRegisters) + NextRegisterID = std::max(NextRegisterID, Register.Reg.number() + 1U); + std::uint32_t NextClassID = 1; + for (const RegisterClassDesc &Class : Description.RegisterClasses) + NextClassID = std::max(NextClassID, Class.ID.value() + 1U); + + for (std::uint32_t Length = 2; Length <= 8; ++Length) { + std::vector TupleRegisters; + TupleRegisters.reserve(33U - Length); + for (std::uint32_t Start = 0; Start + Length <= 32; ++Start) { + auto Tuple = PhysicalRegister::create(NextRegisterID++); + if (!Tuple) + return makeUnexpected(ErrorCode::InternalError, "RISC-V vector tuple ID is invalid"); + + std::string Name; + std::vector Units; + Units.reserve(Length); + for (std::uint32_t Offset = 0; Offset < Length; ++Offset) { + auto Element = PhysicalRegister::create(FirstVector + Start + Offset); + if (!Element) + return makeUnexpected(ErrorCode::InternalError, + "RISC-V vector tuple element ID is invalid"); + const auto ElementDescription = + std::ranges::find(Description.PhysicalRegisters, *Element, &PhysicalRegisterDesc::Reg); + if (ElementDescription == Description.PhysicalRegisters.end() || + ElementDescription->Units.size() != 1) { + return makeUnexpected(ErrorCode::InternalError, + "RISC-V vector tuple element has invalid register units"); + } + if (!Name.empty()) + Name.push_back('_'); + Name.append(ElementDescription->Name); + Units.push_back(ElementDescription->Units.front()); + } + + Description.PhysicalRegisters.push_back({ + .Reg = *Tuple, + .Name = std::move(Name), + .Encoding = Start, + .Units = std::move(Units), + .IsConstant = false, + .IsArtificial = false, + .IsReserved = false, + .AlternativeNames = {}, + }); + TupleRegisters.push_back(*Tuple); + } + + const RegisterClassID ClassID = RegisterClassID::fromValue(NextClassID++); + Description.RegisterClasses.push_back({ + .ID = ClassID, + .Name = "VRTuple" + std::to_string(Length), + .Registers = std::move(TupleRegisters), + .AllocationOrder = {}, + .SizeInBits = Length * 64U, + .SpillSizeInBits = Length * 64U, + .SpillAlignmentInBits = 64, + .Lanes = LaneMask::fromRaw(1), + .SupportedSubRegs = {}, + .SuperClasses = {}, + .DefaultBank = VectorBankID, + .Allocatable = false, + .CopyCost = Length, + }); + VectorBank->RegisterClasses.push_back(ClassID); + } + return {}; +} + [[nodiscard]] std::shared_ptr makePreservedMask(std::initializer_list Preserved) { std::vector Words; @@ -124,6 +208,8 @@ Expected createRegisterInfo() { appendGeneratedRegisterInfo(Description); if (auto Result = appendRISCVSubRegisterInfo(Description); !Result) return std::unexpected(Result.error()); + if (auto Result = appendRISCVVectorTupleInfo(Description); !Result) + return std::unexpected(Result.error()); return TargetRegisterInfo::create(std::move(Description)); } diff --git a/backend/unittests/Target/RISCVTargetTest.cpp b/backend/unittests/Target/RISCVTargetTest.cpp index aed3cc2..c067168 100644 --- a/backend/unittests/Target/RISCVTargetTest.cpp +++ b/backend/unittests/Target/RISCVTargetTest.cpp @@ -55,8 +55,8 @@ void testRegisterFacts(TestContext &Context) { const rcc::PhysicalRegister V8 = registerID(rcc::riscv::PhysicalRegisterID::V8); Context.expect( - Registers->physicalRegisters().size() == 130 && Registers->registerUnits().size() == 98 && - Registers->registerClasses().size() == 11 && Registers->registerBanks().size() == 4, + Registers->physicalRegisters().size() == 326 && Registers->registerUnits().size() == 98 && + Registers->registerClasses().size() == 18 && Registers->registerBanks().size() == 4, "RISC-V must expose scalar, vector, restricted, and status physical registers"); Context.expect(Registers->physicalRegister("x0") != nullptr && Registers->physicalRegister("zero") == nullptr && @@ -89,6 +89,17 @@ void testRegisterFacts(TestContext &Context) { !Registers->registerClass("vr")->Allocatable && Registers->registerClassContains(Registers->registerClass("vr")->ID, V8), "vector physical registers must retain LLVM MIR names and encodings"); + const auto *V8V9 = Registers->physicalRegister("v8_v9"); + const auto *V28V29V30 = Registers->physicalRegister("v28_v29_v30"); + const auto *V0ThroughV7 = Registers->physicalRegister("v0_v1_v2_v3_v4_v5_v6_v7"); + Context.expect(V8V9 != nullptr && V28V29V30 != nullptr && V0ThroughV7 != nullptr && + Registers->regsOverlap(V8V9->Reg, V8) && + !Registers->regsOverlap(V28V29V30->Reg, V8) && + Registers->regsOverlap(V0ThroughV7->Reg, + registerID(rcc::riscv::PhysicalRegisterID::V7)) && + Registers->registerClass("vrtuple2") != nullptr && + !Registers->registerClass("vrtuple2")->Allocatable, + "vector tuple registers must expose canonical names and physical overlap"); Context.expect(Registers->physicalRegister("fflags") != nullptr && Registers->physicalRegister("fflags")->Reg == FFLAGS && Registers->isReservedRegister(FFLAGS) && -- cgit v1.2.3