Commit Graph

2601 Commits

Author SHA1 Message Date
Andrew Trick
280761f0d1 [move-only] Fix SILOptimizer code motion to preserve value deinits
Multiple code motion and ARC related passes were removing struct/enum
deinits.

Passes fixed include:
- SILCombine
- EarlyCodeMotion
- ReleaseHoisting
- *many* passes that rely on ARC analysis (RCIndentity)
2023-06-06 09:17:53 -07:00
Andrew Trick
f7d30d4f8b [move-only] Fix SILOptimizer expansion to preserve deinits.
Many basic SIL passes were silently deleting the struct deinit:
- SROA
- Mem2Reg
- RLE
- DSE
- FunctionSignatureOpts
- LowerAggregates

Fixes rdar://109849028 ([move-only] LowerAggregateInstrs eliminates struct deinitialization)
2023-06-06 09:17:53 -07:00
Andrew Trick
62b0899500 [move-only] Disable move-only devirtualization.
It is not needed for correctness and hides most of the deinit related
optimizer bugs.
2023-06-06 09:17:53 -07:00
Andrew Trick
0bbd92a446 [move-only] Rename MoveOnlyDeinitInsertion
to MoveOnlyDeinitDevirtualization
2023-06-06 09:17:53 -07:00
swift-ci
1d39add45d Merge pull request #66328 from meg-gupta/fixtmprvalue
Disable TempRValueOpt when there are users of the temp object preceding the copy
2023-06-05 12:24:10 -07:00
nate-chandler
f0f05602f4 Merge pull request #66303 from nate-chandler/rdar109894792
[Mem2Reg] Recognize store_borrows for debug_value.
2023-06-05 10:30:43 -07:00
Meghana Gupta
332b405bd9 Disable TempRValueOpt when there are users of the temp object preceding the copy 2023-06-05 09:51:54 -07:00
Joe Groff
359e045192 Require switch on a noncopyable-type binding to be explicitly consume-d.
Pattern matching as currently implemented is consuming, but that's not
necessarily what we want to be the default behavior when borrowing pattern
matching is implemented. When a binding of noncopyable type is pattern-matched,
require it to be annotated with the `consume` operator explicitly. That way,
when we introduce borrowing pattern matching later, we have the option to make
`switch x` do the right thing without subtly changing the behavior of existing
code. rdar://110073984
2023-06-02 18:14:37 -07:00
Nate Chandler
d928def87f [Mem2Reg] Recognize store_borrows for debug_value.
When `debug_value`s are visited, if their operand is the stack address,
they are rewritten as `debug_value`s of the stored value, provided it is
known.

Previously, the check for whether the operand is the stack address,
however, just compared the `debug_value`'s operand with the
`alloc_stack`.  For owned `alloc_stack`s (i.e. those that are not
"store_borrow locations"), that was correct.  For guaranteed
`alloc_stack`s (i.e. those that are "store_borrow locations"), however,
this failed to recognize the the values produced by the `store_borrow`
instructions (which amount to aliases for the `alloc_stack`) as the
stack address.

Here, this is fixed by checking whether the `debug_value`'s operand is
either (1) the `alloc_stack` itself or (2) some `store_borrow` whose
destination is the `alloc_stack`.

rdar://109894792
2023-06-02 12:23:21 -07:00
Erik Eckstein
4284dc10d0 Optimizer: implement the ObjectOutliner pass in Swift 2023-05-22 15:34:26 +02:00
nate-chandler
76a733e4fd Merge pull request #65923 from nate-chandler/mem2reg/complete-new-enum-phi-lifetimes
[Mem2Reg] Complete new enum phi lifetimes.
2023-05-16 07:01:54 -07:00
Nate Chandler
209e3df685 [Mem2Reg] Complete new enum phi lifetimes.
When multi-block `alloc_stack`s of enum type with users are promoted,
lifetimes of stored values are completed to compensate for the legality
of not `destroy_addr`ing the `alloc_stack` in blocks where no
non-trivial value is known to be stored (the none case block of a
`switch_enum` of a load_borrow of the `alloc_stack`, e.g.).

Here, phis created during promotion are lifetime completed as well.
2023-05-15 17:39:54 -07:00
Nate Chandler
f234d8dfbb [Mem2Reg] NFC: Lifted livePhiBlocks into caller.
Previously, the value was computed and destroyed during
`promoteAllocationInBlock`.  Make the value available in
`StackAllocationPromoter`'s top-level routine (`::run`) in preparation
for using it there.
2023-05-15 13:37:06 -07:00
Nate Chandler
62b9323cde [Mem2Reg] NFC: Removed duplicative check.
Because getLexicalValueForStore returns "null" when
lexicalLifetimeEnsured is false, there's no need to check first whether
lexicalLifetimeEnsured is true before calling getLexicalValueForStore
and only taking action if a non-"null" value is returned.
2023-05-15 13:37:06 -07:00
Michael Gottesman
9c9fe09e25 [allocbox-to-stack] When we promote an argument that is moveonly, use consumable_and_assignable, not assignable_but_not_consumable.
Otherwise, since the compiler views assignable_but_not_consumable in this
position as a sign of an escaping closure, we emit escaping closure errors
instead of nonescaping closure errors.
2023-05-14 13:34:36 -07:00
Michael Gottesman
3ccda34275 Revert "[move-only] Ensure that we treat captured escaping closure arguments as such even if the closure doesn't actually escape"
This reverts commit 224674cad1.

Originally, I made this change since we were going to follow the AST in a strict
way in terms of what closures are considered escaping or not from a diagnostics
perspective. Upon further investigation I found that we actually do something
different for inout escaping semantics and by treating the AST as the one point
of truth, we are being inconsistent with the rest of the compiler. As an
example, the following code is considered by the compiler to not be an invalid
escaping use of an inout implying that we do not consider the closure to be
escaping:

```
func f(_ x: inout Int) {
  let g = {
    _ = x
  }
}
```

in contrast, a var is always considered to be an escape:

```
func f(_ x: inout Int) {
  var g = {
    _ = x
  }
}

test2.swift:3:13: error: escaping closure captures 'inout' parameter 'x'
    var g = {
            ^
test2.swift:2:10: note: parameter 'x' is declared 'inout'
func f(_ x: inout Int) {
         ^
test2.swift:4:11: note: captured here
        _ = x
          ^
```

Of course, if we store the let into memory, we get the error one would expect:

```
var global: () -> () = {}
func f(_ x: inout Int) {
  let g = {
    _ = x
  }
  global = g
}

test2.swift:4:11: error: escaping closure captures 'inout' parameter 'x'
  let g = {
          ^
test2.swift:3:10: note: parameter 'x' is declared 'inout'
func f(_ x: inout Int) {
         ^
test2.swift:5:7: note: captured here
    _ = x
      ^
```

By reverting to the old behavior where allocbox to stack ran early, noncopyable
types now have the same sort of semantics: let closures that capture a
noncopyable type that do not on the face of it escape are considered
non-escaping, while if the closure is ever stored into memory (e.x.: store into
a global, into a local var) or escapes, we get the appropriate escaping
diagnostics. E.x.:

```
public struct E : ~Copyable {}
public func borrowVal(_ e: borrowing E) {}
public func consumeVal(_ e: consuming E) {}

func f1() {
  var e = E()

  // Mutable borrowing use of e. We can consume e as long as we reinit at end
  // of function. We don't here, so we get an error.
  let c1: () -> () = {
    borrowVal(e)
    consumeVal(e)
  }

  // Mutable borrowing use of e. We can consume e as long as we reinit at end
  // of function. We do do that here, so no error.
  let c2: () -> () = {
    borrowVal(e)
    consumeVal(e)
    e = E()
  }
}

```
2023-05-14 13:34:36 -07:00
swift-ci
cd06759029 Merge pull request #65835 from meg-gupta/newflags
Add new flags "reborrow" and "escaping" to SILArgument.
2023-05-11 17:27:36 -07:00
Meghana Gupta
1dc713e2f7 Add new flags "reborrow" and "escaping" to SILArgument.
"reborrow" flag on the SILArgument avoids transitive walk over the phi operandsi
to determine if it is a reborrow in multiple utilities.
SIL transforms must keep the flag up-to-date by calling SILArgument::setReborrow.
SILVerifier checks to ensure the flag is not invalidated.

Currently "escaping" is not used anywhere.
2023-05-11 12:31:37 -07:00
Erik Eckstein
13108d69f6 SILOptimizer: remove the obsolete MandatoryGenericSpecializer pass 2023-05-11 08:11:44 +02:00
Erik Eckstein
dc3cb18029 Swift Optimizer: add the MandatoryPerformanceOptimizations pass
As a replacement for the old MandatoryGenericSpecializer

The pass it not enabled yet in the pass pipeline
2023-05-11 08:11:44 +02:00
Erik Eckstein
92a17f8a01 Optimizer: extract the NamedReturnValueOptimization from CopyForwarding to a separate function pass
This allows to run the NamedReturnValueOptimization only late in the pipeline.
The optimization shouldn't be done before serialization, because it might prevent predictable memory optimizations in the caller after inlining.
2023-05-11 08:11:44 +02:00
Erik Eckstein
85052a1489 deprecate the -experimental-performance-annotations option
Performance annotations can now be used without specifying this option
2023-05-11 08:03:19 +02:00
Erik Eckstein
ee2924fd27 Inliner: don't distinguish between the "mid-level" and "late" inliner
Now that we handle inlined global initializers in LICM, CSE and the StringOptimization, we don't need to have a separate mid-level inliner pass, which treats global accessors specially.
2023-05-08 21:23:36 +02:00
Erik Eckstein
19b828bcec StringOptimization: handle inlined global accessors.
In case a global accessor is inlined, the `global_addr` and it's `builtin "once"` call is visible in the SIL instead of the call to the global initializer.
2023-05-08 21:23:36 +02:00
Erik Eckstein
56c09c3aed CSE: cse builtin "once" calls
`builtin "once"` calls are a result of inlining global accessors
2023-05-08 21:23:36 +02:00
Erik Eckstein
260e68b102 Passmanager: fix a problem with skipping the inliner pass
A pass is skipped if no other pass changed the function since the previous run of the same pass.
Don't do this is if a pass depends on the function bodies of called functions, e.g. the inliner.
Other passes might change the callees, e.g. function signature opts, which makes it worth to run the inliner
again, even if the function itself didn't change.
2023-05-08 21:23:36 +02:00
Michael Gottesman
224674cad1 [move-only] Ensure that we treat captured escaping closure arguments as such even if the closure doesn't actually escape
Specifically, we already have the appropriate semantics for arguments captured
by escaping closures but in certain cases allocbox to stack is able to prove
that the closure doesn’t actually escape. This results in the capture being
converted into a non-escaping SIL form. This then causes the move checker to
emit the wrong kind of error.

The solution is to create an early allocbox to stack that doesn’t promote move
only types in boxes from heap -> stack if it is captured by an escaping closure
but does everything else normally. Then once the move checking is completed, we
run alloc box to stack an additional time to ensure that we keep the guarantee
that heap -> stack is performed in those cases.

rdar://108905586
2023-05-04 12:25:19 -07:00
Erik Eckstein
4b33b99ee2 MemoryLifetimeVerifier: be more precise with indirect function arguments.
Optimizations can rely on alias analysis to know that an in-argument (or parts of it) is not actually read.
We have to do the same in the verifier: if alias analysis says that an in-argument is not read, there is no need that the memory location is initialized.

Fixes a false verifier error.
rdar://106806899
2023-05-03 14:33:45 +02:00
nate-chandler
6e1a6fb13c Merge pull request #65359 from nate-chandler/rdar108376960
[AllocBoxToStack] Specialize moved PAIs.
2023-04-24 07:05:36 -07:00
Meghana Gupta
1f4efebbdf Enable temprvalueopt of lexical enum values 2023-04-22 15:11:19 -07:00
Meghana Gupta
f833bdb090 Enable Mem2Reg of lexical enum values in multiple blocks 2023-04-21 22:55:09 -07:00
Meghana Gupta
0b835f0080 Fix ownership verification error due to multi block mem2reg with store_borrows
@guaranteed stored values will never be added to a phi in mem2reg because
any uses of store borrowed locations have to be accessed via the store borrow return address
and since we ban address phis altogether we will never have input sil which necessitates this.

But, the DJ-edges based algorithm for inserting phi blocks in mem2reg can insert unnecessary phis
which are removed later.

Ensure fixPhiPredBlock handles both owned and guaranteed stored values correctly for this reason.
2023-04-21 12:29:18 -07:00
Nate Chandler
20147e61f1 [AllocBoxToStack] Specialize moved PAIs.
Added move_value to the list of instructions looked through when
determining whether a partial_apply instruction escapes.

rdar://108376960
2023-04-21 11:07:14 -07:00
Meghana Gupta
4496de1dfa Revert "Revert "Enable mem2reg of enum types ""
This reverts commit d6efa98447f7389440ba2c68d6e6f15196fff755.
2023-04-20 13:41:01 -07:00
Slava Pestov
d98484050b SILOptimizer: Fix bad hash calculation in CSE
Fixes rdar://problem/108045677.
2023-04-17 16:22:06 -04:00
Meghana Gupta
38dcfeca13 Merge pull request #65167 from meg-gupta/temprvalueenum
Enable store elimination of enums with uses in multiple blocks
2023-04-17 10:07:55 -07:00
Saleem Abdulrasool
cec38d780c Revert "Enable mem2reg of enum types " 2023-04-14 07:42:23 -07:00
swift-ci
2c084d82f1 Merge pull request #65085 from meg-gupta/mem2regenableoptional
Enable mem2reg of enum types
2023-04-13 18:31:37 -07:00
Meghana Gupta
96a6d44cf9 Enable mem2reg of enum types
Previously it was disabled because we have incomplete address lifetimes for such types,
and transforming to value form in mem2reg would expose verification errors due to incompleteness.

Enable this case here and fixup the lifetimes using the new lifetime completion utility.
2023-04-13 15:51:18 -07:00
Meghana Gupta
05d64b8d36 Enable store elimination of enums with uses in multiple blocks 2023-04-13 15:15:18 -07:00
Slava Pestov
a05019454c Merge pull request #65119 from slavapestov/sil-optimizer-peepholes-for-packs
Simple SILOptimizer peepholes for packs
2023-04-13 15:27:35 -04:00
nate-chandler
6b19388ea4 Revert "[Mem2Reg] Omit lexical moves for lexical values." 2023-04-13 08:31:04 -07:00
Slava Pestov
66d601cc40 SILOptimizer: Teach CSE about scalar_pack_index, dynamic_pack_index, tuple_pack_element_addr 2023-04-12 17:33:31 -04:00
Nate Chandler
1938912ceb [TempRValueOpt] NFC: Clarified assertion. 2023-04-12 07:24:41 -07:00
nate-chandler
2a3e7ba298 Merge pull request #65052 from nate-chandler/rdar104729396
[TempRValueOpt] Fold added destroy_addrs into loads/copy_addrs.
2023-04-12 07:03:16 -07:00
nate-chandler
252cc1ee8d Merge pull request #65022 from nate-chandler/rdar99160718
[Mem2Reg] Omit lexical moves for lexical values.
2023-04-11 16:23:48 -07:00
Meghana Gupta
5a35479975 Move around utilities, move isWriteAllocation outside the class 2023-04-11 15:40:13 -07:00
Nate Chandler
10215198da [TempRValueOpt] NFC: Assert no copy of uncopyable. 2023-04-11 10:41:53 -07:00
Nate Chandler
c21338af57 [TempRValueOpt] Fold new destroy_addrs into loads.
To avoid introducing new copies--which is illegal for move-only values--
don't rewrite `load [take]`s and `copy_addr [take]`s as `load [copy]`s
and `copy_addr`s respectively and introduce new `destroy_addr`s after
them.  Instead, get the effect of folding such a newly created
`destroy_addr` into the preceding rewritten `load [copy]` or
`copy_addr`.  Get that effect by neither modifying the `copy_addr [take]`
or `load [take]` nor adding a subsequent `destroy_addr`.

An example for each kind (`load [take]` and `copy_addr [take]`):

```
// Input 1 (`load [take]`)
  copy_addr [take] %src to [init] %tmp
  %val = load [take] %src
// Old Output 1
  %val = load [copy] %src
  destroy_addr %src
// New Output 2
  %val = load [take] %src
```

```
// Input 2 (`copy_addr [take]`)
  copy_addr [take] %src to [init] %tmp
  copy_addr [take] %src to [init] %dst
// Old Output 2
  copy_addr %src to [init] %dst
  destroy_addr %src
// New Output 2
  copy_addr [take] %src to [init] %dst
```

rdar://107839979
2023-04-11 10:41:53 -07:00
Nate Chandler
d2e4d5395f [TempRValueOpt] NFC: Renamed variable.
In preparation for "folding" an "inserted destroy" into a load [copy] or
copy_addr, rename the variable that indicates whether the copyInst's
source must be deinitialized after its last "load".
2023-04-11 10:41:53 -07:00