Skip to content

Fix some bugs with high-alignment fields in continuations #981

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions llvm/include/llvm/Support/OptimalLayout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//===-- OptimalLayout.h - Optimal data 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.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// 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.
///
/// 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.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_OPTIMALLAYOUT_H
#define LLVM_SUPPORT_OPTIMALLAYOUT_H

#include "llvm/Support/Alignment.h"
#include "llvm/ADT/ArrayRef.h"
#include <utility>

namespace llvm {

/// A field in a structure.
struct OptimalLayoutField {
/// 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)
: Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) {
assert(Size > 0 && "adding an empty field to the layout");
}

/// The offset of this field in the final layout. If this is
/// initialized to FlexibleOffset, layout will overwrite it with
/// the assigned offset of the field.
uint64_t Offset;

/// The required size of this field in bytes. Does not have to be
/// a multiple of Alignment. Must be non-zero.
uint64_t Size;

/// A opaque value which uniquely identifies this field.
const void *Id;

/// Private scratch space for the algorithm. The implementation
/// must treat this as uninitialized memory on entry.
void *Scratch;

/// The required alignment of this field.
Align Alignment;

/// Return true if this field has been assigned a fixed offset.
/// After layout, this will be true of all the fields.
bool hasFixedOffset() const {
return (Offset != FlexibleOffset);
}

/// Given that this field has a fixed offset, return the offset
/// of the first byte following it.
uint64_t getEndOffset() const {
assert(hasFixedOffset());
return Offset + Size;
}
};

/// Compute a layout for a struct containing the given fields, making a
/// best-effort attempt to minimize the amount of space required.
///
/// Two features are supported which require a more careful solution
/// than the well-known "sort by decreasing alignment" solution:
///
/// - Fields may be assigned a fixed offset in the layout. If there are
/// gaps among the fixed-offset fields, the algorithm may attempt
/// to allocate flexible-offset fields into those gaps. If that's
/// undesirable, the caller should "block out" those gaps by e.g.
/// just creating a single fixed-offset field that represents the
/// entire "header".
///
/// - The size of a field is not required to be a multiple of, or even
/// greater than, the field's required alignment. The only constraint
/// on fields is that they must not be zero-sized.
///
/// To simplify the implementation, any fixed-offset fields in the
/// layout must appear at the start of the field array, and they must
/// be ordered by increasing offset.
///
/// The algorithm will produce a guaranteed-minimal layout with no
/// interior padding in the following "C-style" case:
///
/// - every field's size is a multiple of its required alignment and
/// - either no fields have initially fixed offsets, or the fixed-offset
/// fields have no interior padding and end at an offset that is at
/// least as aligned as all the flexible-offset fields.
///
/// Otherwise, while the algorithm will make a best-effort attempt to
/// avoid padding, it cannot guarantee a minimal layout, as there is
/// no known efficient algorithm for doing so.
///
/// The layout produced by this algorithm may not be stable across LLVM
/// releases. Do not use this anywhere where ABI stability is required.
///
/// Flexible-offset fields with the same size and alignment will be ordered
/// the same way they were in the initial array. Otherwise the current
/// algorithm makes no effort to preserve the initial order of
/// flexible-offset fields.
///
/// On return, all fields will have been assigned a fixed offset, and the
/// array will be sorted in order of ascending offsets. Note that this
/// means that the fixed-offset fields may no longer form a strict prefix
/// if there's any padding before they end.
///
/// 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);

} // namespace llvm

#endif
4 changes: 3 additions & 1 deletion llvm/lib/IR/Verifier.cpp
Original file line number Diff line number Diff line change
@@ -3073,7 +3073,9 @@ static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) {
if (Attrs.hasParamAttribute(I, AK))
Copy.addAttribute(AK);
}
if (Attrs.hasParamAttribute(I, Attribute::Alignment))
// `align` is ABI-affecting only in combination with `byval`.
if (Attrs.hasParamAttribute(I, Attribute::Alignment) &&
Attrs.hasParamAttribute(I, Attribute::ByVal))
Copy.addAlignmentAttr(Attrs.getParamAlignment(I));
return Copy;
}
1 change: 1 addition & 0 deletions llvm/lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -115,6 +115,7 @@ add_llvm_component_library(LLVMSupport
MemoryBuffer.cpp
MD5.cpp
NativeFormatting.cpp
OptimalLayout.cpp
Optional.cpp
Parallel.cpp
PluginLoader.cpp
Loading