v8/test/unittests/compiler/frame-unittest.cc
Bill Budge e639eafea3 Reland "Reland "Reland "[compiler][wasm] Align Frame slots to value size"""
This is a reland of 352b9ecbdb

The test/fix CL has been merged in, as the fixes to return slot
accounting are needed to fix Arm64 issues turned up by the fuzzers:

https://chromium-review.googlesource.com/c/v8/v8/+/2644139

The reverted fix for Wasm return slot allocation is added in
patchset #2, to avoid fuzzer issues that it fixed:

https://chromium-review.googlesource.com/c/v8/v8/+/2683024

TBR=neis@chromium.org

Original change's description:
> Reland "Reland "[compiler][wasm] Align Frame slots to value size""
>
> This is a reland of 1694925c72
>
> Minor fix to linkage for constexpr.
>
> TBR=ahaas@chromium.org,neis@chromium.org
>
> Original change's description:
> > Reland "[compiler][wasm] Align Frame slots to value size"
> >
> > This is a reland of cddaf66c37
> >
> > Original change's description:
> > > [compiler][wasm] Align Frame slots to value size
> > >
> > > - Adds an AlignedSlotAllocator class and tests, to unify slot
> > >   allocation. This attempts to use alignment holes for smaller
> > >   values.
> > > - Reworks Frame to use the new allocator for stack slots.
> > > - Reworks LinkageAllocator to use the new allocator for stack
> > >   slots and for ARMv7 FP register aliasing.
> > > - Fixes the RegisterAllocator to align spill slots.
> > > - Fixes InstructionSelector to align spill slots.
> > >
> > > Bug: v8:9198
> > >
> > > Change-Id: Ida148db428be89ef95de748ec5fc0e7b0358f523
> > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2512840
> > > Commit-Queue: Bill Budge <bbudge@chromium.org>
> > > Reviewed-by: Georg Neis <neis@chromium.org>
> > > Reviewed-by: Andreas Haas <ahaas@chromium.org>
> > > Cr-Commit-Position: refs/heads/master@{#71644}
> >
> > Bug: v8:9198
> > Change-Id: Ib91fa6746370c38496706341e12d05c7bf999389
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2633390
> > Commit-Queue: Bill Budge <bbudge@chromium.org>
> > Reviewed-by: Andreas Haas <ahaas@chromium.org>
> > Reviewed-by: Georg Neis <neis@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#72195}
>
> Bug: v8:9198
> Change-Id: I91e02b823af8ec925dacf075388fb22e3eeb3384
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2640890
> Reviewed-by: Bill Budge <bbudge@chromium.org>
> Commit-Queue: Bill Budge <bbudge@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#72209}

Bug: v8:9198
Change-Id: Ia5cf63af4e5991bc7cf42da9972ffd044fc829f0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2733177
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73238}
2021-03-05 19:49:19 +00:00

243 lines
8.8 KiB
C++

// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/frame.h"
#include "src/codegen/aligned-slot-allocator.h"
#include "testing/gtest-support.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
constexpr int kSlotSize = AlignedSlotAllocator::kSlotSize;
constexpr int kFixed1 = 1;
constexpr int kFixed3 = 3;
} // namespace
class FrameTest : public ::testing::Test {
public:
FrameTest() = default;
~FrameTest() override = default;
};
TEST_F(FrameTest, Constructor) {
Frame frame(kFixed3);
EXPECT_EQ(kFixed3, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(0, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, ReserveSpillSlots) {
Frame frame(kFixed3);
constexpr int kReserve2 = 2;
frame.ReserveSpillSlots(kReserve2);
EXPECT_EQ(kFixed3 + kReserve2, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(kReserve2, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, EnsureReturnSlots) {
Frame frame(kFixed3);
constexpr int kReturn3 = 3;
constexpr int kReturn5 = 5;
constexpr int kReturn2 = 2;
frame.EnsureReturnSlots(kReturn3);
EXPECT_EQ(kFixed3 + kReturn3, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(0, frame.GetSpillSlotCount());
EXPECT_EQ(kReturn3, frame.GetReturnSlotCount());
// Returns should grow by 2 slots.
frame.EnsureReturnSlots(kReturn5);
EXPECT_EQ(kFixed3 + kReturn5, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(0, frame.GetSpillSlotCount());
EXPECT_EQ(kReturn5, frame.GetReturnSlotCount());
// Returns shouldn't grow.
frame.EnsureReturnSlots(kReturn2);
EXPECT_EQ(kFixed3 + kReturn5, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(0, frame.GetSpillSlotCount());
EXPECT_EQ(kReturn5, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AllocateSavedCalleeRegisterSlots) {
Frame frame(kFixed3);
constexpr int kFirstSlots = 2;
constexpr int kSecondSlots = 3;
frame.AllocateSavedCalleeRegisterSlots(kFirstSlots);
EXPECT_EQ(kFixed3 + kFirstSlots, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(0, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
frame.AllocateSavedCalleeRegisterSlots(kSecondSlots);
EXPECT_EQ(kFixed3 + kFirstSlots + kSecondSlots,
frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(0, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AlignSavedCalleeRegisterSlots) {
Frame frame(kFixed3);
constexpr int kSlots = 2; // An even number leaves the slots misaligned.
frame.AllocateSavedCalleeRegisterSlots(kSlots);
// Align, which should add 1 padding slot.
frame.AlignSavedCalleeRegisterSlots(2 * kSlotSize);
EXPECT_EQ(kFixed3 + kSlots + 1, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(1, frame.GetSpillSlotCount()); // padding
EXPECT_EQ(0, frame.GetReturnSlotCount());
// Align again, which should not add a padding slot.
frame.AlignSavedCalleeRegisterSlots(2 * kSlotSize);
EXPECT_EQ(kFixed3 + kSlots + 1, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(1, frame.GetSpillSlotCount()); // padding
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AllocateSpillSlotAligned) {
Frame frame(kFixed1);
// Allocate a quad slot, which must add 3 padding slots. Frame returns the
// last index of the 4 slot allocation.
int end = kFixed1 + 3 + 4;
int slot = kFixed1 + 3 + 4 - 1;
EXPECT_EQ(slot, frame.AllocateSpillSlot(4 * kSlotSize, 4 * kSlotSize));
EXPECT_EQ(end, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed1, frame.GetFixedSlotCount());
EXPECT_EQ(end - kFixed1, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
// Allocate a double slot, which should leave the first padding slot and
// take the last two slots of padding.
slot = kFixed1 + 1 + 2 - 1;
EXPECT_EQ(slot, frame.AllocateSpillSlot(2 * kSlotSize, 2 * kSlotSize));
EXPECT_EQ(end, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed1, frame.GetFixedSlotCount());
EXPECT_EQ(end - kFixed1, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
// Allocate a single slot, which should take the last padding slot.
slot = kFixed1;
EXPECT_EQ(slot, frame.AllocateSpillSlot(kSlotSize, kSlotSize));
EXPECT_EQ(end, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed1, frame.GetFixedSlotCount());
EXPECT_EQ(end - kFixed1, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AllocateSpillSlotAlignedWithReturns) {
Frame frame(kFixed3);
constexpr int kReturn3 = 3;
constexpr int kReturn5 = 5;
frame.EnsureReturnSlots(kReturn3);
// Allocate a double slot, which must add 1 padding slot. This should occupy
// slots 4 and 5, and AllocateSpillSlot returns the last slot index.
EXPECT_EQ(kFixed3 + 2, frame.AllocateSpillSlot(2 * kSlotSize, 2 * kSlotSize));
EXPECT_EQ(kFixed3 + kReturn3 + 3, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(3, frame.GetSpillSlotCount());
EXPECT_EQ(kReturn3, frame.GetReturnSlotCount());
frame.EnsureReturnSlots(kReturn5);
// Allocate a single slot, which should take the padding slot.
EXPECT_EQ(kFixed3, frame.AllocateSpillSlot(kSlotSize, kSlotSize));
EXPECT_EQ(kFixed3 + kReturn5 + 3, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(3, frame.GetSpillSlotCount());
EXPECT_EQ(kReturn5, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AllocateSpillSlotAndEndSpillArea) {
Frame frame(kFixed3);
// Allocate a double slot, which must add 1 padding slot.
EXPECT_EQ(kFixed3 + 2, frame.AllocateSpillSlot(2 * kSlotSize, 2 * kSlotSize));
// Allocate an unaligned double slot. This should be at the end.
EXPECT_EQ(kFixed3 + 4, frame.AllocateSpillSlot(2 * kSlotSize));
EXPECT_EQ(kFixed3 + 5, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(5, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
// Allocate a single slot. This should not be the padding slot, since that
// area has been closed by the unaligned allocation.
EXPECT_EQ(kFixed3 + 5, frame.AllocateSpillSlot(kSlotSize, kSlotSize));
EXPECT_EQ(kFixed3 + 6, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(6, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AllocateSpillSlotOverAligned) {
Frame frame(kFixed1);
// Allocate a 4-aligned double slot, which must add 3 padding slots. This
// also terminates the slot area. Returns the starting slot in this case.
EXPECT_EQ(kFixed1 + 4, frame.AllocateSpillSlot(2 * kSlotSize, 4 * kSlotSize));
EXPECT_EQ(kFixed1 + 5, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed1, frame.GetFixedSlotCount());
EXPECT_EQ(5, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
// Allocate a single slot. This should not use any padding slot.
EXPECT_EQ(kFixed1 + 5, frame.AllocateSpillSlot(kSlotSize, kSlotSize));
EXPECT_EQ(kFixed1 + 6, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed1, frame.GetFixedSlotCount());
EXPECT_EQ(6, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AllocateSpillSlotUnderAligned) {
Frame frame(kFixed1);
// Allocate a 1-aligned double slot. This also terminates the slot area.
EXPECT_EQ(kFixed1 + 1, frame.AllocateSpillSlot(2 * kSlotSize, kSlotSize));
EXPECT_EQ(kFixed1 + 2, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed1, frame.GetFixedSlotCount());
EXPECT_EQ(2, frame.GetSpillSlotCount());
EXPECT_EQ(0, frame.GetReturnSlotCount());
}
TEST_F(FrameTest, AlignFrame) {
Frame frame(kFixed3);
constexpr int kReturn3 = 3;
frame.EnsureReturnSlots(kReturn3);
// Allocate two single slots, which leaves spill slots not 2-aligned.
EXPECT_EQ(kFixed3, frame.AllocateSpillSlot(kSlotSize, kSlotSize));
EXPECT_EQ(kFixed3 + 1, frame.AllocateSpillSlot(kSlotSize, kSlotSize));
// Align to 2 slots. This should pad the spill and return slot areas.
frame.AlignFrame(2 * kSlotSize);
EXPECT_EQ(kFixed3 + 3 + kReturn3 + 1, frame.GetTotalFrameSlotCount());
EXPECT_EQ(kFixed3, frame.GetFixedSlotCount());
EXPECT_EQ(3, frame.GetSpillSlotCount());
EXPECT_EQ(kReturn3 + 1, frame.GetReturnSlotCount());
}
} // namespace compiler
} // namespace internal
} // namespace v8