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

Conversation

swiftix
Copy link
Contributor

@swiftix swiftix commented Mar 21, 2017

This PR addresses TODOs from #8241.

  • It supports merging for layout constraints, e.g., if both a _Trivial constraint and a _Trivial(64) constraint appear on a type parameter, we keep only _Trivial(64) as a more specific layout constraint. We do a similar thing for ref-counted/native-ref-counted. The overall idea is to keep the more specific of two compatible layout constraints.
  • The presence of a superclass constraint implies a layout constraint, e.g., a superclass constraint implies _Class or _NativeClass layout constraint.

@swiftix
Copy link
Contributor Author

swiftix commented Mar 21, 2017

@swift-ci please smoke test

@swiftix
Copy link
Contributor Author

swiftix commented Mar 21, 2017

@DougGregor Please have a look.

case LayoutConstraintKind::UnknownLayout:
return LayoutConstraint(
&LayoutConstraintInfo::UnknownLayoutConstraintInfo);
default:
Copy link
Member

Choose a reason for hiding this comment

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

We don't need the default, right? It'll end up suppressing warnings that we'd rather see when the switch isn't covering all of the cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@@ -106,6 +110,24 @@ bool LayoutConstraintInfo::isNativeRefCountedObject(LayoutConstraintKind Kind) {
return Kind == LayoutConstraintKind::NativeRefCountedObject;
}

bool LayoutConstraintInfo::isClass(LayoutConstraintKind Kind) {
return Kind == LayoutConstraintKind::Class;
}
Copy link
Member

Choose a reason for hiding this comment

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

Should this return true when kind == LayoutConstraintKind::NativeClass? It "is" a class constraint, after all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For this I introduced isAnyClass. This predicate is intended to be used to check the exact kind.

}

if ((*this)->isClass() && Other->isNativeClass()) {
// Prefer a more concrete _NativeClass conttraint.
Copy link
Member

Choose a reason for hiding this comment

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

Missing a return Other; here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops. I forgot it while copy&pasting the code.


if (Other->isClass() && (*this)->isNativeClass()) {
// Prefer a more concrete _NativeClass conttraint.
}
Copy link
Member

Choose a reason for hiding this comment

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

Missing a return *this here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same here.

// Prefer a more concrete _NativeClass conttraint.
}

return LayoutConstraint::getUnknownLayout();
Copy link
Member

Choose a reason for hiding this comment

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

Might it be better to have a 2-D table to describe the results? It's pretty hard to make sure that this long sequence of if statements does the right thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@DougGregor Please have a look at the update that I pushed. It uses a 2-D table, but I'm not quite happy with it. The initialization of the table looked pretty ugly. I had to use macros to shorten it. And I'm still not quite convinced it is really easier. WDYT?


bool LayoutConstraintInfo::isRefCounted(LayoutConstraintKind Kind) {
return Kind == LayoutConstraintKind::RefCountedObject ||
Kind == LayoutConstraintKind::Class;
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this also check for Kind == LayoutConstraintKind::NativeRefCountedObject and Kind == LayoutConstraintKind::NativeClass?

@@ -100,6 +102,7 @@ class C2 : C, P4 { }
// CHECK: superclassConformance3
// CHECK: Requirements:
// CHECK-NEXT: τ_0_0 : C2 [τ_0_0: Explicit @ {{.*}}:46]
// CHECK-NEXT: τ_0_0 : _NativeClass [τ_0_0: Explicit @ {{.*}}:46 -> Superclass]
Copy link
Member

Choose a reason for hiding this comment

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

Yay.

if (!initializedMergeTable) {
// initialize the merge table once.
initializedMergeTable = true;
MERGE_TO(TrivialOfAtMostSize, Trivial, TrivialOfAtMostSize);
Copy link
Member

Choose a reason for hiding this comment

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

You should be able to use initializer list nesting { { ... }, { ... }, ... } to avoid the imperative initialization and initializedMergeTable bit. It'll also make sure that cases never get skipped, e.g., the missing merge(TrivialOfExactSize, TrivialOfExactSize) case.

return LayoutConstraint::getUnknownLayout();

if ((*this)->getKind() == mergeKind)
return *this;
Copy link
Member

Choose a reason for hiding this comment

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

When the result is one of the sized cases (TrivialOfExactSize or TrivialOfAtMostSize), you'll need to do some checking of the size to determine the proper result. The lookup table doesn't always suffice in these cases... for example, the merge(TrivialOfExactSize, TrivialOfExactSize) case might produce TrivialOfExactSize (if the sizes are the same) and might produce TrivialOfAtMostSize or UnknownLayout (if the sizes are different; we can choose which semantics we prefer).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@@ -170,6 +196,18 @@ 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.

return isNativeClass(Kind);
}

bool isAnyClass() const {
Copy link
Member

Choose a reason for hiding this comment

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

I still find it confusing that we have isClass() and isAnyClass(). If someone wants the isClass() behavior, they can just check the kind exactly. Are you opposed to giving isClass() the behavior that isAnyClass() has (i.e., so isClass() answers the question "is it some kind of class?") and removing isAnyClass() entirely?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

return isAnyClass(Kind);
}

bool isRefCounted() const {
Copy link
Member

Choose a reason for hiding this comment

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

These behavior the way I'd expect: isRefCounted() is true for any layout kind that ensures reference-counting.

@swiftix
Copy link
Contributor Author

swiftix commented Mar 22, 2017

@DougGregor I pushed the updated version. This one initializes all entries in the merge table. Does it look more reliable?

// If we got here, it means that the Self == Other check above has failed.
// And that could only happen if either the kinds are different or
// size/alignment parameters are different.
return LayoutConstraint::getUnknownLayout();
Copy link
Member

Choose a reason for hiding this comment

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

Okay, it probably doesn't matter, but one could merge exact-size(N) and at-most-size(N) into exact-size(N).

swiftix added 2 commits March 22, 2017 16:37
- Add support for _Class and _NativeClass layout constraints, which are supposed to represent T: Superclass and P: class constraints in the future.
- Use the re-factoring to also reduce the number of dynamic allocations when creating layout constraints. Simple non-parametrized layout constraints are now represented as statically allocated singletons (static members of LayoutConstraintInfo).
This PR addresses TODOs from swiftlang#8241.

- It supports merging for layout constraints, e.g., if both a _Trivial constraint and a _Trivial(64) constraint appear on a type parameter, we keep only _Trivial(64) as a more specific layout constraint. We do a similar thing for ref-counted/native-ref-counted. The overall idea is to keep the more specific of two compatible layout constraints.
- The presence of a superclass constraint implies a layout constraint, e.g., a superclass constraint implies _Class or _NativeClass
@swiftix swiftix force-pushed the wip-gsb-layout-constrains-fixes branch from 80d2ac7 to e1403c6 Compare March 22, 2017 23:50
@swiftix
Copy link
Contributor Author

swiftix commented Mar 22, 2017

@swift-ci please smoke test

@swiftix swiftix merged commit e3bc23c into swiftlang:master Mar 23, 2017
@DougGregor
Copy link
Member

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants