mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
9f30d2a5ae
fixed fields with highly-aligned flexible fields. The code was not considering the possibility that aligning the current offset to the alignment of a queue might push us past the end of the gap. Subtracting the offsets to figure out the maximum field size for the gap then overflowed, making us think that we had nearly unbounded space to fill. Fixes PR 51131.
150 lines
3.8 KiB
C++
150 lines
3.8 KiB
C++
//=== - unittest/Support/OptimizedStructLayoutTest.cpp - Layout tests -----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/OptimizedStructLayout.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
class LayoutTest {
|
|
struct Field {
|
|
uint64_t Size;
|
|
Align Alignment;
|
|
uint64_t ForcedOffset;
|
|
uint64_t ExpectedOffset;
|
|
};
|
|
|
|
SmallVector<Field, 16> Fields;
|
|
bool Verified = false;
|
|
|
|
public:
|
|
LayoutTest() {}
|
|
LayoutTest(const LayoutTest &) = delete;
|
|
LayoutTest &operator=(const LayoutTest &) = delete;
|
|
~LayoutTest() { assert(Verified); }
|
|
|
|
LayoutTest &flexible(uint64_t Size, uint64_t Alignment,
|
|
uint64_t ExpectedOffset) {
|
|
Fields.push_back({Size, Align(Alignment),
|
|
OptimizedStructLayoutField::FlexibleOffset, ExpectedOffset});
|
|
return *this;
|
|
}
|
|
|
|
LayoutTest &fixed(uint64_t Size, uint64_t Alignment, uint64_t Offset) {
|
|
Fields.push_back({Size, Align(Alignment), Offset, Offset});
|
|
return *this;
|
|
}
|
|
|
|
void verify(uint64_t ExpectedSize, uint64_t ExpectedAlignment) {
|
|
SmallVector<OptimizedStructLayoutField, 8> LayoutFields;
|
|
LayoutFields.reserve(Fields.size());
|
|
for (auto &F : Fields)
|
|
LayoutFields.emplace_back(&F, F.Size, F.Alignment, F.ForcedOffset);
|
|
|
|
auto SizeAndAlign = performOptimizedStructLayout(LayoutFields);
|
|
|
|
EXPECT_EQ(SizeAndAlign.first, ExpectedSize);
|
|
EXPECT_EQ(SizeAndAlign.second, Align(ExpectedAlignment));
|
|
|
|
for (auto &LF : LayoutFields) {
|
|
auto &F = *static_cast<const Field *>(LF.Id);
|
|
EXPECT_EQ(LF.Offset, F.ExpectedOffset);
|
|
}
|
|
|
|
Verified = true;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
TEST(OptimizedStructLayoutTest, Basic) {
|
|
LayoutTest()
|
|
.flexible(12, 4, 8)
|
|
.flexible(8, 8, 0)
|
|
.flexible(4, 4, 20)
|
|
.verify(24, 8);
|
|
}
|
|
|
|
TEST(OptimizedStructLayoutTest, OddSize) {
|
|
LayoutTest()
|
|
.flexible(8, 8, 16)
|
|
.flexible(4, 4, 12)
|
|
.flexible(1, 1, 10)
|
|
.flexible(10, 8, 0)
|
|
.verify(24, 8);
|
|
}
|
|
|
|
TEST(OptimizedStructLayoutTest, Gaps) {
|
|
LayoutTest()
|
|
.fixed(4, 4, 8)
|
|
.fixed(4, 4, 16)
|
|
.flexible(4, 4, 0)
|
|
.flexible(4, 4, 4)
|
|
.flexible(4, 4, 12)
|
|
.flexible(4, 4, 20)
|
|
.verify(24, 4);
|
|
}
|
|
|
|
TEST(OptimizedStructLayoutTest, Greed) {
|
|
// The greedy algorithm doesn't find the optimal layout here, which
|
|
// would be to put the 5-byte field at the end.
|
|
LayoutTest()
|
|
.fixed(4, 4, 8)
|
|
.flexible(5, 4, 0)
|
|
.flexible(4, 4, 12)
|
|
.flexible(4, 4, 16)
|
|
.flexible(4, 4, 20)
|
|
.verify(24, 4);
|
|
}
|
|
|
|
TEST(OptimizedStructLayoutTest, Jagged) {
|
|
LayoutTest()
|
|
.flexible(1, 2, 18)
|
|
.flexible(13, 8, 0)
|
|
.flexible(3, 2, 14)
|
|
.verify(19, 8);
|
|
}
|
|
|
|
TEST(OptimizedStructLayoutTest, GardenPath) {
|
|
// The 4-byte-aligned field is our highest priority, but the less-aligned
|
|
// fields keep leaving the end offset mis-aligned.
|
|
LayoutTest()
|
|
.fixed(7, 4, 0)
|
|
.flexible(4, 4, 44)
|
|
.flexible(6, 1, 7)
|
|
.flexible(5, 1, 13)
|
|
.flexible(7, 2, 18)
|
|
.flexible(4, 1, 25)
|
|
.flexible(4, 1, 29)
|
|
.flexible(1, 1, 33)
|
|
.flexible(4, 2, 34)
|
|
.flexible(4, 2, 38)
|
|
.flexible(2, 2, 42)
|
|
.flexible(2, 2, 48)
|
|
.verify(50, 4);
|
|
}
|
|
|
|
// PR 51131
|
|
TEST(OptimizedStructLayoutTest, HighAlignment) {
|
|
// Handle the case where a flexible field has such a high alignment
|
|
// requirement that aligning LastEnd to it gives an offset past the
|
|
// end of the gap before the next fixed-alignment field.
|
|
LayoutTest()
|
|
.fixed(8, 8, 0)
|
|
.fixed(8, 8, 8)
|
|
.fixed(64, 64, 64)
|
|
.flexible(1, 1, 16)
|
|
.flexible(1, 1, 17)
|
|
.flexible(4, 128, 128)
|
|
.flexible(1, 1, 18)
|
|
.flexible(1, 1, 19)
|
|
.verify(132, 128);
|
|
}
|