Skip to content
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

SubtypingDiscoverer: Differentiate non-flow subtyping constraints #6344

Merged
merged 4 commits into from
Feb 27, 2024

Conversation

kripken
Copy link
Member

@kripken kripken commented Feb 24, 2024

When we do a local.set of a value into a local then we have both a subtyping constraint - for
the value to be valid to put in that local - and also a flow of a value, which can then reach
more places. Such flow then interacts with casts in Unsubtyping, since it needs to know
what can flow where in order to know how casts force us to keep subtyping relations.

That regressed in the not-actually-NFC #6323 in which I added the innocuous lines
to add subtyping constraints in ref.eq. It seems fine to require that the arms of a
RefEq must be of type eqref, but Unsubtyping then assuming those arms flowed into
a location of type eqref... which means casts might force us to not optimize some
things.

To fix this, differentiate the rare case of non-flowing subtyping constraints, which is
basically only RefEq. There are perhaps a few more cases (like i31 operations) but they
do not matter in practice for Unsubtyping anyhow; I suggest we land this first to undo
the regression and then at our leisure investigate the other instructions.

@kripken kripken requested a review from tlively February 24, 2024 00:57
@kripken
Copy link
Member Author

kripken commented Feb 24, 2024

Open to other ideas here, btw... it's late on Friday and this is the best I could come up with 😄

edit: e.g. maybe there is a more targeted solution in Unsubtyping? Though I suspect some changes in SubtypingDiscoverer are unavoidable.

@@ -193,6 +193,22 @@ struct Unsubtyping
noteSubtype(sub->type, super->type);
}

void noteNonFlowSubtype(Expression* sub, Type super) {
Copy link
Member

Choose a reason for hiding this comment

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

IIRC, nothing about Unsubtyping is flow-sensitive in any way, so differentiating between non-flow subtyping and flow subtyping seems like the wrong abstraction, or rather a fix for a problem we do not have here.

Is it the case that noteSubtype was simply never passed a basic supertype before that change to SubtypeDiscoverer? If so, I suspect the proper fix is to change isBottom() to isBasic() in the check at the beginning of noteSubtype.

Copy link
Member Author

Choose a reason for hiding this comment

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

Heh, our thinking is identical: I actually considered just that, but sadly it doesn't work: we do need to consider basic types there. Consider if we write a user type to anyref, then that interacts with casts. The cast logic basically needs to know about all the things that might flow into anyref, since it needs to preserve cast differences among them, when we cast back from anyref. That is, unfortunately, where the flow sensitivity comes from.

(And for that reason the new test in this PR must contain casts.)

Copy link
Member Author

Choose a reason for hiding this comment

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

(friendly ping @tlively , there is at least one project that regressed by this that is eager to get a fix)

Copy link
Member

Choose a reason for hiding this comment

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

Oops, sorry for letting this slip.

Copy link
Member

@tlively tlively left a comment

Choose a reason for hiding this comment

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

LGTM, I think this makes sense now.

@kripken kripken merged commit d5157e0 into WebAssembly:main Feb 27, 2024
14 checks passed
@kripken kripken deleted the unsub.eq branch February 27, 2024 21:39
radekdoulik pushed a commit to dotnet/binaryen that referenced this pull request Jul 12, 2024
…bAssembly#6344)

When we do a local.set of a value into a local then we have both a subtyping constraint - for
the value to be valid to put in that local - and also a flow of a value, which can then reach
more places. Such flow then interacts with casts in Unsubtyping, since it needs to know
what can flow where in order to know how casts force us to keep subtyping relations.

That regressed in the not-actually-NFC WebAssembly#6323 in which I added the innocuous lines
to add subtyping constraints in ref.eq. It seems fine to require that the arms of a
RefEq must be of type eqref, but Unsubtyping then assuming those arms flowed into
a location of type eqref... which means casts might force us to not optimize some
things.

To fix this, differentiate the rare case of non-flowing subtyping constraints, which is
basically only RefEq. There are perhaps a few more cases (like i31 operations) but they
do not matter in practice for Unsubtyping anyhow; I suggest we land this first to undo
the regression and then at our leisure investigate the other instructions.
@gkdn gkdn mentioned this pull request Aug 31, 2024
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