diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-08 04:14:34 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-08 04:14:34 +0800 |
| commit | 77884c967d1cbc48afcbaef7e5a35adcb3c5da1b (patch) | |
| tree | 8cc31c1c5115ed909ec9f8751964bfdc96fbd4ad /backend/lib/CodeGen/MachineVerifier.cpp | |
| parent | 10b7e69448f866bcd6893b21d7f78d766252eb11 (diff) | |
| download | rcc-project-77884c967d1cbc48afcbaef7e5a35adcb3c5da1b.tar.gz rcc-project-77884c967d1cbc48afcbaef7e5a35adcb3c5da1b.tar.xz | |
[CodeGen] Implement machine SSA exit
Diffstat (limited to 'backend/lib/CodeGen/MachineVerifier.cpp')
| -rw-r--r-- | backend/lib/CodeGen/MachineVerifier.cpp | 87 |
1 files changed, 84 insertions, 3 deletions
diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index f6f5640..8f4809a 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -2,6 +2,7 @@ #include "rcc/CodeGen/MachineVerifier.h" +#include "rcc/CodeGen/GenericOpcodes.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineFrameInfo.h" #include "rcc/CodeGen/MachineFunction.h" @@ -87,6 +88,9 @@ public: auto CFGResult = verifyCFG(); if (!CFGResult) return CFGResult; + auto PHIResult = verifyPHIs(); + if (!PHIResult) + return PHIResult; auto RegisterResult = verifyRegisterInfo(); if (!RegisterResult) return RegisterResult; @@ -428,9 +432,8 @@ private: } [[nodiscard]] Expected<void> verifyFrameLifetimes() const { - auto VerifyPoints = - [this](std::span<const MachineFrameSaveRestorePoint> Points, - std::string_view Kind) -> Expected<void> { + auto VerifyPoints = [this](std::span<const MachineFrameSaveRestorePoint> Points, + std::string_view Kind) -> Expected<void> { for (const MachineFrameSaveRestorePoint &Point : Points) { if (!LinkedBlockIDs.contains(Point.Block)) { return fail(std::string("frame ") + std::string(Kind) + @@ -591,6 +594,8 @@ private: } HasPhi |= Descriptor->Flags.has(InstructionFlag::Phi); + HasStageTenPseudo |= Instruction.opcode() == opcode(GenericOpcode::REG_SEQUENCE) || + Instruction.opcode() == opcode(GenericOpcode::INSERT_SUBREG); HasGenericInstruction |= Descriptor->Flags.has(InstructionFlag::Generic); HasExecutablePseudo |= Descriptor->Flags.has(InstructionFlag::Pseudo) && !Descriptor->Flags.has(InstructionFlag::Meta) && @@ -708,6 +713,75 @@ private: return {}; } + [[nodiscard]] Expected<void> verifyPHIs() { + for (const MachineBasicBlock *Block = Function.firstBlock(); Block != nullptr; + Block = Block->next()) { + bool SawNonMetaInstruction = false; + for (const MachineInstr *Instruction = Block->firstInstruction(); Instruction != nullptr; + Instruction = Instruction->next()) { + const InstructionDescriptor *Descriptor = + Target.instructionDescriptor(Instruction->opcode()); + if (Descriptor == nullptr) + return fail("PHI verification encountered an unregistered instruction"); + + if (!Descriptor->Flags.has(InstructionFlag::Phi)) { + SawNonMetaInstruction |= !Descriptor->Flags.has(InstructionFlag::Meta); + continue; + } + if (SawNonMetaInstruction) + return fail("PHI instruction appears after a non-meta instruction"); + + const std::span<const MachineOperand> Operands = Instruction->operands(); + if (Operands.size() < 3 || (Operands.size() - 1U) % 2U != 0) { + return fail("PHI must contain a destination and at least one incoming pair"); + } + const Register *Destination = Operands.front().getIf<Register>(); + if (Destination == nullptr || !Destination->isVirtual() || !Operands.front().isDef() || + Operands.front().isUse() || Operands.front().isImplicit()) { + return fail("PHI destination must be an explicit virtual-register definition"); + } + + std::unordered_set<const MachineBasicBlock *> IncomingBlocks; + for (std::size_t Index = 1; Index < Operands.size(); Index += 2U) { + const MachineOperand &ValueOperand = Operands[Index]; + const MachineOperand &BlockOperand = Operands[Index + 1U]; + const Register *Value = ValueOperand.getIf<Register>(); + const BasicBlockOperand *Incoming = BlockOperand.getIf<BasicBlockOperand>(); + if (Value == nullptr || !ValueOperand.isUse() || ValueOperand.isDef() || + ValueOperand.isImplicit() || Incoming == nullptr || Incoming->Block == nullptr || + BlockOperand.isImplicit()) { + return fail("PHI incoming operands must be explicit register/block pairs"); + } + if (std::ranges::find(Block->predecessors(), Incoming->Block) == + Block->predecessors().end()) { + return fail("PHI incoming block is not a CFG predecessor"); + } + if (!IncomingBlocks.insert(Incoming->Block).second) + return fail("PHI contains duplicate incoming blocks"); + + if (!Value->isNoRegister() && Destination->isVirtual() && Value->isVirtual() && + Operands.front().subReg().value() == 0 && ValueOperand.subReg().value() == 0) { + auto DestinationInfo = Function.registerInfo().virtualRegisterInfo(*Destination); + auto ValueInfo = Function.registerInfo().virtualRegisterInfo(*Value); + if (!DestinationInfo || !ValueInfo) + return fail("PHI references an unknown virtual register"); + if (DestinationInfo->get().Type && ValueInfo->get().Type && + DestinationInfo->get().Type != ValueInfo->get().Type) { + return fail("PHI destination and incoming value types do not match"); + } + } + auto Compatibility = Target.validateTieCompatibility(Operands.front(), ValueOperand, + Function.registerInfo()); + if (!Compatibility) + return failWith("PHI register compatibility", Compatibility.error()); + } + if (IncomingBlocks.size() != Block->predecessors().size()) + return fail("PHI incoming blocks do not exactly cover CFG predecessors"); + } + } + return {}; + } + [[nodiscard]] Expected<void> verifyRegisterInfo() { const MachineRegisterInfo &RegInfo = Function.registerInfo(); std::unordered_set<PhysicalRegister> FunctionLiveIns; @@ -767,6 +841,9 @@ private: if (Has(MachineFunctionProperty::TiedOpsRewritten) && !Has(MachineFunctionProperty::Selected)) { return fail("TiedOpsRewritten requires Selected"); } + if (Has(MachineFunctionProperty::TiedOpsRewritten) && !Has(MachineFunctionProperty::NoPHIs)) { + return fail("TiedOpsRewritten requires NoPHIs"); + } if (Has(MachineFunctionProperty::FrameFinalized) && (!Has(MachineFunctionProperty::NoVRegs) || !Has(MachineFunctionProperty::NoFrameIndices))) { return fail("FrameFinalized requires NoVRegs and NoFrameIndices"); @@ -797,6 +874,9 @@ private: if (Has(MachineFunctionProperty::TiedOpsRewritten) && HasUnrewrittenTie) { return fail("TiedOpsRewritten function has unequal tied registers"); } + if (Has(MachineFunctionProperty::TiedOpsRewritten) && HasStageTenPseudo) { + return fail("TiedOpsRewritten function contains a Stage 10 pseudo"); + } const bool NeedsTypes = Options.Mode == MachineVerifierMode::PreLegalizer || Has(MachineFunctionProperty::Legalized) || @@ -837,6 +917,7 @@ private: bool HasExecutablePseudo = false; bool HasFrameIndex = false; bool HasUnrewrittenTie = false; + bool HasStageTenPseudo = false; bool HasLiveVirtualRegister = false; bool MissingVirtualType = false; bool MissingVirtualBank = false; |
