Skip to content

[GSB] Improve handling of layout constraints #8253

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 2 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
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
48 changes: 47 additions & 1 deletion include/swift/AST/LayoutConstraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ enum class LayoutConstraintKind : unsigned char {
TrivialOfAtMostSize,
// It is a layout constraint representing a trivial type of an unknown size.
Trivial,
// It is a layout constraint representing a reference counted class instance.
Class,
// It is a layout constraint representing a reference counted native class
// instance.
NativeClass,
// It is a layout constraint representing a reference counted object.
RefCountedObject,
// It is a layout constraint representing a native reference counted object.
NativeRefCountedObject,
LastLayout = NativeRefCountedObject,
};

/// This is a class representing the layout constraint.
Expand Down Expand Up @@ -108,6 +114,22 @@ class LayoutConstraintInfo : public llvm::FoldingSetNode {
return isNativeRefCountedObject(Kind);
}

bool isClass() const {
return isClass(Kind);
}

bool isNativeClass() const {
return isNativeClass(Kind);
}

bool isRefCounted() const {
return isRefCounted(Kind);
}

bool isNativeRefCounted() const {
return isNativeRefCounted(Kind);
}

unsigned getTrivialSizeInBytes() const {
assert(isKnownSizeTrivial());
return (SizeInBits + 7) / 8;
Expand Down Expand Up @@ -170,6 +192,16 @@ class LayoutConstraintInfo : public llvm::FoldingSetNode {

static bool isNativeRefCountedObject(LayoutConstraintKind Kind);

static bool isAnyRefCountedObject(LayoutConstraintKind Kind);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the reason for these static versions. They just seem to bloat the API.


static bool isClass(LayoutConstraintKind Kind);

static bool isNativeClass(LayoutConstraintKind Kind);

static bool isRefCounted(LayoutConstraintKind Kind);

static bool isNativeRefCounted(LayoutConstraintKind Kind);

/// Uniquing for the LayoutConstraintInfo.
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, Kind, SizeInBits, Alignment);
Expand All @@ -189,6 +221,14 @@ class LayoutConstraintInfo : public llvm::FoldingSetNode {
void *operator new(size_t bytes, const ASTContext &ctx,
AllocationArena arena, unsigned alignment = 8);
void *operator new(size_t Bytes, void *Mem) throw() { return Mem; }

// Representation of the non-parametrized layouts.
static LayoutConstraintInfo UnknownLayoutConstraintInfo;
static LayoutConstraintInfo RefCountedObjectConstraintInfo;
static LayoutConstraintInfo NativeRefCountedObjectConstraintInfo;
static LayoutConstraintInfo ClassConstraintInfo;
static LayoutConstraintInfo NativeClassConstraintInfo;
static LayoutConstraintInfo TrivialConstraintInfo;
};

/// A wrapper class containing a reference to the actual LayoutConstraintInfo
Expand All @@ -204,19 +244,25 @@ class LayoutConstraint {
static LayoutConstraint getLayoutConstraint(LayoutConstraintKind Kind,
ASTContext &C);

static LayoutConstraint getLayoutConstraint(LayoutConstraintKind Kind);

static LayoutConstraint getLayoutConstraint(LayoutConstraintKind Kind,
unsigned SizeInBits,
unsigned Alignment,
ASTContext &C);

static LayoutConstraint getUnknownLayout(ASTContext &C);
static LayoutConstraint getUnknownLayout();

LayoutConstraintInfo *getPointer() const { return Ptr; }

bool isNull() const { return Ptr == 0; }

LayoutConstraintInfo *operator->() const { return Ptr; }

/// Merge these two constraints and return a more specific one
/// or fail if they’re incompatible and return an unknown constraint.
LayoutConstraint merge(LayoutConstraint Other);

explicit operator bool() const { return Ptr != 0; }

void dump() const;
Expand Down
9 changes: 6 additions & 3 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4074,6 +4074,12 @@ LayoutConstraint LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind
unsigned SizeInBits,
unsigned Alignment,
ASTContext &C) {
if (!LayoutConstraintInfo::isKnownSizeTrivial(Kind)) {
assert(SizeInBits == 0);
assert(Alignment == 0);
return getLayoutConstraint(Kind);
}

// Check to see if we've already seen this tuple before.
llvm::FoldingSetNodeID ID;
LayoutConstraintInfo::Profile(ID, Kind, SizeInBits, Alignment);
Expand All @@ -4094,7 +4100,4 @@ LayoutConstraint LayoutConstraint::getLayoutConstraint(LayoutConstraintKind Kind
return LayoutConstraint(New);
}

LayoutConstraint LayoutConstraint::getUnknownLayout(ASTContext &C) {
return getLayoutConstraint(LayoutConstraintKind::UnknownLayout, 0, 0, C);
}

21 changes: 19 additions & 2 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2079,9 +2079,14 @@ bool GenericSignatureBuilder::addLayoutRequirement(
equivClass->layoutConstraints.push_back({PAT, Layout, Source});

// Update the layout in the equivalence class, if we didn't have one already.
// FIXME: Layouts can probably be merged sensibly.
if (!equivClass->layout)
equivClass->layout = Layout;
else {
// Try to merge layout constraints.
auto mergedLayout = equivClass->layout.merge(Layout);
if (mergedLayout->isKnownLayout() && mergedLayout != equivClass->layout)
equivClass->layout = mergedLayout;
}

return false;
}
Expand Down Expand Up @@ -2120,6 +2125,16 @@ bool GenericSignatureBuilder::updateSuperclass(
if (!equivClass->superclass) {
equivClass->superclass = superclass;
updateSuperclassConformances();
// Presence of a superclass constraint implies a _Class layout
// constraint.
auto layoutReqSource = source->viaSuperclass(*this, nullptr);
addLayoutRequirement(T,
LayoutConstraint::getLayoutConstraint(
superclass->getClassOrBoundGenericClass()->isObjC()
? LayoutConstraintKind::Class
: LayoutConstraintKind::NativeClass,
getASTContext()),
layoutReqSource);
return false;
}

Expand Down Expand Up @@ -3459,7 +3474,9 @@ void GenericSignatureBuilder::checkLayoutConstraints(
return constraint.value == equivClass->layout;
},
[&](LayoutConstraint layout) {
if (layout == equivClass->layout)
// If the layout constraints are mergable, i.e. compatible,
// it is a redundancy.
if (layout.merge(equivClass->layout)->isKnownLayout())
return ConstraintRelation::Redundant;

return ConstraintRelation::Conflicting;
Expand Down
Loading