aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 23:57:49 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 23:57:49 +0800
commit2872e39af3aa78b7a54b74d104f133aa715d01cb (patch)
tree168061fb22943a82efbe53c135d0f920a5e1e839
parente7586a115e9ff6ee303c2546cb0eab48bde6dfbb (diff)
downloadrcc-project-2872e39af3aa78b7a54b74d104f133aa715d01cb.tar.gz
rcc-project-2872e39af3aa78b7a54b74d104f133aa715d01cb.tar.xz
[CodeGen] Treat reserved registers as always live
-rw-r--r--backend/lib/CodeGen/MachineLiveness.cpp11
-rw-r--r--backend/unittests/CodeGen/MachineLivenessTest.cpp41
2 files changed, 52 insertions, 0 deletions
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<PhysicalRegister> Physical = Reg.physicalRegister();
+ return Physical && (Function.registerInfo().isReserved(*Physical) ||
+ Target.registers().isReservedRegister(*Physical));
+}
+
[[nodiscard]] Expected<void> 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<std::uint32_t>(rcc::riscv::InstructionOpcode::ADDI)))
+ : rcc::Expected<rcc::MachineInstrBuilder>{std::unexpected(Point.error())};
+ auto Def = Pending ? Pending->addDef(rcc::Register::fromPhysical(*X5))
+ : rcc::Expected<void>{std::unexpected(Pending.error())};
+ auto Use = Def ? Pending->addUse(rcc::Register::fromPhysical(*X0))
+ : rcc::Expected<void>{std::unexpected(Def.error())};
+ auto Immediate =
+ Use ? Pending->addImmediate(1) : rcc::Expected<void>{std::unexpected(Use.error())};
+ auto Instruction = Immediate
+ ? Pending->build()
+ : rcc::Expected<rcc::MachineInstr *>{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();
}