Skip to content

Fix speculative devirtualization to correctly use casted value [5.2] #29004

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

Conversation

slavapestov
Copy link
Contributor

@slavapestov slavapestov commented Jan 4, 2020

We used to emit this:

  checked_cast_br [exact] %0 : $Foo to $Bar, bb1, bb2

bb1(%1 : $Bar): // NOTE: %1 was not used anywhere
  %2 = unchecked_ref_cast %0 : $Foo to $Bar
  apply ...(..., %2)
  br ...

bb2:
  ...

This is not ownership SIL-safe, because we're re-using the original
operand, which will have already been consumed at that point.

The more immediate problem here is that this is actually not safe
when combined with other optimizations. Suppose that after the
speculative devirtualization, our function is inlined into another
function where the operand was an upcast. Now we have this code:

  %0 = upcast ...
  checked_cast_br [exact] %0 : $Foo to $Bar, bb1, bb2

bb1(%1 : $Bar):
  apply ...(..., %1) // NOTE: we're using the BB argument here
  br ...

bb2:
  ...

The SILCombiner will simplify the unchecked_ref_cast of the upcast
into an unchecked_ref_cast of the upcast's original operand. At
this point, we have an unchecked_ref_cast between two unrelated
class types. While this means the block bb1 is unreachable, we
might perform further optimizations on it before we run the cast
optimizer and delete it altogether.

In particular, the devirtualizer follows chains of reference cast
instructions, and it will get very confused if it finds this invalid
cast between unrelated types.

Fixes rdar://problem/57712094, https://bugs.swift.org/browse/SR-11916.

…d value

We used to emit this:

  checked_cast_br [exact] %0 : $Foo to $Bar, bb1, bb2

bb1(%1 : $Bar):
  %2 = unchecked_ref_cast %0 : $Foo to %1 : $Bar
  apply ...(..., %2)
  br ...

bb2:
  ...

This is not ownership SIL-safe, because we're re-using the original
operand, which will have already been consumed at that point.

The more immediate problem here is that this is actually not safe
when combined with other optimizations. Suppose that after the
speculative devirtualization, our function is inlined into another
function where the operand was an upcast. Now we have this code:

  %0 = upcast ...
  checked_cast_br [exact] %0 : $Foo to $Bar, bb1, bb2

bb1(%1 : $Bar):
  %2 = unchecked_ref_cast %0 : $Foo to %1 : $Bar
  apply ...(..., %2)
  br ...

bb2:
  ...

The SILCombiner will simplify the unchecked_ref_cast of the upcast
into an unchecked_ref_cast of the upcast's original operand. At
this point, we have an unchecked_ref_cast between two unrelated
class types. While this means the block bb1 is unreachable, we
might perform further optimizations on it before we run the cast
optimizer and delete it altogether.

In particular, the devirtualizer follows chains of reference cast
instructions, and it will get very confused if it finds this invalid
cast between unrelated types.

Fixes <rdar://problem/57712094>, <https://bugs.swift.org/browse/SR-11916>.
@slavapestov slavapestov requested a review from a team as a code owner January 4, 2020 01:26
@slavapestov
Copy link
Contributor Author

@swift-ci Please test

@slavapestov
Copy link
Contributor Author

@DougGregor do you mind approving this once @gottesmm reviews the master branch PR? #29003

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