From e5fdceb9b869f010a2a75638fd38aaf1867f3008 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sun, 9 Aug 2026 04:40:17 +0800 Subject: [CodeGen] Complete register allocation infrastructure --- backend/unittests/CodeGen/RegAllocFastTest.cpp | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 backend/unittests/CodeGen/RegAllocFastTest.cpp (limited to 'backend/unittests/CodeGen/RegAllocFastTest.cpp') diff --git a/backend/unittests/CodeGen/RegAllocFastTest.cpp b/backend/unittests/CodeGen/RegAllocFastTest.cpp new file mode 100644 index 0000000..cf5498f --- /dev/null +++ b/backend/unittests/CodeGen/RegAllocFastTest.cpp @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "CodeGen/RegisterAllocationTestSupport.h" +#include "rcc/CodeGen/MachineCFGUpdater.h" + +#include + +namespace { + +using namespace rcc; +using namespace rcc::test; +using namespace rcc::test::ra; + +void testBlockBoundary(TestContext &Context, const TargetDescription &Target) { + auto Fixture = createFunction("fast-boundary", 40); + if (!Fixture) + return; + auto Exit = Fixture->Function->createBasicBlock(); + if (!Exit || !Fixture->Function->appendBlock(**Exit) || + !Fixture->Function->cfgUpdater().addSuccessor(*Fixture->Block, **Exit, + BranchProbability::one())) + return; + auto Value = createVReg(*Fixture->Function); + if (!Value || !buildDef(*Fixture->Function, Target, *Fixture->Block, *Value, 9) || + !buildUse(*Fixture->Function, Target, **Exit, *Value) || + !buildUse(*Fixture->Function, Target, **Exit, + Register::fromPhysical(physical(TestRegister::G0))) || + !prepareForAllocation(*Fixture->Function, Target)) + return; + TestRegisterAllocationInfo Info; + auto Allocated = runAllocator(*Fixture->Function, Target, Info, AllocatorKind::Fast); + Context.expect(Allocated && countOpcode(*Fixture->Function, testOpcode(SpillStoreOpcode)) == 1 && + countOpcode(*Fixture->Function, testOpcode(SpillLoadOpcode)) == 1 && + Fixture->Function->properties().has(MachineFunctionProperty::NoVRegs), + "FastAllocator must preserve values across a block boundary"); +} + +void testFunctionLiveInAndDebug(TestContext &Context, const TargetDescription &Target) { + auto Fixture = createFunction("fast-live-in", 41); + if (!Fixture) + return; + auto Value = createVReg(*Fixture->Function); + const PhysicalRegister G0 = physical(TestRegister::G0); + if (!Value || !Fixture->Function->registerInfo().addLiveIn(G0, *Value) || + !buildUse(*Fixture->Function, Target, *Fixture->Block, *Value, {}, true) || + !buildUse(*Fixture->Function, Target, *Fixture->Block, *Value) || + !prepareForAllocation(*Fixture->Function, Target)) + return; + TestRegisterAllocationInfo Info; + auto Allocated = runAllocator(*Fixture->Function, Target, Info, AllocatorKind::Fast); + const MachineOperand *DebugOperand = nullptr; + for (const MachineInstr *Instruction = Fixture->Block->firstInstruction(); Instruction != nullptr; + Instruction = Instruction->next()) { + for (const MachineOperand &Operand : Instruction->operands()) { + if (Operand.isDebugUse()) { + DebugOperand = &Operand; + break; + } + } + if (DebugOperand != nullptr) + break; + } + Context.expect( + Allocated && DebugOperand != nullptr && DebugOperand->registerValue() && + (DebugOperand->registerValue()->isNoRegister() || + DebugOperand->registerValue() == Register::fromPhysical(G0)) && + std::ranges::none_of(Fixture->Function->registerInfo().virtualRegisters(), + [](const VirtualRegisterInfo &Info) { return !Info.IsTombstone; }), + "FastAllocator must preserve function live-ins and debug locations"); +} + +} // namespace + +int main() { + TestContext Context; + auto Target = createTarget(); + Context.expect(Target.has_value(), "FastAllocator test target must be constructible"); + if (!Target) + return Context.result(); + testBlockBoundary(Context, *Target); + testFunctionLiveInAndDebug(Context, *Target); + return Context.result(); +} -- cgit v1.2.3