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);
 | 
						|
}
 |