From 2872e39af3aa78b7a54b74d104f133aa715d01cb Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Tue, 11 Aug 2026 23:57:49 +0800 Subject: [CodeGen] Treat reserved registers as always live --- backend/lib/CodeGen/MachineLiveness.cpp | 11 ++++++ backend/unittests/CodeGen/MachineLivenessTest.cpp | 41 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'backend') diff --git a/backend/lib/CodeGen/MachineLiveness.cpp b/backend/lib/CodeGen/MachineLiveness.cpp index 9ed09cc..528a675 100644 --- a/backend/lib/CodeGen/MachineLiveness.cpp +++ b/backend/lib/CodeGen/MachineLiveness.cpp @@ -239,6 +239,13 @@ void addPhysicalRegister(RegisterUnitLaneSet &Set, const PhysicalRegisterDesc &D Set.unite(physicalRegisterCoverage(Description, Requested)); } +[[nodiscard]] bool isReservedPhysicalRegister(Register Reg, const MachineFunction &Function, + const TargetDescription &Target) noexcept { + const std::optional Physical = Reg.physicalRegister(); + return Physical && (Function.registerInfo().isReserved(*Physical) || + Target.registers().isReservedRegister(*Physical)); +} + [[nodiscard]] Expected addRegisterMaskDefs(RegisterUnitLaneSet &Set, const RegisterMask &Mask, const TargetDescription &Target) { for (const PhysicalRegisterDesc &Description : Target.registers().physicalRegisters()) { @@ -274,6 +281,8 @@ void addPhysicalRegister(RegisterUnitLaneSet &Set, const PhysicalRegisterDesc &D VirtualUses.add(*Reg, *Lanes); return {}; } + if (isReservedPhysicalRegister(*Reg, Function, Target)) + return {}; auto Units = physicalOperandUnits(Operand, Target); if (!Units) return std::unexpected(Units.error()); @@ -851,6 +860,8 @@ struct LivenessRebuildPlan final { return std::unexpected(Lanes.error()); return Virtual.intersects(*Reg, *Lanes); } + if (isReservedPhysicalRegister(*Reg, Function, Target)) + return true; auto Units = physicalOperandUnits(Operand, Target); if (!Units) return std::unexpected(Units.error()); diff --git a/backend/unittests/CodeGen/MachineLivenessTest.cpp b/backend/unittests/CodeGen/MachineLivenessTest.cpp index 3f7621d..84a247f 100644 --- a/backend/unittests/CodeGen/MachineLivenessTest.cpp +++ b/backend/unittests/CodeGen/MachineLivenessTest.cpp @@ -856,6 +856,46 @@ void testRISCVLiveness(TestContext &Context) { "production RV64GC register units must participate in LiveIntervals"); } +void testRISCVReservedRegisterLiveness(TestContext &Context) { + auto Target = rcc::riscv::createTargetDescription(); + auto Fixture = createFunction("riscv-reserved-liveness", 10, 1); + if (!Target || !Fixture) { + Context.expect(false, "RV64GC reserved-register liveness fixture creation must succeed"); + return; + } + auto X0 = rcc::riscv::physicalRegister(rcc::riscv::PhysicalRegisterID::X0); + auto X5 = rcc::riscv::physicalRegister(rcc::riscv::PhysicalRegisterID::X5); + if (!X0 || !X5) { + Context.expect(false, "RV64GC reserved-register fixture registers must resolve"); + return; + } + + rcc::MachineIRBuilder Builder(*Fixture->Function, *Target); + auto Point = Builder.setInsertPoint(*Fixture->Blocks[0]); + auto Pending = Point ? Builder.buildInstr(rcc::Opcode::fromValue( + static_cast(rcc::riscv::InstructionOpcode::ADDI))) + : rcc::Expected{std::unexpected(Point.error())}; + auto Def = Pending ? Pending->addDef(rcc::Register::fromPhysical(*X5)) + : rcc::Expected{std::unexpected(Pending.error())}; + auto Use = Def ? Pending->addUse(rcc::Register::fromPhysical(*X0)) + : rcc::Expected{std::unexpected(Def.error())}; + auto Immediate = + Use ? Pending->addImmediate(1) : rcc::Expected{std::unexpected(Use.error())}; + auto Instruction = Immediate + ? Pending->build() + : rcc::Expected{std::unexpected(Immediate.error())}; + if (!Instruction) { + Context.expect(false, "RV64GC reserved-register liveness instruction must be built"); + return; + } + + auto Rebuilt = rcc::rebuildMachineLiveness(*Fixture->Function, *Target); + const rcc::MachineOperand *ZeroUse = (*Instruction)->operandAt(1); + Context.expect(Rebuilt && Fixture->Blocks[0]->liveIns().empty() && ZeroUse != nullptr && + !ZeroUse->registerFlags().has(rcc::RegisterOperandFlag::Kill), + "reserved registers must remain available without live-ins or kill flags"); +} + } // namespace int main() { @@ -874,5 +914,6 @@ int main() { testFailedRebuildIsAtomic(Context, *Target); testAnalysisRegistrationAndInvalidation(Context, *Target); testRISCVLiveness(Context); + testRISCVReservedRegisterLiveness(Context); return Context.result(); } -- cgit v1.2.3