aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests
diff options
context:
space:
mode:
authorRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 20:08:36 +0800
committerRichard-Qin-X <richard.qin.001@gmail.com>2026-08-11 20:08:36 +0800
commit551f0b3fcd6f797ed6dca90f39123b0359396dcb (patch)
treeccef579ebdf4f1df9bf2b5f08062b66c216b19bd /backend/unittests
parent8b797159e6c8fe1294fd2d26de3bd0992c61ea24 (diff)
downloadrcc-project-551f0b3fcd6f797ed6dca90f39123b0359396dcb.tar.gz
rcc-project-551f0b3fcd6f797ed6dca90f39123b0359396dcb.tar.xz
[RISCV] Match LLVM call-frame pseudo semantics
Diffstat (limited to 'backend/unittests')
-rw-r--r--backend/unittests/Target/RISCVCallLoweringTest.cpp35
-rw-r--r--backend/unittests/Target/RISCVFrameLoweringTest.cpp23
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 &&