mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-28 13:51:09 +00:00
Rename OptimalLayout to OptimizedStructLayout at Chris's request.
This commit is contained in:
parent
4f1d6dd171
commit
9fa45eab44
@ -1,4 +1,4 @@
|
||||
//===-- OptimalLayout.h - Optimal data layout algorithm -----------*- C++ -*-=//
|
||||
//===-- OptimizedStructLayout.h - Struct layout algorithm ---------*- C++ -*-=//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@ -8,19 +8,31 @@
|
||||
///
|
||||
/// This file provides an interface for laying out a sequence of fields
|
||||
/// as a struct in a way that attempts to minimizes the total space
|
||||
/// requirements of the struct.
|
||||
/// requirements of the struct while still satisfying the layout
|
||||
/// requirements of the individual fields. The resulting layout may be
|
||||
/// substantially more compact than simply laying out the fields in their
|
||||
/// original order.
|
||||
///
|
||||
/// The word "optimal" is a misnomer in several ways. First, minimizing
|
||||
/// space usage doesn't necessarily yield optimal performance because it
|
||||
/// may decrease locality. Second, there is no known efficient algorithm
|
||||
/// that guarantees a minimal layout for arbitrary inputs. Nonetheless,
|
||||
/// this algorithm is likely to produce much more compact layouts than
|
||||
/// would be produced by just allocating space in a buffer.
|
||||
/// Fields may be pre-assigned fixed offsets. They may also be given sizes
|
||||
/// that are not multiples of their alignments. There is no currently no
|
||||
/// way to describe that a field has interior padding that other fields may
|
||||
/// be allocated into.
|
||||
///
|
||||
/// This algorithm does not claim to be "optimal" for several reasons:
|
||||
///
|
||||
/// - First, it does not guarantee that the result is minimal in size.
|
||||
/// There is no known efficient algoorithm to achieve minimality for
|
||||
/// unrestricted inputs. Nonetheless, this algorithm
|
||||
///
|
||||
/// - Second, there are other ways that a struct layout could be optimized
|
||||
/// besides space usage, such as locality. This layout may have a mixed
|
||||
/// impact on locality: less overall memory may be used, but adjacent
|
||||
/// fields in the original array may be moved further from one another.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_OPTIMALLAYOUT_H
|
||||
#define LLVM_SUPPORT_OPTIMALLAYOUT_H
|
||||
#ifndef LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H
|
||||
#define LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H
|
||||
|
||||
#include "llvm/Support/Alignment.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
@ -29,13 +41,13 @@
|
||||
namespace llvm {
|
||||
|
||||
/// A field in a structure.
|
||||
struct OptimalLayoutField {
|
||||
struct OptimizedStructLayoutField {
|
||||
/// A special value for Offset indicating that the field can be moved
|
||||
/// anywhere.
|
||||
static constexpr uint64_t FlexibleOffset = ~(uint64_t)0;
|
||||
|
||||
OptimalLayoutField(const void *Id, uint64_t Size, Align Alignment,
|
||||
uint64_t FixedOffset = FlexibleOffset)
|
||||
OptimizedStructLayoutField(const void *Id, uint64_t Size, Align Alignment,
|
||||
uint64_t FixedOffset = FlexibleOffset)
|
||||
: Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) {
|
||||
assert(Size > 0 && "adding an empty field to the layout");
|
||||
}
|
||||
@ -122,8 +134,8 @@ struct OptimalLayoutField {
|
||||
/// The return value is the total size of the struct and its required
|
||||
/// alignment. Note that the total size is not rounded up to a multiple
|
||||
/// of the required alignment; clients which require this can do so easily.
|
||||
std::pair<uint64_t, Align>
|
||||
performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields);
|
||||
std::pair<uint64_t, Align> performOptimizedStructLayout(
|
||||
MutableArrayRef<OptimizedStructLayoutField> Fields);
|
||||
|
||||
} // namespace llvm
|
||||
|
@ -117,7 +117,7 @@ add_llvm_component_library(LLVMSupport
|
||||
MemoryBuffer.cpp
|
||||
MD5.cpp
|
||||
NativeFormatting.cpp
|
||||
OptimalLayout.cpp
|
||||
OptimizedStructLayout.cpp
|
||||
Optional.cpp
|
||||
Parallel.cpp
|
||||
PluginLoader.cpp
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===--- OptimalLayout.cpp - Optimal data layout algorithm ----------------===//
|
||||
//===--- OptimizedStructLayout.cpp - Optimal data layout algorithm ----------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@ -6,16 +6,18 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the performOptimalLayout interface.
|
||||
// This file implements the performOptimizedStructLayout interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/OptimalLayout.h"
|
||||
#include "llvm/Support/OptimizedStructLayout.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
using Field = OptimizedStructLayoutField;
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void checkValidLayout(ArrayRef<OptimalLayoutField> Fields, uint64_t Size,
|
||||
static void checkValidLayout(ArrayRef<Field> Fields, uint64_t Size,
|
||||
Align MaxAlign) {
|
||||
uint64_t LastEnd = 0;
|
||||
Align ComputedMaxAlign;
|
||||
@ -37,7 +39,7 @@ static void checkValidLayout(ArrayRef<OptimalLayoutField> Fields, uint64_t Size,
|
||||
#endif
|
||||
|
||||
std::pair<uint64_t, Align>
|
||||
llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
llvm::performOptimizedStructLayout(MutableArrayRef<Field> Fields) {
|
||||
#ifndef NDEBUG
|
||||
// Do some simple precondition checks.
|
||||
{
|
||||
@ -101,8 +103,7 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
// important if we get into the gap-filling stage below, but it
|
||||
// doesn't hurt here.
|
||||
array_pod_sort(FirstFlexible, E,
|
||||
[](const OptimalLayoutField *lhs,
|
||||
const OptimalLayoutField *rhs) -> int {
|
||||
[](const Field *lhs, const Field *rhs) -> int {
|
||||
// Decreasing alignment.
|
||||
if (lhs->Alignment != rhs->Alignment)
|
||||
return (lhs->Alignment < rhs->Alignment ? 1 : -1);
|
||||
@ -240,13 +241,13 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
/// monotonically descending in size and otherwise in the original order.
|
||||
///
|
||||
/// We remove the queue from the array as soon as this is empty.
|
||||
OptimalLayoutField *Head;
|
||||
OptimizedStructLayoutField *Head;
|
||||
|
||||
/// The alignment requirement of the queue.
|
||||
Align Alignment;
|
||||
|
||||
static OptimalLayoutField *getNext(OptimalLayoutField *Cur) {
|
||||
return static_cast<OptimalLayoutField*>(Cur->Scratch);
|
||||
static Field *getNext(Field *Cur) {
|
||||
return static_cast<Field *>(Cur->Scratch);
|
||||
}
|
||||
};
|
||||
SmallVector<AlignmentQueue, 8> FlexibleFieldsByAlignment;
|
||||
@ -290,9 +291,7 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
#endif
|
||||
|
||||
/// Helper function to remove a field from a queue.
|
||||
auto spliceFromQueue = [&](AlignmentQueue *Queue,
|
||||
OptimalLayoutField *Last,
|
||||
OptimalLayoutField *Cur) {
|
||||
auto spliceFromQueue = [&](AlignmentQueue *Queue, Field *Last, Field *Cur) {
|
||||
assert(Last ? Queue->getNext(Last) == Cur : Queue->Head == Cur);
|
||||
|
||||
// If we're removing Cur from a non-initial position, splice it out
|
||||
@ -319,7 +318,7 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
|
||||
// Do layout into a local array. Doing this in-place on Fields is
|
||||
// not really feasible.
|
||||
SmallVector<OptimalLayoutField, 16> Layout;
|
||||
SmallVector<Field, 16> Layout;
|
||||
Layout.reserve(Fields.size());
|
||||
|
||||
// The offset that we're currently looking to insert at (or after).
|
||||
@ -327,9 +326,7 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
|
||||
// Helper function to splice Cur out of the given queue and add it
|
||||
// to the layout at the given offset.
|
||||
auto addToLayout = [&](AlignmentQueue *Queue,
|
||||
OptimalLayoutField *Last,
|
||||
OptimalLayoutField *Cur,
|
||||
auto addToLayout = [&](AlignmentQueue *Queue, Field *Last, Field *Cur,
|
||||
uint64_t Offset) -> bool {
|
||||
assert(Offset == alignTo(LastEnd, Cur->Alignment));
|
||||
|
||||
@ -362,8 +359,8 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
|
||||
// Find the matching field. Note that this should always find
|
||||
// something because of the MinSize check above.
|
||||
for (OptimalLayoutField *Cur = Queue->Head, *Last = nullptr;
|
||||
true; Last = Cur, Cur = Queue->getNext(Cur)) {
|
||||
for (Field *Cur = Queue->Head, *Last = nullptr; true;
|
||||
Last = Cur, Cur = Queue->getNext(Cur)) {
|
||||
assert(Cur && "didn't find a match in queue despite its MinSize");
|
||||
if (Cur->Size <= MaxViableSize)
|
||||
return addToLayout(Queue, Last, Cur, StartOffset);
|
||||
@ -441,7 +438,7 @@ llvm::performOptimalLayout(MutableArrayRef<OptimalLayoutField> Fields) {
|
||||
// Copy the layout back into place.
|
||||
assert(Layout.size() == Fields.size());
|
||||
memcpy(Fields.data(), Layout.data(),
|
||||
Fields.size() * sizeof(OptimalLayoutField));
|
||||
Fields.size() * sizeof(OptimizedStructLayoutField));
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Make a final check that the layout is valid.
|
@ -29,7 +29,7 @@
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/circular_raw_ostream.h"
|
||||
#include "llvm/Support/OptimalLayout.h"
|
||||
#include "llvm/Support/OptimizedStructLayout.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
|
||||
@ -412,7 +412,7 @@ public:
|
||||
|
||||
// Everything else has a flexible offset.
|
||||
} else {
|
||||
Offset = OptimalLayoutField::FlexibleOffset;
|
||||
Offset = OptimizedStructLayoutField::FlexibleOffset;
|
||||
}
|
||||
|
||||
Fields.push_back({FieldSize, Offset, ForSpill, Ty, 0,
|
||||
@ -445,7 +445,7 @@ void FrameTypeBuilder::finish(StructType *Ty) {
|
||||
|
||||
// Prepare the optimal-layout field array.
|
||||
// The Id in the layout field is a pointer to our Field for it.
|
||||
SmallVector<OptimalLayoutField, 8> LayoutFields;
|
||||
SmallVector<OptimizedStructLayoutField, 8> LayoutFields;
|
||||
LayoutFields.reserve(Fields.size());
|
||||
for (auto &Field : Fields) {
|
||||
LayoutFields.emplace_back(&Field, Field.Size, Field.Alignment,
|
||||
@ -453,11 +453,11 @@ void FrameTypeBuilder::finish(StructType *Ty) {
|
||||
}
|
||||
|
||||
// Perform layout.
|
||||
auto SizeAndAlign = performOptimalLayout(LayoutFields);
|
||||
auto SizeAndAlign = performOptimizedStructLayout(LayoutFields);
|
||||
StructSize = SizeAndAlign.first;
|
||||
StructAlign = SizeAndAlign.second;
|
||||
|
||||
auto getField = [](const OptimalLayoutField &LayoutField) -> Field & {
|
||||
auto getField = [](const OptimizedStructLayoutField &LayoutField) -> Field & {
|
||||
return *static_cast<Field *>(const_cast<void*>(LayoutField.Id));
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ add_llvm_unittest(SupportTests
|
||||
MemoryBufferTest.cpp
|
||||
MemoryTest.cpp
|
||||
NativeFormatTests.cpp
|
||||
OptimalLayoutTest.cpp
|
||||
OptimizedStructLayoutTest.cpp
|
||||
ParallelTest.cpp
|
||||
Path.cpp
|
||||
ProcessTest.cpp
|
||||
|
@ -1,4 +1,4 @@
|
||||
//=== - llvm/unittest/Support/OptimalLayoutTest.cpp - Layout tests --------===//
|
||||
//=== - 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.
|
||||
@ -6,7 +6,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/OptimalLayout.h"
|
||||
#include "llvm/Support/OptimizedStructLayout.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
@ -33,7 +33,7 @@ public:
|
||||
LayoutTest &flexible(uint64_t Size, uint64_t Alignment,
|
||||
uint64_t ExpectedOffset) {
|
||||
Fields.push_back({Size, Align(Alignment),
|
||||
OptimalLayoutField::FlexibleOffset, ExpectedOffset});
|
||||
OptimizedStructLayoutField::FlexibleOffset, ExpectedOffset});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -43,12 +43,12 @@ public:
|
||||
}
|
||||
|
||||
void verify(uint64_t ExpectedSize, uint64_t ExpectedAlignment) {
|
||||
SmallVector<OptimalLayoutField, 8> LayoutFields;
|
||||
SmallVector<OptimizedStructLayoutField, 8> LayoutFields;
|
||||
LayoutFields.reserve(Fields.size());
|
||||
for (auto &F : Fields)
|
||||
LayoutFields.emplace_back(&F, F.Size, F.Alignment, F.ForcedOffset);
|
||||
|
||||
auto SizeAndAlign = performOptimalLayout(LayoutFields);
|
||||
auto SizeAndAlign = performOptimizedStructLayout(LayoutFields);
|
||||
|
||||
EXPECT_EQ(SizeAndAlign.first, ExpectedSize);
|
||||
EXPECT_EQ(SizeAndAlign.second, Align(ExpectedAlignment));
|
||||
@ -64,7 +64,7 @@ public:
|
||||
|
||||
}
|
||||
|
||||
TEST(OptimalLayoutTest, Basic) {
|
||||
TEST(OptimizedStructLayoutTest, Basic) {
|
||||
LayoutTest()
|
||||
.flexible(12, 4, 8)
|
||||
.flexible(8, 8, 0)
|
||||
@ -72,7 +72,7 @@ TEST(OptimalLayoutTest, Basic) {
|
||||
.verify(24, 8);
|
||||
}
|
||||
|
||||
TEST(OptimalLayoutTest, OddSize) {
|
||||
TEST(OptimizedStructLayoutTest, OddSize) {
|
||||
LayoutTest()
|
||||
.flexible(8, 8, 16)
|
||||
.flexible(4, 4, 12)
|
||||
@ -81,7 +81,7 @@ TEST(OptimalLayoutTest, OddSize) {
|
||||
.verify(24, 8);
|
||||
}
|
||||
|
||||
TEST(OptimalLayoutTest, Gaps) {
|
||||
TEST(OptimizedStructLayoutTest, Gaps) {
|
||||
LayoutTest()
|
||||
.fixed(4, 4, 8)
|
||||
.fixed(4, 4, 16)
|
||||
@ -92,7 +92,7 @@ TEST(OptimalLayoutTest, Gaps) {
|
||||
.verify(24, 4);
|
||||
}
|
||||
|
||||
TEST(OptimalLayoutTest, Greed) {
|
||||
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()
|
||||
@ -104,7 +104,7 @@ TEST(OptimalLayoutTest, Greed) {
|
||||
.verify(24, 4);
|
||||
}
|
||||
|
||||
TEST(OptimalLayoutTest, Jagged) {
|
||||
TEST(OptimizedStructLayoutTest, Jagged) {
|
||||
LayoutTest()
|
||||
.flexible(1, 2, 18)
|
||||
.flexible(13, 8, 0)
|
||||
@ -112,7 +112,7 @@ TEST(OptimalLayoutTest, Jagged) {
|
||||
.verify(19, 8);
|
||||
}
|
||||
|
||||
TEST(OptimalLayoutTest, GardenPath) {
|
||||
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()
|
@ -95,7 +95,7 @@ static_library("Support") {
|
||||
"MathExtras.cpp",
|
||||
"MemoryBuffer.cpp",
|
||||
"NativeFormatting.cpp",
|
||||
"OptimalLayout.cpp",
|
||||
"OptimizedStructLayout.cpp",
|
||||
"Optional.cpp",
|
||||
"Parallel.cpp",
|
||||
"PluginLoader.cpp",
|
||||
|
@ -55,7 +55,7 @@ unittest("SupportTests") {
|
||||
"MemoryBufferTest.cpp",
|
||||
"MemoryTest.cpp",
|
||||
"NativeFormatTests.cpp",
|
||||
"OptimalLayoutTest.cpp",
|
||||
"OptimizedStructLayoutTest.cpp",
|
||||
"ParallelTest.cpp",
|
||||
"Path.cpp",
|
||||
"ProcessTest.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user