Commit Graph

180 Commits

Author SHA1 Message Date
swift-ci
121b372275 Merge pull request #65892 from gottesmm/pr-14860f6cced1de4e2a6c4ebcf07577c0d56525b8
[move-only] Eliminate dead field.
2023-05-12 15:36:25 -07:00
Michael Gottesman
d252902414 [move-only] Eliminate dead field.
Originally this was a method to determine if we had emitted a diagnostic when
running our gather visitor. It was pretty footgunny since one could easily
forget to set it. Instead of doing that, we now maintain a counter in the
diagnostic emitter that counts how many diagnostics we have emitted and use that
to determine if during the walk if we emitted any additional diagnostics.
2023-05-12 12:49:20 -07:00
Michael Gottesman
a4fcdd893e [move-only] Fix a thinko where we are treating inout convention as a consuming use instead of liveness use.
rdar://109217216
2023-05-11 10:56:42 -07:00
Michael Gottesman
7f0ef3daf7 [move-only] When assigning a var that escapes into a closure into another local, emit the correct error message.
With some of the changes that I have made, we began to emit a mark_must_check
[no_copy] on a copy_addr here. This change teaches the move address checker how
to recognize that in this case if we have a project_box it is actually b/c we
have something captured by an escaping closure.
2023-05-04 13:07:17 -07:00
Michael Gottesman
be7667b6e5 [move-only] Teach the move checker how to correctly check an address only type used by escaping closures.
When we have a loadable type, SILGen always eagerly loads the value, so the move
checker handled checking those cases by just looking for loads and emitting the
error based off of a load. Of course for address only types, the codegen looks
slightly different (we consume the value directly rather than load it). So this
change just teaches the checker how to do that.

rdar://105106470
2023-05-02 16:30:33 -07:00
Michael Gottesman
d10fdf79a5 [move-only] Do not treat accessing copyable fields of a moveonly address only type as consuming the address only type.
rdar://105106470
2023-05-02 16:30:29 -07:00
Nate Chandler
868dfd8366 [SILOptimizer] Use BitfieldRef, not invalidate.
`SSAPrunedLiveness::invalidate` is used as though it reset the state of
the instance it is called on.  Clients then reuse the instance with the
expectation that it has been reset.  But since it has not been reset,
this results in unexpected liveness results.

rdar://108627366
2023-04-27 16:16:13 -07:00
Michael Gottesman
c577055100 [move-only] Instead of using AccessUseVisitor to visit addresses use TransitiveAddressVisitor.
This makes it so that the move address checker is not dependent on starting the
traversal at a base object. I also included verifier checks that the API can
visit all address uses for:

1. project_box.
2. alloc_stack.
3. ref_element_addr.
4. ref_tail_addr.
5. global_addr_inst.

this is because this visitor is now apart of the SIL API definition as being
able to enumerate /all/ addresses derived from a specific chosen address value.

This is a refactoring NFCI change.

rdar://108510644
2023-04-25 10:51:03 -07:00
Michael Gottesman
811824019e [move-only] Change the destructure through deinit error to lookup the deinit at the AST level rather than the SIL level.
I also added a note telling the user where the deinit is.

rdar://101651138
2023-04-13 12:49:28 -07:00
Michael Gottesman
76e93828ef [move-only] Make it an error if we attempt to destructure/partially invalidate through a field with a deinit.
If one has a type with a deinit, if one were to partially invalidate the value,
the checker will clean up the remaining parts of the value but not the actual
underlying value. This then would cause the deinit of the actual type to be
called.

rdar://101651138
2023-04-12 15:18:56 -07:00
Joe Groff
8e21bfcc47 MoveOnlyAddressChecker: Confine analysis to current formal access.
Code can only locally interact with a mutable memory location within a
formal access, and is only responsible for maintaining its invariants
during that access, so the move-only address checker does not need to,
and should not, observe operations that occur outside of the access
marked with the `mark_must_check` instruction. And for immutable
memory locations, although there are no explicit formal accesses, that's
because every access must be read-only, so although individual
accesses are not delimited, they are all compatible as far as
move-only checking is concerned. So we can back out the changes to SILGen
to re-project a memory location from its origin on every access, a
change which breaks invariants assumed by other SIL passes.
2023-04-02 16:33:57 -07:00
Michael Gottesman
43d8ab24f4 [move-only] Add a new type of mark_must_check initable_but_not_consumable.
This is used to teach the checker that the thing being checked is supposed to be
uninitialized at the mark_must_check point so that we don't put a destroy_addr
there.

The way this is implemented is that we always initially add
assignable_but_not_consumable but in DI once we discover that the assign we are
guarding is an init, we convert the assignable to its initable variant.

rdar://106525988
2023-03-31 17:32:58 -07:00
Michael Gottesman
1957f57a92 [move-only] Handle terminator users like yield when converting borrow -> destructure.
rdar://106164128
2023-03-28 16:01:01 -07:00
Andrew Trick
cbe856e53a Cleanup PrunedLiveBlocks
Use BasicBlockBitfield to record per-block liveness state. This has
been the intention since BasicBlockBitfield was first introduced.

Remove the per-field bitfield from PrunedLiveBlocks. This
(re)specializes the data structure for scalar liveness and drastically
simplifies the implementation.

This utility is fundamental to all ownership utilities. It will be on
the critical path in many areas of the compiler, including at
-Onone. It needs to be minimal and as easy as possible for compiler
engineers to understand, investigate, and debug.

This is in preparation for fixing bugs related to multi-def liveness
as used by the move checker.
2023-03-22 02:36:57 -07:00
Andrew Trick
ae64ff5cb0 Rename PrunedLiveness.clear() to invalidate()
Because SILBitfield cannot be cleared.
2023-03-22 01:36:48 -07:00
Andrew Trick
15796e3ff9 PrunedLiveness: add a SILFunction argument
So that liveness can migrate to using a SILBitfield.
2023-03-22 01:36:48 -07:00
Michael Gottesman
bbd2ad4de9 [move-only] Wire up proper debug info for addresses.
I included here SIL tests and in a separate PR against lldb included lldb tests
that validate as we step that the values are validated/invalidated as
appropriate.

rdar://106767457
2023-03-19 16:37:08 -07:00
Michael Gottesman
3de646e7c4 [move-only] Change global_addr assignable_but_not_consumable accesses such that they are initialized at end of lifetime.
I also added an interpreter test that validates that ref_element_addr works as
expected (I fixed that in an earlier commit, but did not add an interpreter
test).

rdar://106724277
2023-03-16 12:28:59 -07:00
Michael Gottesman
b3bbaec709 Merge pull request #64366 from gottesmm/pr-63fcd3307c126048533239ab77552bb5acdc728c
[move-only] Treat mark_must_check assignable_but_not_consumable as ending initialized
2023-03-14 17:12:11 -07:00
Michael Gottesman
02a12d4142 [move-only] Make sure to treat ref_element_addr mutable address accesses similar to inout.
I also slightly changed the codegen around where we insert the mark_must_check.
Specifically, before we would emit the mark_must_check directly on the
ref_element_addr and then insert the access. This had the unfortunate effect
that we would hoist any destroy_addr that were actually needed out of the access
scope. Rather than do that, I now insert the mark_must_check on the access
itself. This results in the destroy_addr being within the scope (like the
mark_must_check itself).

rdar://105910066
2023-03-14 14:03:20 -07:00
Michael Gottesman
8f9772dcf1 [move-only] Make sure to treat (mark_must_check (begin_access (project_box (@capture box arg)))) like an inout term user requiring situation.
We already did this for the situation without the begin_access. In truth, using
the terminator is a bit too wide, but it works for these sorts of arguments that
use assignable_but_not_consumable so for expediency (and since we are just
walking blocks), I just decided to do something quick.

rdar://106208343
2023-03-14 14:03:20 -07:00
Michael Gottesman
156523e598 [move-only] Update the address checker description comment given changes to the algorithm. 2023-03-12 14:55:19 -07:00
Michael Gottesman
c3787df2a9 [move-only] Remove misguided handling of inout.
I think this was just an incorrect fix. The actual issue is that the memory
lifetime verifier views debug_value as requiring a live address... but at the
same time, we do not want to emit diagnostics for a debug_value... we want to do
it for other things. So my solution is to add debug_value to the final liveness
computation, but not use it earlier when we use said liveness to compute
diagnostics.

rdar://106442224
2023-03-08 12:18:10 -08:00
Michael Gottesman
f5acc07bbc [move-only] Fix crash due to an earlier change I made to move end_borrow out of addressUseChecker and into the liveness checker.
This just makes sure that we won't crash on it and emit a proper message. I
think we should improve the message, but this at least gives a proper error.

rdar://106340382
2023-03-06 18:13:00 -08:00
Kavon Farvardin
6e5b49a410 no_consume_or_assign ref_element_addr should not have any destroys
This fixes an issue when doing move-checking on a read accessor,
where the field is only borrowed. After the MoveOnlyAddressChecker
ran on it, it'd inject a destroy that didn't get "claimed":

```
  %2 = ref_element_addr %0 : $ListOfFiles, #ListOfFiles.file
  %3 = mark_must_check [no_consume_or_assign] %2 : $*File
  %4 = begin_access [read] [dynamic] %3 : $*File
  %5 = load_borrow %4 : $*File
  yield %5 : $File, resume bb1, unwind bb2

bb1:
  end_borrow %5 : $File
  end_access %4 : $*File
  destroy_addr %2 : $*File // BAD
  %9 = tuple ()
  return %9 : $()
```

The approach of this fix is to recognize that at the point we're
injecting destroys, we would have emitted diagnostics and stopped
already if there were any consuming uses that we need to clean-up
after, since we're in `no_consume_or_assign` checking mode here
when just reading the field.
2023-03-02 15:14:24 -08:00
Michael Gottesman
1dd896ded9 [move-only] Implement escaping closure semantics.
NOTE: A few of the test patterns need to be made better, but this patch series
is large enough, I want to get it into tree and iterate.
2023-02-20 11:04:21 -08:00
Michael Gottesman
50af8fd493 [move-only] Box owned arguments like let parameters. 2023-02-20 11:04:21 -08:00
Michael Gottesman
a571357cce [move-only] Change noncopyable lets to be emitted as boxes like vars.
Some notes:

1. This ensures that if we capture them, we just capture the box by reference.

2. We are still using the old incorrect semantics for captures. I am doing this
   so I can bring this up in separate easy to understand patches all of which
   pass all of the moveonly tests.

3. Most of the test edits are due to small differences in error messages in
   between the object and address checker.

4. I had to add a little support to the move only address checker for a small
   pattern that doesn't occur with vars but do es occur for lets when we codegen
   like this, specifically around enums. The pattern is we perform a load_borrow
   and then copy_value and then use the result of the copy_value. Rather than fight
   SILGen pattern I introduced a small canonicalization into the address checker which
   transforms that pattern into a load [copy] + begin_borrow to restore the codegen
   to a pattern the checker expects.

5. I left noimplicitcopy alone for now. But we should come back around and fix
   it in a similar way. I just did not have time to do so.
2023-02-20 11:04:21 -08:00
Michael Gottesman
f4e1b2a8f2 [move-only] Update SILGen/MoveCheckers so that vars are emitted in eagerly projected box form.
This is the first slice of bringing up escaping closure support. The support is
based around introducing a new type of SILGen VarLoc: a VarLoc with a box and
without a value. Because the VarLoc only has a box, we have to in SILGen always
eagerly reproject out the address from the box. The reason why I am doing this
is that it makes it easy for the move checker to distinguish in between
different accesses to the box that we want to check separately. As such every
time that we open the box, we insert a mark_must_check
[assignable_but_not_consumable] on that project. If allocbox_to_stack manages to
determine that the box can be stack allocated, we eliminate all of the
mark_must_check and place a new mark_must_check [consumable_and_assignable] on
the alloc_stack.  The end result is that we get the old model that we had before
and also can support escaping closures.
2023-02-20 11:04:21 -08:00
Michael Gottesman
6c922af8aa [move-only] Combine the address/object checker in the same pass so that we only run cleanups once.
Otherwise, sometimes when the object checker emits a diagnostic and cleans up
the IR, some of the cleaned up copies are copies that should have been handled
by the address checker. The end result is that the address checker does not emit
diagnostics for that IR. I found this problem was exascerbated when writing code
for escaping closures.

This commit also cleans up the passes in preparation for at a future time moving
some of the transformations into the utils folder.
2023-02-19 13:55:22 -08:00