Commit Graph

55 Commits

Author SHA1 Message Date
Nate Chandler
fcec328c54 [Test] Ensourced multidefuse-liveness.
Moved the test next to the code it calls.
2023-07-04 11:52:13 -07:00
Nate Chandler
f99637156b [Test] Ensourced multidef-liveness.
Moved the test next to the code it calls.
2023-07-04 11:52:13 -07:00
Nate Chandler
ef02dc2081 [Test] Ensourced ssa-liveness.
Moved the test next to the code it calls.
2023-07-04 11:52:13 -07:00
Nate Chandler
3343ab926d [Test] Ensourced pruned-livenes-boundary...
-with-list-of-last-users-insertion-points.  Moved the test next to the
code it calls.
2023-07-04 11:52:13 -07:00
Andrew Trick
c9eb1aea91 MultiDefPrunedLiveness: add support for arbitrary uses/defs.
This now supports liveness holes within blocks where previously we
expected a phi def.

PrunedLiveness is streamlined for SSA liveness where we expect the
defs and uses to be related in the SSA def-use graph.
MultiDefPrunedLiveness was added on top of SSAPrunedLivenes to handle
extended SSA liveness that occurs with phis, but are still connected
in the def-use graph. Recently MultiDefPrunedLiveness was repurposed
for liveness of addressible storage. This means that we can now have
uses before defs in the same block without a corresponding phi.

Fortunately, handling this case is a straightforward extension of
MultiDefPrunedLiveness that does not complicate or penalize the
streamlined SSA case.
2023-04-04 10:22:32 -07:00
Andrew Trick
d44c7f3b99 [NFC] Move the updateForUse API into PrunedliveRange
PrunedLiveness only knows about the live blocks and uses.

The PrunedLiveRange subclass is now responsible for updating liveness
based on both the defs and uses. This is in preparation for handling
non-SSA liveness when uses occur before the first def.
2023-04-04 10:22:32 -07:00
Andrew Trick
927d526ac9 silence a noasserts warning 2023-04-04 10:22:32 -07:00
Andrew Trick
0c8ecb54bf Revert "MultiDefPrunedLiveness: add support for arbitrary uses/defs." 2023-03-28 17:43:42 -07:00
Andrew Trick
6b77b79ac8 MultiDefPrunedLiveness: add support for arbitrary uses/defs.
This now supports liveness holes within blocks where previously we
expected a phi def.

PrunedLiveness is streamlined for SSA liveness where we expect the
defs and uses to be related in the SSA def-use graph.
MultiDefPrunedLiveness was added on top of SSAPrunedLivenes to handle
extended SSA liveness that occurs with phis, but are still connected
in the def-use graph. Recently MultiDefPrunedLiveness was repurposed
for liveness of addressible storage. This means that we can now have
uses before defs in the same block without a corresponding phi.

Fortunately, handling this case is a straightforward extension of
MultiDefPrunedLiveness that does not complicate or penalize the
streamlined SSA case.
2023-03-24 18:40:31 -07:00
Andrew Trick
44fc97d340 [NFC] Move the updateForUse API into PrunedliveRange
PrunedLiveness only knows about the live blocks and uses.

The PrunedLiveRange subclass is now responsible for updating liveness
based on both the defs and uses. This is in preparation for handling
non-SSA liveness when uses occur before the first def.
2023-03-23 22:05:54 -07:00
Andrew Trick
f30fd127fa silence a noasserts warning 2023-03-23 16:08:36 -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
Michael Gottesman
3b72951148 [sil] Provide FieldSensitivePrunedLiveness with its own implementation of PrunedLiveBlocks called FieldSensitivePrunedLiveBlocks.
This will let the non-field sensitive version use a more performant
implementation internally. This is important since PrunedLiveBlocks is used in
the hot path when working with Ownership SSA, while the field sensitive version
is only used for certain diagnostics.

NOTE: I did not refactor PrunedLiveness to use the faster implementation... this
is just a quick pass over the code to prepare for that change.
2023-02-07 16:26:41 -08:00
Andrew Trick
4224d940ec Add visitInnerAdjacentPhis OSSA helper
This API is the inverse of visitEnclosingDefs when called on a phi.

This replaces the visitAdjacentReborrowsOfPhi algorithm with a small
loop that simply checks all the phis in the current block.

This should all be fairly efficient once SILArgument has a "reborrow"
flag.
2023-02-06 23:11:23 -08:00
Andrew Trick
7990dda02b Cleanup PrunedLiveness interface.
In preparation for adding OwnershipLiveness.

Rename Simple LiveRangeSummary to LiveRangeSummary.

Add initializeDefNode helpers to avoid confusion about the argument
type.

Add defBegin/defEnd iterators in MultiDefPrunedLiveness.
2023-01-24 23:26:40 -08:00
Andrew Trick
7dc9405131 Add a visited set for PrunedLiveness guaranteed value. 2023-01-13 14:16:15 -08:00
Andrew Trick
599b1d1ae4 Handle guaranteed phis conservatively in a few more places. 2023-01-13 08:55:16 -08:00
swift-ci
c547f57b06 Merge pull request #62737 from valeriyvan/PrunedLiveness-null-derefence
Fix NULL pointer dereference
2023-01-12 03:53:22 -08:00
Andrew Trick
208bb76ce3 Fix MultiDefPrunedLiveness; add boundaries for dead end blocks.
Make sure liveness reports a complete boundary even for OSSA lifetimes
that are incomplete. Definition blocks can be on the liveness boundary
in this case.
2023-01-09 23:01:37 -08:00
Andrew Trick
07d4655fb7 Fix an assert in MultiDefPrunedLiveness
Fixes an assert that was meant for a narrow case and accidentally
applied too broadly.

This variation of the liveness utilities wasn't being exercised widely,
and is difficult to test with valid OSSA.
2023-01-09 13:46:58 -08:00
Michael Gottesman
5dceb82a76 [pruned-liveness] Change computeScalarUseBlockLiveness to internally sue the scalar version of markBlockLive 2023-01-07 14:40:04 -08:00
Michael Gottesman
82abf02883 [pruned-liveness] Change the internal machinery of updateForUse to use only scalar logic.
I did this by doing the following:

1. I renamed computeUseBlockLiveness to computeScalarUseBlockLiveness and
changed it to take a specific bit that it is testing for.

2. I changed the logic that already existed in this code path that worked scalar
by scalar to use scalar logic rather than call the broken multi-bit at a time
code path.

3. We took advantage of resultingFoundLiveness now only returning the requested
bits instead of all bits. This ensures that we do not run
computeScalarUseBlockLiveness for those unneeded dead bits resulting in liveness
being inappropriately propagated into predecessors.
2023-01-07 14:28:41 -08:00
Michael Gottesman
72c72968e8 [pruned-liveness] Make it so that PrunedLiveBlocks prints out all bits except just the first bit. 2023-01-07 14:14:59 -08:00
Valeriy Van
ad33e6a7f7 Fix NULL pointer dereference 2022-12-21 22:58:00 +02:00
Meghana Gupta
511739b494 Delete OperandOwnership::GuaranteedForwardingPhi
Use OperandOwnership::GuaranteedForwarding instead.
2022-12-13 12:51:31 -08:00
Michael Gottesman
3f90afb901 [move-addr] Move Field Sensitive Pruned Liveness into its own header/cpp impl. 2022-12-08 10:29:48 -08:00
Meghana Gupta
786eb94853 Support @guaranteed forwarding phis 2022-10-19 19:54:27 -07:00
Meghana Gupta
b1f719709b Rename ForwardingBorrow -> GuaranteedForwarding 2022-10-19 19:54:27 -07:00
Nate Chandler
c2f354eefd [PrunedLiveness] Addressed boundary TODO.
With guaranteed phis, we'll be able to encounter cases where the last
users are BranchInsts which use but don't consume a value.  But even
without them, we can still test the API.
2022-10-17 16:50:04 -07:00
Andrew Trick
6af0b6d818 Use ScopedAddressValue in PrunedLiveness
to handle scoped addresses properly
2022-10-12 12:32:15 -07:00
Andrew Trick
2c700be8eb Add a TODO in PrunedLivenessBoundary::visitInsertionPoints 2022-10-10 09:24:29 -07:00
Andrew Trick
715d3f7c31 Split PrunedLiveness::findBoundariesInBlock into fast paths
This allows dynamic dispatch into the fast paths. It's also easier to
understand the fast paths when written as separate loops.

This way, we can used MultiDefPrunedLiveness to compute ownership
liveness, but still benefit from the fact that the common case (owned
non-phi value) is much simpler and faster to compute.

This approach is necessary because we use stack-based data structures
within the liveness result, so we need to statically instantiate
something that can handle all cases.
2022-10-06 19:02:24 -07:00
Andrew Trick
755bce217d Remove complexity in findBoundariesInBlock
We can remove a ton of complexity by assuming that SSA uses never
occur before a def in the same block. This will hold true as long as
useless phis are only removed after all unreachable code is first
removed. Then we don't have the self-loop problem.

The SILVerifier already checks this invariant and I added an in-depth
comment in SimplifyCFG.
2022-10-04 13:27:48 -07:00
Andrew Trick
6861b318ca Make PrunedLiveness::computeSimple one-level transitive
Computing simple liveness is distinct from computing transitive
liveness. But for safety and consistency, always handle the first
level of liveness transitively. This way, computeSimple can be used on
guaranteed values that need OSSA lifetime fixup.

Simple liveness just means that *inner* borrow and address scopes are
assumed to be complete.

This utility is still only used conservatively because OSSA lifetime
completion is not yet enabled. But, in the future, computeSimple can
be used in the common case.
2022-10-04 13:27:48 -07:00
Andrew Trick
da4f1b9a70 Add InnerBorrowKind and AddressUseKind to PrunedLiveness API
The API for computing simple liveness now returns a
SimpleLiveRangeSummary. Callers need to decide how to handle reborrows
and pointer escapes. If either condition exists then the resulting
liveness does not necessarily encapsulate the definition's ownership.

Fixes some number of latent bugs w.r.t. liveness clients.
2022-10-04 13:27:47 -07:00
Andrew Trick
40e03ef782 Update passes to use SSAPrunedLiveness or MultiDefPrunedLiveness 2022-10-04 13:27:47 -07:00
Andrew Trick
ca503b54b7 Redesign PrunedLiveness APIs, introducing live ranges
First restore the basic PrunedLiveness abstraction to its original
intention. Move code outside of the basic abstraction that polutes the
abstraction and is fundamentally wrong from the perspective of the
liveness abstraction.

Most clients need to reason about live ranges, including the def
points, not just liveness based on use points. Add a PrunedLiveRange
layer of types that understand where the live range is
defined. Knowing where the live range is defined (the kill set) helps
reliably check that arbitrary points are within the boundary. This
way, the client doesn't need to be manage this on its own. We can also
support holes in the live range for non-SSA liveness. This makes it
safe and correct for the way liveness is now being used. This layer
safety handles:

- multiple defs
- instructions that are both uses and defs
- dead values
- unreachable code
- self-loops

So it's no longer the client's responsibility to check these things!

Add SSAPrunedLiveness and MultiDefPrunedLiveness to safely handle each
situation.

Split code that I can't figure out into
DiagnosticPrunedLiveness. Hopefully it will be deleted soon.
2022-10-04 13:27:44 -07:00
Andrew Trick
4b361d5bb6 Merge pull request #61145 from atrick/ossa-nonuse-liveness
Handle OperandOwnerhip::NonUse in PrunedLiveness::computeSSALiveness.
2022-09-16 09:35:08 -07:00
Michael Gottesman
724449d579 [move-only] Add support for trivial move only var/mutating self/inout. 2022-09-15 13:55:03 -07:00
Andrew Trick
e1e59ac621 Handle OperandOwnerhip::NonUse in PrunedLiveness::computeSSALiveness.
Fixes a bug in the simple PrunedLiveness routine for SSA values.

Without this fix, the init_existential_ref instruction below was not
considered a lifetime-ending use because the non-use type dependednt
operand (which is not really an operand at all) would override the
forwarding operand:

  %1 = open_existential_ref %0 : $any P to $@opened("...", any P) Self
  %2 = init_existential_ref %1 : $@opened("...", any P) Self : $@opened("...", any P) Self, $AnyObject

This will be tested by silgen_cleanup_complete_ossa.sil.
2022-09-15 11:13:56 -07:00
Michael Gottesman
0a16cc362a [move-only] Implement an initial version of the move only address checker.
Some notes:

1. I added support for both loadable/address only types.

2. These tests are based off of porting the move only object tests for inout,
vars, mutating self, etc.

3. I did not include already written tests for address only types in this
specific merge since I need to change us to borrow move only var like types.
Without that, we get a lot of spurious error msgs and the burden of writing that
is not worth it. So instead in a forthcoming commit where I fix that issue in
SILGen, I will commit the corresponding address only tests for this work.

4. I did not include support for trivial types in this. I am going to do
object/address for that at the same time.
2022-09-11 18:57:32 -07:00
Michael Gottesman
7c452ca400 [pruned-liveness] Implement FieldSensitiveAddressPrunedLiveness.
This is the same algorithm as pruned liveness but assumes that one is tracking
liveness from an address and uses the same scheme as DI to track liveness as a
bit vector.
2022-08-30 17:25:55 -07:00
Michael Gottesman
e51e17fa5e [pruned-liveness] Change the internal bit-vector to use 2 bits to represent its state instead of 1 + missing value in DenseMap.
The reason why I am doing this is that in order to be able to use
PrunedLivenessBlocks with multiple elements, we can no longer rely on dead being
represented by a block not having any state, since a dead bit could have a
neighboring live bit.

That being said, the only place that this is used now is the current
PrunedLiveness implementation which only stores a single bit... but that still
at least exercises the code and lets us know that it works.
2022-08-22 13:26:34 -07:00
Michael Gottesman
04144d8214 [pruned-liveness] Change PrunedLiveBlocks so that it can propagate multiple bits of liveness rather than just one.
This is useful for making a form of PrunedLiveness that is sensitive to address
fields. I wired up the current PrunedLiveness to just use PrunedLiveBlocks with
num bits set to 1.
2022-08-22 12:11:18 -07:00
Meghana Gupta
742052a063 Update PrunedLiveness
- To detect instructions occuring before definition
- To handle reborrows
2022-06-30 10:31:20 -07:00
Josh Soref
d767912be2 Spelling sil (#42471)
* spelling: accessible

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: accessories

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: allocated

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: amortizes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: are

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: arguments

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: cacheable

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: check

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: clazz

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: compatible

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: compilation

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: completely

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: construct

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: conversion

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: declarations

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: derivation

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: deserialization

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: destroyed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: determined

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: different

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: doesn't

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: equality

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: equivalent

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: formation

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: forwards

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: global

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: guaranteed

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: have

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: identify

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: inaccessible

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: indeterminate

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: indices

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: inefficient

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: inheritance

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: instantaneous

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: instruction

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: intentionally

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: interior

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: intrinsic

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: introducing

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: irrelevant

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: message

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: multi

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: necessarily

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: object

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: one

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: optimization

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: otherwise

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: overridden

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: parameter

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: pattern

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: pipeline

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: possibility

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: postdominance

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: providing

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: reached

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: recognized

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: refrigerator

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: remaining

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: resilient

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: retrieve

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: scavenge

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: scheduled

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: separately

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: serializable

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: signature

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: simplicity

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: specifically

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: substituted

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: substitution

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: subtypes

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: supplement

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: syntax

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: the

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: there

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: these

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: this

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: though

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: through

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: transitively

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: transpose

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: trivial

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: value

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: verification

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: visibility

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: weird

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

* spelling: whole

Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>

Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
2022-04-22 15:11:09 -07:00
Andrew Trick
218f33e216 Add a FIXME to remove PrunedLiveness::nonLifetimeEndingUsesInLiveOut
Looks like it was added as a bootstrapping hack but doesn't belong
here and won't work in general.
2022-02-16 12:23:01 -08:00
Nate Chandler
2c0a35aa54 [PrunedLiveness] Added areUsesOutsideBoundary. 2022-02-02 09:58:25 -08:00
Andrew Trick
febde3da2f SemanticARCOpts fix - remove deadEndBlocks checks
SemanticARCOptVisitor::performGuaranteedCopyValueOptimization was
converting this SIL

    %borrow = begin_borrow %copiedValue
    %copy = copy_value %borrow
    %borrowCopy = begin_borrow %copy
    end_borrow %borrow
    end_borrow %borrowCopy
    destroy_value %copy
    // something something
    unreachable

into

    %borrow = begin_borrow %copiedValue
    %innerBorrow = begin_borrow %borrow
    end_borrow %borrow
    end_borrow %innerBorrow
    // something something
    unreachable

Dead-end blocks are simply irrelevant for this
optimization. Unfortunately, there were multiple layers of attempted
workarounds that were hiding the real problem, except in rare cases.

Thanks Nate Chandler for reducing the test.
2021-12-09 20:23:17 -08:00
Michael Gottesman
4aa4ac3027 [moveOnly] Add checker that validates that if a let/param copyable value has _move applied to it, the let doesn't have any later uses.
This is just an initial prototype for people to play with. It is as always
behind the -enable-experimental-move-only flag.

NOTE: In this PR I implemented this only for 'local let' like things (local
lets/params). I did not implement in this PR support for local var and haven't
done anything with class ivars or globals.

rdar://83957028
2021-11-04 17:13:29 -07:00