aboutsummaryrefslogtreecommitdiff
path: root/backend/unittests/CodeGen/MachineFrameInfoTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/unittests/CodeGen/MachineFrameInfoTest.cpp')
-rw-r--r--backend/unittests/CodeGen/MachineFrameInfoTest.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/backend/unittests/CodeGen/MachineFrameInfoTest.cpp b/backend/unittests/CodeGen/MachineFrameInfoTest.cpp
new file mode 100644
index 0000000..7368815
--- /dev/null
+++ b/backend/unittests/CodeGen/MachineFrameInfoTest.cpp
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/CodeGen/MachineFrameInfo.h"
+
+#include <cstdint>
+#include <iostream>
+#include <string_view>
+
+namespace {
+
+class TestContext final {
+public:
+ void expect(bool Condition, std::string_view Message) {
+ if (Condition)
+ return;
+ std::cerr << Message << '\n';
+ ++FailureCount;
+ }
+
+ [[nodiscard]] int result() const noexcept {
+ return FailureCount == 0 ? 0 : 1;
+ }
+
+private:
+ int FailureCount = 0;
+};
+
+[[nodiscard]] rcc::StackObjectDesc fixedObject(std::uint64_t Size, std::uint64_t Align) {
+ rcc::StackObjectDesc Description;
+ Description.Size = Size;
+ Description.Align = *rcc::Alignment::create(Align);
+ return Description;
+}
+
+void testObjectLifecycle(TestContext &Context) {
+ rcc::MachineFrameInfo Frame;
+
+ auto LocalDescription = fixedObject(8, 8);
+ LocalDescription.IsAliased = true;
+ LocalDescription.AddressTaken = true;
+ LocalDescription.Lifetime.push_back(
+ {rcc::MachineInstrStableID::fromValue(3), rcc::MachineInstrStableID::fromValue(7)});
+ auto Local = Frame.createObject(LocalDescription);
+
+ auto FixedDescription = fixedObject(16, 16);
+ FixedDescription.Kind = rcc::StackObjectKind::FixedABI;
+ FixedDescription.Offset = -32;
+ auto Fixed = Frame.createObject(FixedDescription);
+
+ auto SpillDescription = fixedObject(8, 8);
+ SpillDescription.Kind = rcc::StackObjectKind::SpillSlot;
+ auto Spill = Frame.createObject(SpillDescription);
+
+ rcc::StackObjectDesc VariableDescription;
+ VariableDescription.Kind = rcc::StackObjectKind::VariableSized;
+ VariableDescription.Align = *rcc::Alignment::create(32);
+ auto Variable = Frame.createObject(VariableDescription);
+
+ Context.expect(Local && Fixed && Spill && Variable, "valid stack object kinds must be created");
+ if (!Local || !Fixed || !Spill || !Variable)
+ return;
+
+ Context.expect(Local->value() == 0 && Fixed->value() == 1 && Spill->value() == 2 &&
+ Variable->value() == 3 && Frame.liveObjectCount() == 4,
+ "frame indices must be monotonic table identities");
+ Context.expect(Frame.object(*Fixed)->isFixed() && Frame.object(*Spill)->isSpill() &&
+ Frame.object(*Variable)->isVariableSized(),
+ "stack object semantic categories must be derived exactly");
+
+ Context.expect(Frame.setObjectOffset(*Local, -8).has_value() &&
+ Frame.setObjectOffset(*Spill, -16).has_value() &&
+ Frame.markObjectDead(*Spill).has_value(),
+ "live stack objects must support controlled pre-freeze updates");
+ Context.expect(Frame.object(*Spill)->description()->IsDead,
+ "dead stack object state must remain explicit");
+
+ Context.expect(Frame.eraseObject(*Fixed).has_value() && Frame.object(*Fixed) == nullptr &&
+ Frame.liveObjectCount() == 3,
+ "erasing a stack object must leave an inaccessible tombstone");
+ auto Replacement = Frame.createObject(fixedObject(4, 4));
+ Context.expect(Replacement && Replacement->value() == 4,
+ "erased frame indices must never be reused");
+ if (!Replacement)
+ return;
+ Context.expect(Frame.setObjectOffset(*Replacement, -24).has_value(),
+ "replacement stack object must accept a final offset");
+
+ Context.expect(Frame.setMaxCallFrameSize(24).has_value() &&
+ Frame.freeze(64, *rcc::Alignment::create(16)).has_value() &&
+ Frame.isFrozen() && Frame.staticStackSize() == 64 &&
+ Frame.stackAlignment().bytes() == 16 && Frame.maxCallFrameSize() == 24 &&
+ Frame.verify().has_value(),
+ "complete frame layout must freeze atomically");
+
+ Context.expect(!Frame.createObject(fixedObject(8, 8)) && !Frame.setObjectOffset(*Local, -40) &&
+ !Frame.eraseObject(*Local) && !Frame.setMaxCallFrameSize(32) &&
+ !Frame.freeze(64, *rcc::Alignment::create(16)),
+ "frozen frames must reject every semantic mutation");
+}
+
+void testInvalidDescriptions(TestContext &Context) {
+ rcc::MachineFrameInfo Frame;
+
+ rcc::StackObjectDesc MissingSize;
+ Context.expect(!Frame.createObject(MissingSize),
+ "fixed-size stack object must reject a missing size");
+
+ auto ZeroSize = fixedObject(0, 1);
+ Context.expect(!Frame.createObject(ZeroSize), "fixed-size stack object must reject zero size");
+
+ rcc::StackObjectDesc InvalidVariable;
+ InvalidVariable.Kind = rcc::StackObjectKind::DynamicAlloca;
+ InvalidVariable.Size = 8;
+ Context.expect(!Frame.createObject(InvalidVariable),
+ "variable-sized stack object must reject a fixed size");
+
+ auto MissingFixedOffset = fixedObject(8, 8);
+ MissingFixedOffset.Kind = rcc::StackObjectKind::FixedABI;
+ Context.expect(!Frame.createObject(MissingFixedOffset),
+ "fixed ABI stack object must require an offset");
+
+ auto InvalidTarget = fixedObject(8, 8);
+ InvalidTarget.Kind = rcc::StackObjectKind::Target;
+ Context.expect(!Frame.createObject(InvalidTarget),
+ "target stack object must carry target identity");
+
+ auto InvalidLifetime = fixedObject(8, 8);
+ InvalidLifetime.Lifetime.push_back(
+ {rcc::MachineInstrStableID::fromValue(4), rcc::MachineInstrStableID::fromValue(4)});
+ Context.expect(!Frame.createObject(InvalidLifetime),
+ "stack object lifetime must reject equal boundaries");
+
+ Context.expect(!rcc::StackID::targetStack(4), "target stack IDs must not overlap built-in IDs");
+ auto TargetStack = rcc::StackID::targetStack(256);
+ auto Target = fixedObject(8, 8);
+ Target.Kind = rcc::StackObjectKind::Target;
+ if (TargetStack)
+ Target.Stack = *TargetStack;
+ auto TargetIndex = Frame.createObject(Target);
+ Context.expect(TargetStack && TargetIndex,
+ "target stack identity must admit target stack objects");
+
+ auto Unresolved = Frame.createObject(fixedObject(8, 8));
+ Context.expect(Unresolved && !Frame.freeze(16, *rcc::Alignment::create(8)) && !Frame.isFrozen() &&
+ !Frame.staticStackSize() && Frame.verify().has_value(),
+ "failed frame freeze must not mutate frame state");
+}
+
+} // namespace
+
+int main() {
+ TestContext Context;
+ testObjectLifecycle(Context);
+ testInvalidDescriptions(Context);
+ return Context.result();
+}