18423a6f3SJohn McCall //=== - unittest/Support/OptimizedStructLayoutTest.cpp - Layout tests -----===//
28423a6f3SJohn McCall //
38423a6f3SJohn McCall // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48423a6f3SJohn McCall // See https://llvm.org/LICENSE.txt for license information.
58423a6f3SJohn McCall // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68423a6f3SJohn McCall //
78423a6f3SJohn McCall //===----------------------------------------------------------------------===//
88423a6f3SJohn McCall
98423a6f3SJohn McCall #include "llvm/Support/OptimizedStructLayout.h"
108423a6f3SJohn McCall #include "gtest/gtest.h"
118423a6f3SJohn McCall
128423a6f3SJohn McCall using namespace llvm;
138423a6f3SJohn McCall
148423a6f3SJohn McCall namespace {
158423a6f3SJohn McCall
168423a6f3SJohn McCall class LayoutTest {
178423a6f3SJohn McCall struct Field {
188423a6f3SJohn McCall uint64_t Size;
198423a6f3SJohn McCall Align Alignment;
208423a6f3SJohn McCall uint64_t ForcedOffset;
218423a6f3SJohn McCall uint64_t ExpectedOffset;
228423a6f3SJohn McCall };
238423a6f3SJohn McCall
248423a6f3SJohn McCall SmallVector<Field, 16> Fields;
258423a6f3SJohn McCall bool Verified = false;
268423a6f3SJohn McCall
278423a6f3SJohn McCall public:
LayoutTest()288423a6f3SJohn McCall LayoutTest() {}
298423a6f3SJohn McCall LayoutTest(const LayoutTest &) = delete;
308423a6f3SJohn McCall LayoutTest &operator=(const LayoutTest &) = delete;
~LayoutTest()318423a6f3SJohn McCall ~LayoutTest() { assert(Verified); }
328423a6f3SJohn McCall
flexible(uint64_t Size,uint64_t Alignment,uint64_t ExpectedOffset)338423a6f3SJohn McCall LayoutTest &flexible(uint64_t Size, uint64_t Alignment,
348423a6f3SJohn McCall uint64_t ExpectedOffset) {
358423a6f3SJohn McCall Fields.push_back({Size, Align(Alignment),
368423a6f3SJohn McCall OptimizedStructLayoutField::FlexibleOffset, ExpectedOffset});
378423a6f3SJohn McCall return *this;
388423a6f3SJohn McCall }
398423a6f3SJohn McCall
fixed(uint64_t Size,uint64_t Alignment,uint64_t Offset)408423a6f3SJohn McCall LayoutTest &fixed(uint64_t Size, uint64_t Alignment, uint64_t Offset) {
418423a6f3SJohn McCall Fields.push_back({Size, Align(Alignment), Offset, Offset});
428423a6f3SJohn McCall return *this;
438423a6f3SJohn McCall }
448423a6f3SJohn McCall
verify(uint64_t ExpectedSize,uint64_t ExpectedAlignment)458423a6f3SJohn McCall void verify(uint64_t ExpectedSize, uint64_t ExpectedAlignment) {
468423a6f3SJohn McCall SmallVector<OptimizedStructLayoutField, 8> LayoutFields;
478423a6f3SJohn McCall LayoutFields.reserve(Fields.size());
488423a6f3SJohn McCall for (auto &F : Fields)
498423a6f3SJohn McCall LayoutFields.emplace_back(&F, F.Size, F.Alignment, F.ForcedOffset);
508423a6f3SJohn McCall
518423a6f3SJohn McCall auto SizeAndAlign = performOptimizedStructLayout(LayoutFields);
528423a6f3SJohn McCall
538423a6f3SJohn McCall EXPECT_EQ(SizeAndAlign.first, ExpectedSize);
548423a6f3SJohn McCall EXPECT_EQ(SizeAndAlign.second, Align(ExpectedAlignment));
558423a6f3SJohn McCall
568423a6f3SJohn McCall for (auto &LF : LayoutFields) {
578423a6f3SJohn McCall auto &F = *static_cast<const Field *>(LF.Id);
588423a6f3SJohn McCall EXPECT_EQ(LF.Offset, F.ExpectedOffset);
598423a6f3SJohn McCall }
608423a6f3SJohn McCall
618423a6f3SJohn McCall Verified = true;
628423a6f3SJohn McCall }
638423a6f3SJohn McCall };
648423a6f3SJohn McCall
658423a6f3SJohn McCall }
668423a6f3SJohn McCall
TEST(OptimizedStructLayoutTest,Basic)678423a6f3SJohn McCall TEST(OptimizedStructLayoutTest, Basic) {
688423a6f3SJohn McCall LayoutTest()
698423a6f3SJohn McCall .flexible(12, 4, 8)
708423a6f3SJohn McCall .flexible(8, 8, 0)
718423a6f3SJohn McCall .flexible(4, 4, 20)
728423a6f3SJohn McCall .verify(24, 8);
738423a6f3SJohn McCall }
748423a6f3SJohn McCall
TEST(OptimizedStructLayoutTest,OddSize)758423a6f3SJohn McCall TEST(OptimizedStructLayoutTest, OddSize) {
768423a6f3SJohn McCall LayoutTest()
778423a6f3SJohn McCall .flexible(8, 8, 16)
788423a6f3SJohn McCall .flexible(4, 4, 12)
798423a6f3SJohn McCall .flexible(1, 1, 10)
808423a6f3SJohn McCall .flexible(10, 8, 0)
818423a6f3SJohn McCall .verify(24, 8);
828423a6f3SJohn McCall }
838423a6f3SJohn McCall
TEST(OptimizedStructLayoutTest,Gaps)848423a6f3SJohn McCall TEST(OptimizedStructLayoutTest, Gaps) {
858423a6f3SJohn McCall LayoutTest()
868423a6f3SJohn McCall .fixed(4, 4, 8)
878423a6f3SJohn McCall .fixed(4, 4, 16)
888423a6f3SJohn McCall .flexible(4, 4, 0)
898423a6f3SJohn McCall .flexible(4, 4, 4)
908423a6f3SJohn McCall .flexible(4, 4, 12)
918423a6f3SJohn McCall .flexible(4, 4, 20)
928423a6f3SJohn McCall .verify(24, 4);
938423a6f3SJohn McCall }
948423a6f3SJohn McCall
TEST(OptimizedStructLayoutTest,Greed)958423a6f3SJohn McCall TEST(OptimizedStructLayoutTest, Greed) {
968423a6f3SJohn McCall // The greedy algorithm doesn't find the optimal layout here, which
978423a6f3SJohn McCall // would be to put the 5-byte field at the end.
988423a6f3SJohn McCall LayoutTest()
998423a6f3SJohn McCall .fixed(4, 4, 8)
1008423a6f3SJohn McCall .flexible(5, 4, 0)
1018423a6f3SJohn McCall .flexible(4, 4, 12)
1028423a6f3SJohn McCall .flexible(4, 4, 16)
1038423a6f3SJohn McCall .flexible(4, 4, 20)
1048423a6f3SJohn McCall .verify(24, 4);
1058423a6f3SJohn McCall }
1068423a6f3SJohn McCall
TEST(OptimizedStructLayoutTest,Jagged)1078423a6f3SJohn McCall TEST(OptimizedStructLayoutTest, Jagged) {
1088423a6f3SJohn McCall LayoutTest()
1098423a6f3SJohn McCall .flexible(1, 2, 18)
1108423a6f3SJohn McCall .flexible(13, 8, 0)
1118423a6f3SJohn McCall .flexible(3, 2, 14)
1128423a6f3SJohn McCall .verify(19, 8);
1138423a6f3SJohn McCall }
1148423a6f3SJohn McCall
TEST(OptimizedStructLayoutTest,GardenPath)1158423a6f3SJohn McCall TEST(OptimizedStructLayoutTest, GardenPath) {
1168423a6f3SJohn McCall // The 4-byte-aligned field is our highest priority, but the less-aligned
1178423a6f3SJohn McCall // fields keep leaving the end offset mis-aligned.
1188423a6f3SJohn McCall LayoutTest()
1198423a6f3SJohn McCall .fixed(7, 4, 0)
1208423a6f3SJohn McCall .flexible(4, 4, 44)
1218423a6f3SJohn McCall .flexible(6, 1, 7)
1228423a6f3SJohn McCall .flexible(5, 1, 13)
1238423a6f3SJohn McCall .flexible(7, 2, 18)
1248423a6f3SJohn McCall .flexible(4, 1, 25)
1258423a6f3SJohn McCall .flexible(4, 1, 29)
1268423a6f3SJohn McCall .flexible(1, 1, 33)
1278423a6f3SJohn McCall .flexible(4, 2, 34)
1288423a6f3SJohn McCall .flexible(4, 2, 38)
1298423a6f3SJohn McCall .flexible(2, 2, 42)
1308423a6f3SJohn McCall .flexible(2, 2, 48)
1318423a6f3SJohn McCall .verify(50, 4);
1328423a6f3SJohn McCall }
133*326a5a26SJohn McCall
134*326a5a26SJohn McCall // PR 51131
TEST(OptimizedStructLayoutTest,HighAlignment)135*326a5a26SJohn McCall TEST(OptimizedStructLayoutTest, HighAlignment) {
136*326a5a26SJohn McCall // Handle the case where a flexible field has such a high alignment
137*326a5a26SJohn McCall // requirement that aligning LastEnd to it gives an offset past the
138*326a5a26SJohn McCall // end of the gap before the next fixed-alignment field.
139*326a5a26SJohn McCall LayoutTest()
140*326a5a26SJohn McCall .fixed(8, 8, 0)
141*326a5a26SJohn McCall .fixed(8, 8, 8)
142*326a5a26SJohn McCall .fixed(64, 64, 64)
143*326a5a26SJohn McCall .flexible(1, 1, 16)
144*326a5a26SJohn McCall .flexible(1, 1, 17)
145*326a5a26SJohn McCall .flexible(4, 128, 128)
146*326a5a26SJohn McCall .flexible(1, 1, 18)
147*326a5a26SJohn McCall .flexible(1, 1, 19)
148*326a5a26SJohn McCall .verify(132, 128);
149*326a5a26SJohn McCall }
150