From 551f0b3fcd6f797ed6dca90f39123b0359396dcb Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Tue, 11 Aug 2026 20:08:36 +0800 Subject: [RISCV] Match LLVM call-frame pseudo semantics --- backend/unittests/Target/RISCVCallLoweringTest.cpp | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'backend/unittests/Target/RISCVCallLoweringTest.cpp') diff --git a/backend/unittests/Target/RISCVCallLoweringTest.cpp b/backend/unittests/Target/RISCVCallLoweringTest.cpp index d3685ae..1eaf146 100644 --- a/backend/unittests/Target/RISCVCallLoweringTest.cpp +++ b/backend/unittests/Target/RISCVCallLoweringTest.cpp @@ -483,6 +483,8 @@ void testOrdinaryAndIndirectEmission(TestContext &Context) { return; const auto Instructions = instructions(*Block); + rcc::MachineInstr *FrameDown = Instructions.empty() ? nullptr : Instructions.front(); + rcc::MachineInstr *FrameUp = Instructions.size() > 3 ? Instructions[3] : nullptr; rcc::MachineInstr *Call = findInstruction(*Block, rcc::riscv::InstructionOpcode::PseudoCALL); Context.expect(Instructions.size() == 5 && Instructions.front()->opcode() == @@ -497,6 +499,39 @@ void testOrdinaryAndIndirectEmission(TestContext &Context) { Call->operandAt(2)->kind() == rcc::MachineOperand::Kind::RegisterMask, "ordinary emission must materialize canonical full-value copies, call-frame, " "target, ID, and RegMask"); + const rcc::Register StackPointer = + rcc::Register::fromPhysical(physical(rcc::riscv::PhysicalRegisterID::X2)); + const auto HasStackPointerEffects = [StackPointer](const rcc::MachineInstr *Instruction) { + bool HasDef = false; + bool HasUse = false; + if (Instruction == nullptr) + return false; + for (const rcc::MachineOperand &Operand : Instruction->operands()) { + if (!Operand.isRegister() || !Operand.isImplicit() || + Operand.registerValue() != StackPointer) { + continue; + } + HasDef |= Operand.isDef(); + HasUse |= Operand.isUse(); + } + return HasDef && HasUse; + }; + const auto ImmediateAt = [](const rcc::MachineInstr *Instruction, std::size_t Index) { + const rcc::MachineOperand *Operand = + Instruction == nullptr ? nullptr : Instruction->operandAt(Index); + return Operand == nullptr ? nullptr : Operand->getIf(); + }; + const auto *DownAmount = ImmediateAt(FrameDown, 0); + const auto *DownPrepared = ImmediateAt(FrameDown, 1); + const auto *UpAmount = ImmediateAt(FrameUp, 0); + const auto *UpPrepared = ImmediateAt(FrameUp, 1); + Context.expect( + DownAmount != nullptr && *DownAmount == 0 && DownPrepared != nullptr && *DownPrepared == 0 && + UpAmount != nullptr && *UpAmount == 0 && UpPrepared != nullptr && *UpPrepared == 0 && + HasStackPointerEffects(FrameDown) && HasStackPointerEffects(FrameUp) && + !FrameDown->flags().has(rcc::MachineInstrFlag::FrameSetup) && + !FrameUp->flags().has(rcc::MachineInstrFlag::FrameDestroy), + "call-frame pseudos must use LLVM amount/prepared-byte operands and implicit SP effects"); bool HasArgumentUse = false; bool HasResultDef = false; for (const rcc::MachineOperand &Operand : Call->operands()) { -- cgit v1.2.3