From be04617b2196bf62077909f21ea9df7723aae74f Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Wed, 12 Aug 2026 01:31:09 +0800 Subject: [MIR] Create virtual registers referenced by live-ins --- backend/lib/MIR/MIRDocumentParser.cpp | 15 ++++++++--- backend/lib/MIR/MIRDocumentParser.h | 3 ++- backend/lib/MIR/MIRFunctionParser.cpp | 2 +- backend/unittests/MIR/MIRDocumentTest.cpp | 43 +++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/backend/lib/MIR/MIRDocumentParser.cpp b/backend/lib/MIR/MIRDocumentParser.cpp index 954d0d8..9c4728a 100644 --- a/backend/lib/MIR/MIRDocumentParser.cpp +++ b/backend/lib/MIR/MIRDocumentParser.cpp @@ -172,15 +172,22 @@ bool MIRDocumentParser::physicalRegister(const yaml::Node &Node, PhysicalRegiste } bool MIRDocumentParser::virtualRegister(std::string_view Text, const TextRange &Range, - const MIParserContext &Context, Register &Reg) { + MachineFunction &Function, MIParserContext &Context, + Register &Reg) { const auto ID = parsePrefixedID(Text, "%"); if (!ID) return fail(Range, "virtual register must use the '%N' MIR spelling"); - const auto Found = + auto Found = std::ranges::find_if(Context.VirtualRegisters, [ID](const MIVirtualRegisterSlot &Slot) { return Slot.TextID == *ID; }); - if (Found == Context.VirtualRegisters.end()) - return fail(Range, "reference to undefined virtual register '%" + std::to_string(*ID) + "'"); + if (Found == Context.VirtualRegisters.end()) { + auto Created = Function.registerInfo().createVirtualRegister(); + if (!Created) + return importError(Range, Created.error()); + Context.VirtualRegisters.push_back({*ID, *Created}); + Reg = *Created; + return false; + } Reg = Found->Reg; return false; } diff --git a/backend/lib/MIR/MIRDocumentParser.h b/backend/lib/MIR/MIRDocumentParser.h index 3fade39..4d1d1ea 100644 --- a/backend/lib/MIR/MIRDocumentParser.h +++ b/backend/lib/MIR/MIRDocumentParser.h @@ -70,7 +70,8 @@ private: [[nodiscard]] bool physicalRegister(std::string_view Text, const TextRange &Range, PhysicalRegister &Reg); [[nodiscard]] bool virtualRegister(std::string_view Text, const TextRange &Range, - const MIParserContext &Context, Register &Reg); + MachineFunction &Function, MIParserContext &Context, + Register &Reg); [[nodiscard]] Expected resolveMetadataReference(const MachineFunction &Function, std::uint32_t Slot) const; [[nodiscard]] bool parseVariableDebugInfo(const yaml::Node &Entry, MachineFunction &Function, diff --git a/backend/lib/MIR/MIRFunctionParser.cpp b/backend/lib/MIR/MIRFunctionParser.cpp index c8bba70..7e8821b 100644 --- a/backend/lib/MIR/MIRFunctionParser.cpp +++ b/backend/lib/MIR/MIRFunctionParser.cpp @@ -348,7 +348,7 @@ bool MIRDocumentParser::parseRegisters(const yaml::Node &Root, MachineFunction & return true; if (!trim(Text).empty()) { Register Virtual; - if (virtualRegister(Text, VirtualNode->range(), Context, Virtual)) + if (virtualRegister(Text, VirtualNode->range(), Function, Context, Virtual)) return true; Initial = Virtual; } diff --git a/backend/unittests/MIR/MIRDocumentTest.cpp b/backend/unittests/MIR/MIRDocumentTest.cpp index 88f92bc..c655e64 100644 --- a/backend/unittests/MIR/MIRDocumentTest.cpp +++ b/backend/unittests/MIR/MIRDocumentTest.cpp @@ -949,6 +949,48 @@ body: | printDiagnostics(Invalid); } +void testLiveInCreatesVirtualRegister(TestContext &Context) { + auto Target = createTarget(); + Context.expect(Target.has_value(), "live-in virtual-register target must be valid"); + if (!Target) + return; + + constexpr std::string_view DocumentText = R"(--- +name: live_in_vreg +liveins: + - { reg: '$g0', virtual-reg: '%0' } +body: | + bb.0: + %0:gpr64 = TEST_COPY $g0 +)"; + auto Parsed = rcc::mir::parseMIRDocument(*Target, "live-in-vreg.mir", std::string(DocumentText)); + const rcc::MachineFunction *Function = + Parsed.succeeded() ? Parsed.document()->unit().function("live_in_vreg") : nullptr; + const auto Registers = Function != nullptr ? Function->registerInfo().virtualRegisters() + : std::span{}; + const auto LiveIns = Function != nullptr ? Function->registerInfo().liveIns() + : std::span{}; + Context.expect(Parsed.succeeded() && Function != nullptr && Registers.size() == 1 && + Registers.front().RegClass.has_value() && LiveIns.size() == 1 && + LiveIns.front().InitialVirtualRegister.has_value(), + "a live-in must create a virtual register before the body constrains it"); + if (!Parsed.succeeded()) { + printDiagnostics(Parsed); + return; + } + + auto Printed = rcc::mir::printMIRDocument(*Parsed.document(), *Target); + Context.expect(Printed.has_value(), + "an implicitly created live-in virtual register must be printable"); + if (!Printed) + return; + auto RoundTrip = rcc::mir::parseMIRDocument(*Target, "live-in-vreg-round-trip.mir", *Printed); + Context.expect(RoundTrip.succeeded(), + "an implicitly created live-in virtual register must round-trip"); + if (!RoundTrip.succeeded()) + printDiagnostics(RoundTrip); +} + void testBodyDiagnosticLocation(TestContext &Context) { auto Target = createTarget(); Context.expect(Target.has_value(), "body-diagnostic target must be valid"); @@ -1067,6 +1109,7 @@ int main() { testFixedWidthDocumentFields(Context); testAtomicFailure(Context); testLLVMPropertySemantics(Context); + testLiveInCreatesVirtualRegister(Context); testBodyDiagnosticLocation(Context); testAnonymousFunctionsAndIRBlocks(Context); return Context.result(); -- cgit v1.2.3