xref: /llvm-project/llvm/unittests/Support/OptimizedStructLayoutTest.cpp (revision 326a5a2658d81db46a78b184fe42e522ef170f32)
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