Commit Graph

2768 Commits

Author SHA1 Message Date
Doug Gregor
9875bcfcca Merge pull request #39992 from DougGregor/actor-transport-sil-cleanup 2021-10-31 08:07:41 -07:00
Doug Gregor
3da14e6f65 Refactor and generalize distributed actor transport SIL generation.
Refactor the code that generates SIL to call into the distributed actor
transport to eliminate duplication and better cope with concrete actor
transports. Centralize the knowledge of which actor transport is used
with a given distributed actor type.
2021-10-30 21:49:35 -07:00
Slava Pestov
f38f25a3de AST: Factor out AbstractGenericSignatureRequest into a new buildGenericSignature() function
This is slightly cleaner.
2021-10-30 00:35:59 -04:00
Michael Gottesman
f9122a79b7 [moveOnly] Implement a new _copy function that performs an explicit copy value.
The key thing is that the move checker will not consider the explicit copy value
to be a copy_value that can be rewritten, ensuring that any uses of the result
of the explicit copy_value (consuming or other wise) are not checked.

Similar to the _move operator I recently introduced, this is a transparent
function so we can perform one level of specialization and thus at least be
generic over all concrete types.
2021-10-29 15:37:46 -07:00
eeckstein
d5ae51130d Merge pull request #39902 from eeckstein/performance-annotations
First prototype of Performance Annotations
2021-10-29 07:39:41 +02:00
Michael Gottesman
e5d0f386e4 [moveOnly] Add a new experimental move only checker that checks noImplicitCopy variables.
NOTE: This is only available when the flag -enable-experimental-move-only. There
are no effects when the flag is disabled.

The way that this works is that it takes advantage of the following changes to
SILGen emission:

* When SILGen initializes a let with NoImplicitCopyAttribute, SILGen now emits
a begin_borrow [lexical] + copy + move_only. This is a pattern that we can check
and know that we are processing a move only value. When performing move
checking, we check move_only as a move only value and that it isn't consumed
multiple times.

* The first point works well for emitting all diagnostics except for
initializing an additional let var. To work around that I changed let
initialization to always bind to an owned value to a move of that owned
value. There is no semantic difference since that value is going to be consumed
by the binding operation anyways so we effectively just move the cleanup from
the original value we wanted to bind to the move. We still then actually borrow
the new let value with a begin_borrow [lexical] for the new let value. This
ensures that an initialization of a let value appears to be a consuming use to
the move only value checker while ensuring that the value has a proper
begin_borrow [lexical].

Some notes on functionality:

1. This attribute can only be applied to local 'let'.

2. "print" due to how we call it today with a vararg array is treated as a
   consuming use (unfortunately).

3. I have not added the builtin copy operator yet, but I recently added a _move
   skeleton attribute so one can end the lifetimes of these values early.

4. This supports all types that are not address only types (similar to
   _move). To support full on address only types we need opaque values.

rdar://83957088
2021-10-28 11:32:22 -07:00
nate-chandler
1b3fa26a5c Merge pull request #39883 from nate-chandler/lexical_lifetimes/avoid-incorrect-elimination
[SILOptimizer] Keep lexical lifetime markers.
2021-10-28 10:54:59 -07:00
Erik Eckstein
569a520db2 SILOptimizer: add a mandatory generic-specialization pass.
This pass is only used for functions with performance annotations (@_noLocks, @_noAllocation).
It runs in the mandatory pipeline and specializes all function calls in performance-annotated functions and functions which are called from such functions.
In addition, the pass also does some other related optimizations: devirtualization, constant-folding Builtin.canBeClass, inlining of transparent functions and memory access optimizations.
2021-10-28 18:43:14 +02:00
Erik Eckstein
7c28d7a625 migrate SILInliner to use InstructionDeleter 2021-10-28 18:43:14 +02:00
Erik Eckstein
49351c4759 SILOptimizer: extract the peephole optimization for Builtin.canBeClass into a separate utility. 2021-10-28 18:43:14 +02:00
Erik Eckstein
094494e1ed SILOptimizer: add basic block utilities ReachingReturnBlocks and NonErrorHandlingBlocks
* ReachingReturnBlocks: computes the set of blocks from which a path to the return-block exists (does not include paths to a throw-block)
* NonErrorHandlingBlocks: computes the set of blocks which are not used for error handling, i.e. not (exclusively) reachable from the error-block of a try_apply
2021-10-28 18:43:14 +02:00
Michael Gottesman
60f3d61031 Merge pull request #39943 from gottesmm/pr-65ca66f5402c00e0f0fa0608409ef1c732d1fd2b
[moveOnly] Add a skeleton _move function
2021-10-28 02:23:56 -07:00
Michael Gottesman
114789707c [moveOnly] Implement a semi-generic _move function that can be used on non-generic, non-existential values.
This patch introduces a new stdlib function called _move:

```Swift
  @_alwaysEmitIntoClient
  @_transparent
  @_semantics("lifetimemanagement.move")
  public func _move<T>(_ value: __owned T) -> T {
  #if $ExperimentalMoveOnly
    Builtin.move(value)
  #else
    value
  #endif
  }
```

It is a first attempt at creating a "move" function for Swift, albeit a skleton
one since we do not yet perform the "no use after move" analysis. But this at
leasts gets the skeleton into place so we can built the analysis on top of it
and churn tree in a manageable way. Thus in its current incarnation, all it does
is take in an __owned +1 parameter and returns it after moving it through
Builtin.move.

Given that we want to use an OSSA based analysis for our "no use after move"
analysis and we do not have opaque values yet, we can not supporting moving
generic values since they are address only. This has stymied us in the past from
creating this function. With the implementation in this PR via a bit of
cleverness, we are now able to support this as a generic function over all
concrete types by being a little clever.

The trick is that when we transparent inline _move (to get the builtin), we
perform one level of specialization causing the inlined Builtin.move to be of a
loadable type. If after transparent inlining, we inline builtin "move" into a
context where it is still address only, we emit a diagnostic telling the user
that they applied move to a generic or existential and that this is not yet
supported.

The reason why we are taking this approach is that we wish to use this to
implement a new (as yet unwritten) diagnostic pass that verifies that _move
(even for non-trivial copyable values) ends the lifetime of the value. This will
ensure that one can write the following code to reliably end the lifetime of a
let binding in Swift:

```Swift
  let x = Klass()
  let _ = _move(x)
  // hypotheticalUse(x)
```

Without the diagnostic pass, if one were to write another hypothetical use of x
after the _move, the compiler would copy x to at least hypotheticalUse(x)
meaning the lifetime of x would not end at the _move, =><=.

So to implement this diagnostic pass, we want to use the OSSA infrastructure and
that only works on objects! So how do we square this circle: by taking advantage
of the mandatory SIL optimzier pipeline! Specifically we take advantage of the
following:

1. Mandatory Inlining and Predictable Dead Allocation Elimination run before any
   of the move only diagnostic passes that we run.

2. Mandatory Inlining is able to specialize a callee a single level when it
   inlines code. One can take advantage of this to even at -Onone to
   monomorphosize code.

and then note that _move is such a simple function that predictable dead
allocation elimination is able to without issue eliminate the extra alloc_stack
that appear in the caller after inlining without issue. So we (as the tests
show) get SIL that for concrete types looks exactly like we just had run a
move_value for that specific type as an object since we promote away the
stores/loads in favor of object operations when we eliminate the allocation.

In order to prevent any issue with this being used in a context where multiple
specializations may occur, I made the inliner emit a diagnostic if it inlines
_move into a function that applies it to an address only value. The diagnostic
is emitted at the source location where the function call occurs so it is easy
to find, e.x.:

```
func addressOnlyMove<T>(t: T) -> T {
    _move(t) // expected-error {{move() used on a generic or existential value}}
}

moveonly_builtin_generic_failure.swift:12:5: error: move() used on a generic or existential value
    _move(t)
    ^
```

To eliminate any potential ABI impact, if someone calls _move in a way that
causes it to be used in a context where the transparent inliner will not inline
it, I taught IRGen that Builtin.move is equivalent to a take from src -> dst and
marked _move as always emit into client (AEIC). I also took advantage of the
feature flag I added in the previous commit in order to prevent any cond_fails
from exposing Builtin.move in the stdlib. If one does not pass in the flag
-enable-experimental-move-only then the function just returns the value without
calling Builtin.move, so we are safe.

rdar://83957028
2021-10-27 19:36:49 -07:00
Erik Eckstein
bec687db1b ConstantFolding: remove a wrong peephole optimization for signed "< 0" and ">= 0" comparisons
The wrong optimization was: fold x < 0 into false, if x is known to be a result of an unsigned operation with overflow checks enabled.
It was done under the wrong assumption that the result of an overflow-checked unsigned operation fits into a signed integer and is positive.
This is wrong, because the result of an unsigned operation can be larger than Int.max and therefore, when used in a signed integer operation, be re-interpreted as a negative signed value.

Fixes a miscompile which resulted in a missing abort on arithmetic overflow.

rdar://73596890
2021-10-27 14:20:19 +02:00
Andrew Trick
cce4442cce Merge pull request #39880 from kubamracek/revert-df26a6d7407d42e9646c883489ced31ceb700674
Revert "Merge pull request #39805 from atrick/oou-opt-rauw"
2021-10-22 17:52:56 -07:00
Michael Gottesman
960cbcb147 [SILGenCleanup] Do not remove trivial lexical borrow scopes.
This ensures that while in OSSA, we have in the IR information about the lexical
lifetime of let variables.
2021-10-22 14:36:33 -07:00
Kuba Mracek
8158cdf5e5 Revert "Merge pull request #39805 from atrick/oou-opt-rauw"
This reverts commit df26a6d740, reversing
changes made to f9643fd3a2.
2021-10-22 12:29:10 -07:00
Kavon Farvardin
e54fa6c6db inject actorReady calls for async dist actor ctors
Immediately after the hop_to_executor in an async, distributed
actor init, we need to notify the transport that the actor is ready.

This patch does not yet account for more complex cases. In particular,
we will need a mechanism to prevent multiple calls to actorReady,
which can happen if a loop appears in the init:

distributed actor Dactor {
  var x: Int
  init(tport: ActorTransport, count: Int) async {
    var i = count
    repeat {
      self.x = count
      // hop is injected here
      i -= 1
    } while i > 0
  }
}
2021-10-21 19:41:31 -07:00
Kavon Farvardin
51b769795a decouple the emission of actorReady from SILGen
We need to be able to inject a call to a distributed actor's
transport.actorReady, passing the actor instance to it,
during definite initialization. This means that its dependence
on SILGenFunction must be broken, hence this refactoring as
a SILOptimizer utility.
2021-10-21 19:41:31 -07:00
Kuba (Brecka) Mracek
b413a0f4dd Add Builtin.ifdef_<FLAGNAME> as a facility to peek at -D flag that client code is building with (#39797) 2021-10-21 15:36:47 -07:00
Andrew Trick
463922c386 Allow RAUW to optimize struct_extract from function args 2021-10-18 14:16:40 -07:00
Andrew Trick
698ed8e043 Make Ownership RAUW checks more precise - allows more optimization.
Call findOwnershipReferenceRoot when checking for guaranteed values
from SILFunctionArgument.

TODO: We need to add a component path to a reference root abstraction
to handle references that come from a struct_extract or tuple_extract.
2021-10-18 14:16:39 -07:00
Andrew Trick
36fb073c21 OSSA RAUW prepareUnowned - short-circuit empty uses
Avoid generating useless empty copies and borrow scopes.

Bypass all the use-checking logic when there are no uses to avoid
special cases and bugs.
2021-10-18 09:01:15 -07:00
Andrew Trick
652ff78412 OSSA RAUW helper redesign - split prepareReplacement() vs. perform()
Required to fix SILCombine.

Divide the logic into smaller pieces. This allows passes to check for
replaceability before generating the replacement value.

Preparation for simplifying OSSA utilities into smaller logical
components making them flexibile and allowing improvements to be
staged in.
2021-10-18 09:01:15 -07:00
Andrew Trick
4a85e187ca Eliminate unused and incomplete OSSA logic. 2021-10-18 09:01:15 -07:00
Andrew Trick
8062e408ea Migrate to OwnershipLifetimeExtender API: borrowCopyOverScope etc.
Preparation for rewriting non-trivial terminators and generalizing
support for guaranteed phis.

Add guaranteedUsePoints to the RAUW context. This will replace ALL
existing context book-keeping once the old code is deleted.

Introduce a borrowCopyOverScope entry point to handle extending
lifetime over a BorrowedValue. This simply uses the
BorrowedLifetimeExtender.

Introduce higher-level APIs:
- borrowOverValue to extened over a guaranteedValue
- borrowOverSingleUse to extened over a single guaranteed use

These replace both createPlusZeroBorrow and createPlusOneBorrow.

Update RAUW-ctor, RAUW::handleUnowned, and replaceAddressUses to use
the new API.

Restructure RAUW::canFixUpOwnershipForRAUW. Simply use
findInnerTransitiveGuaranteedUses.

Replace RAUW::handleGuaranteed and rewriteReborrows with
OLE::borrowOverValue.

Use the BorrowedLifetimeExtender utility to handle all situations
correctly.

TODO: createPlusOneBorrow can be completely removed, and a massive
amount of confusing/incomplete code can be deleted in a follow-up
commit.
2021-10-18 09:01:15 -07:00
Nate Chandler
a886c7fd9d [LoopRotate] Use ownership for backedge block.
Previously, all phi arguments added to the backedge block were given
@owned ownership.  That was not correct for arguments that needed to
have @guaranteed ownership.  Here, that is corrected by using the
ownership of the original argument from the header block when adding the
phi argument to the backedge block.
2021-10-15 19:06:28 -07:00
Andrew Trick
850426514a Merge pull request #39761 from atrick/fix-accessopt
Fix AccessEnforcementOpts for OSSA
2021-10-15 00:14:23 -07:00
Nate Chandler
09dd1824a3 [SILInliner] Only lifetime args with ownership.
Previously, after https://github.com/apple/swift/pull/39712, lexical
lifetimes were added for arguments whose parameter convention was
guaranteed.  Those lexical borrow scopes were added regardless of the
ownership of the values which were passed as those arguments.  Here, the
lifetimes are only added for argument values which have ownership.
2021-10-14 19:26:56 -07:00
swift-ci
402bc34455 Merge pull request #39725 from nate-chandler/lexical_lifetimes/disable-destroy-hoisting-with-flag 2021-10-14 16:30:21 -07:00
Andrew Trick
4b592c09d8 Add OSSA utilities for extending lifetimes and borrow scopes
Without introducing any new borrow scopes or owned lifetimes.

Top-level APIs:
- extendOwnedLifetime()
- extendLocalBorrow()

New utilitiy: GuaranteedOwnershipExtension.

This is a simple utility to determine whether new uses can be added to
an existing guaranteed value. It reports the kind of transformation
needed and performs the transformation if requested. If transformation
is needed, it simply calls one of the two top-level APIs.
2021-10-14 13:53:37 -07:00
Andrew Trick
d27d83a8f2 CSE/OSSA avoid endless cloning and reoptimization.
Prevent CSE from introducing useless copies, borrows, and
clones. Otherwise it will endlessly clone and re-cse the same
projections endlessly.

TODO: Most of these cases can be handled GuarateedOwnershipExtension
or extendOwnedLifetime without requiring any copies!
2021-10-13 21:56:46 -07:00
Nate Chandler
23a9a1d4c9 Moved lexical lifetime flag to SILOptions.
Previously, the flag was a LangOptioins.  That didn't make much sense because
this isn't really a user-facing behavior.  More importantly, as a member
of that type type it couldn't be accessed when setting up pass
pipelines.  Here, the flag is moved to SILOptions.
2021-10-13 13:47:44 -07:00
Andrew Trick
bdfcc609eb Add a createBorrowScopeForPhiOperands bailout
Avoid using GuaranteedPhiBorrowFixup on phis that cannot possibly have
any guaranteed operands.
2021-10-13 10:57:16 -07:00
Andrew Trick
14e9a01ef7 BorrowedLifetimeExtender minor cleanup 2021-10-13 10:57:16 -07:00
Andrew Trick
d71e450903 Comment OSSA RAUW createBorrowScopeForPhiOperands 2021-10-13 10:57:16 -07:00
Andrew Trick
58a25017f2 OwnershipLifetimeExtender::createPlusOneCopy comments 2021-10-13 10:57:16 -07:00
Andrew Trick
19c8cf12dc Move hasValidRAUWOwnership & canFixUpOwnershipForRAUW
Move the code that sets up the context above all the code that
depends on that context.

This helps keep the relationship straight between several
sub-utilities and gradually clean them up.
2021-10-13 10:57:15 -07:00
Andrew Trick
4cdcc14885 Prepare OwnershipRAUWHelper support for terminator results.
The 'oldValue' can now be a terminator result instead of a
SingleValueInstruction.
2021-10-13 10:57:15 -07:00
Andrew Trick
55e0523b95 Prepare replaceAllUses[AndErase]() API support for terminators
Setup the API for use with SimplifyCFG first, so the OSSA RAUW utility
can be redesigned around it. The functionality is disabled because it
won't be testable until that's all in place.
2021-10-13 10:57:15 -07:00
Andrew Trick
1f94525478 Remove unused Builders from OwnershipRAUWUtility::handleUnowned 2021-10-13 10:57:15 -07:00
Andrew Trick
ed80028b00 Add an assert to createPlusZeroBorrow
If this doesn't hold, it silently miscompiles.
2021-10-13 10:57:15 -07:00
Andrew Trick
d61732969a Make hasValidRAUWOwnership a static member of OwnershipRAUWHelper
Allow quickly checking for valid OSSA value substitution independent
from information about the value's lifetime or scope. Make it a static
member to allow this to check to be done outside of the RAUW
utility. e.g. from SimplifyCFG.
2021-10-13 10:57:15 -07:00
Andrew Trick
a2b6f7cb3b Fix comment typos 2021-10-13 10:57:15 -07:00
Andrew Trick
ed6f701832 Merge pull request #39663 from atrick/fix-addressuses
Fix OSSA handling of address uses
2021-10-13 10:51:45 -07:00
nate-chandler
4424696010 Merge pull request #39712 from nate-chandler/lexical_lifetimes/only-give-guaranteed-args-lexical-lifetimes-during-inlining
[SILInliner] Only guaranteed args get lexical lifetimes.
2021-10-13 07:11:26 -07:00
Andrew Trick
b4a47b6463 Fix findInnerTransitiveUsesForAddress; add AddressUseKind
findInnerTransitiveUsesForAddress was incorrectly returning true for
pointer escapes.

Introduce enum AddressUseKind { NonEscaping, PointerEscape, Unknown };

Clients need to handle each of these cases differently.
2021-10-12 19:58:11 -07:00
Andrew Trick
a336bcdea9 Fix findTransitiveUses to only record leaf uses.
Recording uses is now optional. This utility is also used simply to
check for PointerEscape. When uses are recorded, they are used to
extend a live range. There could be a large number of transitive uses
that we don't want to pass back to the caller.
2021-10-12 19:58:10 -07:00
Nate Chandler
79f7b4a7eb [SILInliner] Only guaranteed args get lexical lifetimes.
Previously, when inlining, both owned and guaranteed arguments were
wrapped in lexical lifetimes before using them to within inlined
callees.  That is redundant, however, because SILGen add lexical
lifetimes for owned arguments within functions.  Here, the redundancy is
removed by only adding lexical lifetimes for guaranteed arguments that
are passed to inlined callees.
2021-10-12 19:45:00 -07:00
Arnold Schwaighofer
8866a2dcb1 Merge pull request #39656 from aschwaighofer/delay_import_prespecializations
Delay import of prespecialized decls until generic specialization
2021-10-12 12:20:16 -07:00