aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/unittests/CodeGen/MachineFunctionClonerTest.cpp')
-rw-r--r--backend/unittests/CodeGen/MachineFunctionClonerTest.cpp78
1 files changed, 66 insertions, 12 deletions
diff --git a/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp b/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp
index 90e847b..3b2fce9 100644
--- a/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp
+++ b/backend/unittests/CodeGen/MachineFunctionClonerTest.cpp
@@ -6,6 +6,7 @@
#include "rcc/CodeGen/LowLevelType.h"
#include "rcc/CodeGen/MachineBasicBlock.h"
#include "rcc/CodeGen/MachineCFGUpdater.h"
+#include "rcc/CodeGen/MachineFrameInfo.h"
#include "rcc/CodeGen/MachineFunction.h"
#include "rcc/CodeGen/MachineFunctionProperties.h"
#include "rcc/CodeGen/MachineIRBuilder.h"
@@ -137,12 +138,12 @@ createFunction(TestContext &Context, std::string Name, std::uint64_t ID) {
return *Block;
}
-[[nodiscard]] rcc::MachineMemOperandDesc loadDescription() {
+[[nodiscard]] rcc::MachineMemOperandDesc loadDescription(rcc::FrameIndex Index) {
rcc::MachineMemOperandDesc Description;
Description.Accesses = {rcc::MemoryAccessFlag::Load, rcc::MemoryAccessFlag::Dereferenceable};
Description.Size = *rcc::MemorySize::fixed(8);
Description.Align = *rcc::Alignment::create(8);
- Description.Base = rcc::MemoryBase::frameIndex(rcc::FrameIndex::fromValue(4));
+ Description.Base = rcc::MemoryBase::frameIndex(Index);
Description.Offset = -8;
return Description;
}
@@ -162,6 +163,7 @@ struct SourceFixture final {
rcc::MachineBasicBlock *Exit = nullptr;
rcc::Register Value;
rcc::Register CopyValue;
+ rcc::FrameIndex StackSlot;
const rcc::MachineMemOperand *LoadMMO = nullptr;
};
@@ -177,6 +179,25 @@ struct SourceFixture final {
Context.expect(Tombstone && Function.registerInfo().eraseVirtualRegister(*Tombstone).has_value(),
"source vreg history must contain a tombstone");
+ rcc::StackObjectDesc HistoricalFrame;
+ HistoricalFrame.Size = 4;
+ HistoricalFrame.Align = *rcc::Alignment::create(4);
+ auto HistoricalFrameIndex = Function.frameInfo().createObject(HistoricalFrame);
+ Context.expect(HistoricalFrameIndex &&
+ Function.frameInfo().eraseObject(*HistoricalFrameIndex).has_value(),
+ "source frame history must contain a tombstone");
+
+ rcc::StackObjectDesc StackSlot;
+ StackSlot.Kind = rcc::StackObjectKind::SpillSlot;
+ StackSlot.Size = 8;
+ StackSlot.Align = *rcc::Alignment::create(8);
+ StackSlot.Offset = -16;
+ auto StackSlotIndex = Function.frameInfo().createObject(StackSlot);
+ Context.expect(StackSlotIndex.has_value(), "source live stack object must be created");
+ if (!StackSlotIndex)
+ return false;
+ Fixture.StackSlot = *StackSlotIndex;
+
Fixture.Entry = createBlock(Context, Function);
Fixture.Exit = createBlock(Context, Function);
if (Fixture.Entry == nullptr || Fixture.Exit == nullptr)
@@ -236,8 +257,7 @@ struct SourceFixture final {
"source tied copy must build");
auto Frame = Builder.buildInstr(rcc::Opcode::fromValue(FrameOpcode));
- Context.expect(Frame && Frame->addFrameIndex(rcc::FrameIndex::fromValue(4), -8).has_value() &&
- Frame->build(),
+ Context.expect(Frame && Frame->addFrameIndex(Fixture.StackSlot, -8).has_value() && Frame->build(),
"source frame-index instruction must build");
auto Address = Builder.buildInstr(rcc::Opcode::fromValue(BlockAddressOpcode));
@@ -246,7 +266,7 @@ struct SourceFixture final {
Address->build(),
"source self block-address instruction must build");
- auto MMO = Function.createMemOperand(loadDescription());
+ auto MMO = Function.createMemOperand(loadDescription(Fixture.StackSlot));
Context.expect(MMO.has_value(), "source MMO must be created");
if (!MMO)
return false;
@@ -255,6 +275,20 @@ struct SourceFixture final {
Context.expect(Load && Load->addMemOperand(**MMO).has_value() && Load->build(),
"source load with MMO must build");
+ rcc::MachineInstr *Definition = findInstruction(*Fixture.Entry, DefOpcode);
+ rcc::MachineInstr *LoadInstruction = findInstruction(*Fixture.Exit, LoadOpcode);
+ const rcc::StackObject *Object = Function.frameInfo().object(Fixture.StackSlot);
+ if (Definition == nullptr || LoadInstruction == nullptr || Object == nullptr)
+ return false;
+ rcc::StackObjectDesc UpdatedStackSlot = *Object->description();
+ UpdatedStackSlot.Lifetime.push_back({Definition->stableID(), LoadInstruction->stableID()});
+ Context.expect(Function.frameInfo()
+ .updateObject(Fixture.StackSlot, std::move(UpdatedStackSlot))
+ .has_value() &&
+ Function.frameInfo().setMaxCallFrameSize(16).has_value() &&
+ Function.frameInfo().freeze(32, *rcc::Alignment::create(16)).has_value(),
+ "source frame metadata must be finalized");
+
Function.properties().set(rcc::MachineFunctionProperty::IsSSA);
Function.properties().set(rcc::MachineFunctionProperty::TracksLiveness);
Function.properties().set(rcc::MachineFunctionProperty::NoPHIs);
@@ -289,7 +323,9 @@ void testDeepClone(TestContext &Context) {
"source and destination must independently preserve valid properties");
Context.expect(Source->allBlocks().size() == 3 && Destination.allBlocks().size() == 2 &&
Source->allInstructions().size() == 7 &&
- Destination.allInstructions().size() == 6,
+ Destination.allInstructions().size() == 6 &&
+ Source->frameInfo().objects().size() == 2 &&
+ Destination.frameInfo().objects().size() == 1,
"clone must omit detached arena history");
Context.expect(Clone->BlockStableIDs.size() == 2 && Clone->InstructionStableIDs.size() == 6 &&
Clone->VirtualRegisters.size() == 2,
@@ -375,21 +411,39 @@ void testDeepClone(TestContext &Context) {
DestinationCopy->operandAt(0)->tiedOperandIndex() == 1 &&
DestinationCopy->operandAt(1)->tiedOperandIndex() == 0,
"clone must remap tied registers and rebuild ties");
- Context.expect(DestinationFrame->operandAt(0)->getIf<rcc::FrameIndexOperand>()->Index ==
- rcc::FrameIndex::fromValue(4) &&
- Clone->FrameIndices.contains(rcc::FrameIndex::fromValue(4)),
- "clone must preserve and map frame indices");
+ const auto FramePosition = Clone->FrameIndices.find(Fixture.StackSlot);
+ Context.expect(FramePosition != Clone->FrameIndices.end() &&
+ FramePosition->second == rcc::FrameIndex::fromValue(0) &&
+ DestinationFrame->operandAt(0)->getIf<rcc::FrameIndexOperand>()->Index ==
+ FramePosition->second,
+ "clone must compact and remap frame indices");
Context.expect(
DestinationAddress->operandAt(0)->getIf<rcc::BlockAddressOperand>()->FunctionName ==
"cloned_function",
"clone must rewrite self block-address function names");
+ rcc::MachineMemOperandDesc ExpectedMMO = Fixture.LoadMMO->description();
+ if (FramePosition != Clone->FrameIndices.end())
+ ExpectedMMO.Base = rcc::MemoryBase::frameIndex(FramePosition->second);
Context.expect(DestinationLoad->memOperands().size() == 1 &&
DestinationLoad->memOperands()[0] != Fixture.LoadMMO &&
- *DestinationLoad->memOperands()[0] == *Fixture.LoadMMO &&
+ DestinationLoad->memOperands()[0]->description() == ExpectedMMO &&
Destination.ownsMemOperand(*DestinationLoad->memOperands()[0]) &&
!Source->ownsMemOperand(*DestinationLoad->memOperands()[0]),
- "clone must deep-copy MMO ownership while preserving semantics");
+ "clone must deep-copy MMO ownership while remapping frame semantics");
+
+ const rcc::StackObject *DestinationStackSlot =
+ FramePosition == Clone->FrameIndices.end()
+ ? nullptr
+ : Destination.frameInfo().object(FramePosition->second);
+ Context.expect(
+ DestinationStackSlot != nullptr && Destination.frameInfo().isFrozen() &&
+ Destination.frameInfo().staticStackSize() == 32 &&
+ Destination.frameInfo().maxCallFrameSize() == 16 &&
+ DestinationStackSlot->description()->Lifetime.size() == 1 &&
+ DestinationStackSlot->description()->Lifetime[0].Begin == DestinationDef->stableID() &&
+ DestinationStackSlot->description()->Lifetime[0].End == DestinationLoad->stableID(),
+ "clone must preserve frozen frame layout and remap instruction lifetimes");
rcc::MachineInstr *SourceDef = findInstruction(*Fixture.Entry, DefOpcode);
const auto InstructionID = SourceDef == nullptr