Skip to content

A couple of SIL fixes #34267

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 3 commits into from
Oct 11, 2020
Merged

Conversation

slavapestov
Copy link
Contributor

@slavapestov slavapestov commented Oct 11, 2020

The ownership verifier got confused by code where a stored property of a class was initialized in-place with an enum value, or was the destination of a cast, erroneously flagging an ownership violation:

  %s = begin_borrow ...
  %e = ref_element_addr %s
  %d = init_enum_data_addr %e // or inject_enum_addr, unconditional_checked_cast_addr

DI got confused by code where more than one component of tuple value was initialized in-place via out parameters of an apply instruction, erroneously diagnosing that all but the first tuple component were uninitialized:

  %t0 = tuple_element_addr %s, 0
  %t1 = tuple_element_addr %s, 1
  %f = function_ref ...
  apply %f(%t0, %t1)

I guess neither code pattern is generated anywhere in the ownership SIL pipeline today, but I imagine it will come up once we more aggressively eliminate copy_addrs before lowering ownership. Also, a change that I'm working on refactors some SILGen code to fix a bug, and the refactoring makes use of in-place initialization, which now generates the above code patterns instead of initializing a temporary and then performing a copy_addr from the temporary.

Finally, DI had some code to 'scalarize' certain tuple operations. After fixing the dataflow analysis to cope with instructions that have multiple non-load uses (such as an apply that initializes both components of a tuple), it appears that we no longer need this step at all.

…rojections

My upcoming SILGen change introduces more stores directly into
the result of a ref_element_addr or struct_element_addr in some
cases. Make sure we handle the failing combinations flagged by
the ownership verifier.
DI had trouble with this pattern:

  %s = struct_element_addr ...
  %t0 = tuple_element_addr %s, 0
  %t1 = tuple_element_addr %s, 1
  %f = function_ref ...
  apply %f(%t0, %t1)

This is because the NonLoadUses map only stored a single use of a
tuple element per instruction, preventing instructions such as
'apply' from being able to use multiple tuple elements.

In other cases where this comes up, such as with 'assign' and
'copy_addr', DI scalarizes the tuple operation by projecting
each component, however clearly this can't be easily done with
an 'apply'.

Instead, we can get DI out of the business of scalarization, at
least for instructions which are known to perform an unconditional
initialization.

We do this by changing the NonLoadUses map to store a vector of
DIMemoryUse IDs instead of a single value.
All the tests seem to pass without it now.
@slavapestov slavapestov requested a review from gottesmm October 11, 2020 03:06
@slavapestov
Copy link
Contributor Author

@swift-ci Please smoke test

@slavapestov
Copy link
Contributor Author

@swift-ci Please test source compatibility

@slavapestov
Copy link
Contributor Author

@swift-ci Please benchmark

@swift-ci
Copy link
Contributor

Performance: -O

Code size: -O

Performance: -Osize

Code size: -Osize

Performance: -Onone

Improvement OLD NEW DELTA RATIO
StringToDataMedium 4650 4300 -7.5% 1.08x (?)

Code size: -swiftlibs

How to read the data The tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.

If you see any unexpected regressions, you should consider fixing the
regressions before you merge the PR.

Noise: Sometimes the performance results (not code size!) contain false
alarms. Unexpected regressions which are marked with '(?)' are probably noise.
If you see regressions which you cannot explain you can try to run the
benchmarks again. If regressions still show up, please consult with the
performance team (@eeckstein).

Hardware Overview
  Model Name: Mac mini
  Model Identifier: Macmini8,1
  Processor Name: 6-Core Intel Core i7
  Processor Speed: 3.2 GHz
  Number of Processors: 1
  Total Number of Cores: 6
  L2 Cache (per Core): 256 KB
  L3 Cache: 12 MB
  Memory: 64 GB

@slavapestov slavapestov merged commit adbcd6a into swiftlang:main Oct 11, 2020
isa<InitExistentialAddrInst>(user) ||
isa<InitEnumDataAddrInst>(user) || isa<BeginAccessInst>(user) ||
isa<TailAddrInst>(user) || isa<IndexAddrInst>(user) ||
isa<UnconditionalCheckedCastAddrInst>(user)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

@slavapestov This is incorrect. UnconditionalCheckedCastAddrInst does not have any results. Instead, you need to select its uses directly. Can you add an error test for unconditional_checked_cast_addr as well just to show via a test that we are correct here?

%2 = alloc_box $<τ_0_0> { var S<τ_0_0> } <T>, var, name "self"
%3 = mark_uninitialized [rootself] %2 : $<τ_0_0> { var S<τ_0_0> } <T>
%4 = project_box %3 : $<τ_0_0> { var S<τ_0_0> } <T>, 0
%5 = struct_element_addr %4 : $*S<T>, #S.x
Copy link
Contributor

Choose a reason for hiding this comment

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

@slavapestov This has far fewer tests than the old version that was deleted above. Are you sure we didn't lose any code coverage?

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.

3 participants