diff options
| author | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-11 20:08:36 +0800 |
|---|---|---|
| committer | Richard-Qin-X <richard.qin.001@gmail.com> | 2026-08-11 20:08:36 +0800 |
| commit | 551f0b3fcd6f797ed6dca90f39123b0359396dcb (patch) | |
| tree | ccef579ebdf4f1df9bf2b5f08062b66c216b19bd /backend/unittests/Target | |
| parent | 8b797159e6c8fe1294fd2d26de3bd0992c61ea24 (diff) | |
| download | rcc-project-551f0b3fcd6f797ed6dca90f39123b0359396dcb.tar.gz rcc-project-551f0b3fcd6f797ed6dca90f39123b0359396dcb.tar.xz | |
[RISCV] Match LLVM call-frame pseudo semantics
Diffstat (limited to 'backend/unittests/Target')
| -rw-r--r-- | backend/unittests/Target/RISCVCallLoweringTest.cpp | 35 | ||||
| -rw-r--r-- | backend/unittests/Target/RISCVFrameLoweringTest.cpp | 23 |
2 files changed, 47 insertions, 11 deletions
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<std::int64_t>(); + }; + 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()) { diff --git a/backend/unittests/Target/RISCVFrameLoweringTest.cpp b/backend/unittests/Target/RISCVFrameLoweringTest.cpp index 7096840..95d6a18 100644 --- a/backend/unittests/Target/RISCVFrameLoweringTest.cpp +++ b/backend/unittests/Target/RISCVFrameLoweringTest.cpp @@ -347,7 +347,7 @@ buildMoveToDouble(rcc::MachineFunction &Function, const rcc::TargetDescription & [[nodiscard]] rcc::Expected<rcc::MachineInstr *> buildCallFramePseudo(rcc::MachineFunction &Function, const rcc::TargetDescription &Target, rcc::MachineBasicBlock &Block, rcc::riscv::InstructionOpcode OpcodeValue, - std::int64_t Amount, std::int64_t Alignment = 16) { + std::int64_t Amount, std::int64_t PreparedBytes = 0) { rcc::MachineIRBuilder Builder(Function, Target); if (auto Result = Builder.setInsertPoint(Block); !Result) return std::unexpected(Result.error()); @@ -356,7 +356,7 @@ buildCallFramePseudo(rcc::MachineFunction &Function, const rcc::TargetDescriptio return std::unexpected(Pending.error()); if (auto Result = Pending->addImmediate(Amount); !Result) return std::unexpected(Result.error()); - if (auto Result = Pending->addImmediate(Alignment); !Result) + if (auto Result = Pending->addImmediate(PreparedBytes); !Result) return std::unexpected(Result.error()); return Pending->build(); } @@ -804,14 +804,14 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target) auto Computed = createFunction("computed-call-frame", 17); if (!Computed) return; - auto ComputedOutgoingAlign = rcc::Alignment::create(16); + auto ComputedOutgoingAlign = rcc::Alignment::create(64); if (!ComputedOutgoingAlign) return; rcc::StackObjectDesc ComputedOutgoingDescription; ComputedOutgoingDescription.Kind = rcc::StackObjectKind::Target; ComputedOutgoingDescription.Size = 8; ComputedOutgoingDescription.Align = *ComputedOutgoingAlign; - ComputedOutgoingDescription.LocalOffset = 48; + ComputedOutgoingDescription.LocalOffset = 0; ComputedOutgoingDescription.TargetFlags = static_cast<std::uint64_t>(rcc::riscv::CallStackObjectFlag::OutgoingArgument); auto ComputedOutgoing = @@ -825,9 +825,9 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target) rcc::riscv::InstructionOpcode::SD, physical(rcc::riscv::PhysicalRegisterID::X11), *ComputedLocal, 0) || !buildCallFramePseudo(*Computed->Function, Target, *Computed->Block, - rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 48, 64) || + rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 64) || !buildCallFramePseudo(*Computed->Function, Target, *Computed->Block, - rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 48, 64) || + rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 64) || !buildReturn(*Computed->Function, Target, *Computed->Block)) { return; } @@ -846,7 +846,7 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target) !buildCallFramePseudo(*Mismatched->Function, Target, *Mismatched->Block, rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 48, 16) || !buildCallFramePseudo(*Mismatched->Function, Target, *Mismatched->Block, - rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 48, 32) || + rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 48, 24) || !buildReturn(*Mismatched->Function, Target, *Mismatched->Block)) { return; } @@ -877,17 +877,18 @@ void testCallFrames(TestContext &Context, const rcc::TargetDescription &Target) return; auto Variable = createStackObject(*Dynamic->Function, rcc::StackObjectKind::DynamicAlloca, std::nullopt, 16); - if (!Variable || + auto OverAligned = createStackObject(*Dynamic->Function, rcc::StackObjectKind::Default, 8, 32); + if (!Variable || !OverAligned || !buildCallFramePseudo(*Dynamic->Function, Target, *Dynamic->Block, - rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 4096, 32) || + rcc::riscv::InstructionOpcode::ADJCALLSTACKDOWN, 4096) || !buildCallFramePseudo(*Dynamic->Function, Target, *Dynamic->Block, - rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 4096, 32) || + rcc::riscv::InstructionOpcode::ADJCALLSTACKUP, 4096) || !buildReturn(*Dynamic->Function, Target, *Dynamic->Block)) { return; } Context.expect(rcc::riscv::registerAllocationInfo().isReservedForFunction( *Dynamic->Function, physReg(rcc::riscv::PhysicalRegisterID::X9), Target), - "over-aligned call frames must reserve BP before register allocation"); + "over-aligned dynamic frames must reserve BP before register allocation"); auto DynamicResult = runFrameLowering(*Dynamic->Function, Target); Context.expect( DynamicResult && |
