Commit Graph

441 Commits

Author SHA1 Message Date
Andrew Trick
4f470a1d34 Fix LifetimeDependenceDiagnostics: scoped dependence on a copy
Diagnose a scoped dependence on an argument that inherits its lifetime as an
error:

@lifetime(borrow arg)
func reborrowSpan<T>(_ arg: Span<T>) -> Span<T> { arg }

@lifetime(copy span)
public func testBorrowInheritedArg<T>(_ span: Span<T>) -> Span<T> {
  reborrowSpan(span) // expected-error {{lifetime-dependent value escapes its scope}}
}

Fixes: rdar://146319009 ([nonescapable] enforce borrow constraint narrowing of inherited lifetime)
2025-04-25 17:58:23 -07:00
Andrew Trick
92b2a8587f Fix LifetimeDependenceDiagnostics: handle mark_dependence_addr
A small typo meant that scoped dependencies modeled with mark_dependence_addr
were not diagnosed.
2025-04-25 17:58:23 -07:00
Andrew Trick
bb9e52c3f2 LifetimeDependenceScopeFixup: cleanup for clarity 2025-04-25 17:58:23 -07:00
Erik Eckstein
8cf4e34cc1 RedundantLoadElimination: support replacing a redundant copy_addr with a store
For example:
```
  %0 = load %1
  copy_addr %1 to %2
```
->
```
  %0 = load %1
  store %0 to %2
```

This is important for MandatoryRedundantLoadElimination to be able to create statically initialized globals in the mandatory pipeline.
For example:
```
public struct MyStruct {
  public static let r: Range<Int> = 1 ..< 3
}

```
gets a statically initialized global, even at Onone, with this improvement.

rdar://149356742
2025-04-23 11:57:28 +02:00
Andrew Trick
33fbe11bf8 Fix LifetimeDependenceScopeFixup: read access can depend on 'inout'
Allow a dependency on a local [read] access scope to be transfered to the
caller's [modify] access.

Fixes rdar://149560133 (Invalid lifetime dependence error when
trying to return Span from an inout argument)
2025-04-22 11:54:53 -07:00
Andrew Trick
a1aaed9159 LifetimeDependenceScopeFixup: handle returning dependent Optional
Add support for returnValue phis (e.g. to return an Optional .some or .none).

Fixes rdar://149397018 (Wrapping non escapable in an Optional
(or any copy lifetime wrapper) is an escape)
2025-04-21 22:33:38 -07:00
Erik Eckstein
1c9a7cd562 SwiftCompilerSources: refactor DiagnosticEngine
* move it from the SIL to the AST module (where it belongs)
* change the signature of `diagnose` from `diagnose(location, .some_error)` to `diagnose(.some_error, at: location)`
* add an overload to allow passing a `SIL.Location` directly to `diagnose`
* add a `Diagnostic : Error` utility struct which allows throwing a `Diagnostic`
2025-04-18 06:58:38 +02:00
Andrew Trick
62454f42fd LifetimeDependenceScopeFixup: _read accessor: extend temporaries
Add support for extending owned temporary values in addition to access scopes
and borrow scopes. Required for _read accessors in which the coroutine depends
on an owned value.
2025-04-16 16:46:38 -07:00
Andrew Trick
b80bd16eea [NFC] Add LifetimeDependenceUseDefWalker utility.
Refactor VariableIntroducerUseDefWalker into a general
LifetimeDependenceUseDefWalker for use with LifetimeDependenceScopeFixup.
2025-04-16 16:43:23 -07:00
Anton Korobeynikov
87ca0f8680 Fix ownership issues with sequences of partial_apply's in AutoDiff closure specialization pass (#80662)
Each partial_apply consumes its arguments, therefore we should never release intermediate ones in the sequence of closures.

Fixes #78847
2025-04-15 07:14:44 -07:00
Meghana Gupta
fe780b670f Handle a special case of borrowed from instruction in CopyToBorrowOptimization 2025-04-11 13:21:22 -07:00
Andrew Trick
81ca8fd3ec Enable NonEscapableType support on Windows.
SwiftCompilerSources for Windows is now fully enabled, so there is no
longer any reason to gate these passes under an OS check.

commit d482ab73bc
Author: Hiroshi Yamauchi <hjyamauchi@gmail.com>
Date:   Fri Dec 13 09:24:44 2024 -0800

Update the pinned toolchain for Windows and enable SwiftCompilerSources for Win/ARM64
2025-03-31 11:21:06 -07:00
Andrew Trick
97b249bd11 Merge pull request #80263 from atrick/markdep-addr
SIL: add mark_dependence_addr
2025-03-26 10:33:42 -07:00
Erik Eckstein
8b2d27007f DiagnoseInfiniteRecursion: re-implement the pass in swift and fix a bug
Fixes a false alarm in case of recursive calls with different type parameters.
For example:

```
protocol P {
  associatedtype E: P
}

func noRecursionMismatchingTypeArgs1<T: P>(_ t: T.Type) {
  if T.self == Int.self {
    return
  }
  noRecursionMismatchingTypeArgs1(T.E.self)
}
```
2025-03-26 09:14:38 +01:00
Andrew Trick
d9dd93560d Support mark_dependence_addr in SIL passes. 2025-03-25 23:02:45 -07:00
Kuba Mracek
ed5e89a501 Also respect -mergeable-traps when merging cond_fails in SILOptimizer 2025-03-24 09:04:44 -07:00
Andrew Trick
001b162dc9 Surface addressableForDeps in SILType and FunctionConventions
With this approach, you cannot tell whether a parameter is addressable only
from the function type. Instead you need the SILValue that will be passed to the
call site.
2025-03-23 19:00:42 -07:00
Andrew Trick
bd7d3ec915 LifetimeDependentInsertion: assert on non-inout parameter dependency
The will be supported in a future commit that adds mark_dependence_addr.
2025-03-19 11:57:53 -07:00
Erik Eckstein
d52f7d1619 AST/SIL: Refactor and simplify AST.Type, AST.CanonicalType and SIL.Type
* let `SIL.Type` conform to `TypeProperties` to share the implementation of common type properties between the AST types and `SIL.Type`
* call references to an `AST.Type` `rawType` (instead of just `type`)
* remove unneeded stuff
* add comments
2025-03-14 09:40:22 +01:00
Meghana Gupta
b6b4a7bfdb Merge pull request #79841 from meg-gupta/fixsemanticarc
Fix two optimizer issues
2025-03-07 19:45:00 -08:00
Meghana Gupta
cd684a3200 Bailout of DestroyHoisting if there were no hoistable destroys
Otherwise, DestroyHoisting attemps to compute interior liveness
and inserts destoys at the ends. CanonicalizeOSSALifetimes is
designed to do this and not DestroyHoisting.
2025-03-07 10:40:42 -08:00
Meghana Gupta
87dcb65b4a Fix copy-to-borrow optimization's end_borrow insertion
allLifetimeEndingInstructions collects insertion points for end_borrows,
and can end up having duplicate entries in the case of enums with non payloaded cases.

Unique the entries so we don't end up with multiple end_borrows

Fixes rdar://146212574
2025-03-06 11:53:38 -08:00
Andrew Trick
b3f401d346 LifetimeDependenceScopeFixup: handle indirect yields & fix bugs
Handle coroutines that yield an address. Fix bugs involving extension of
multiple nested scopes that depend on multiple coroutine operands.
2025-03-05 02:12:21 -08:00
Andrew Trick
fa64a362a2 Add -Xfrontend -enable-address-dependencies
Temporary option to bootstrap '@'_addressable enforcement.

Once all the SILGen cases are handled, we won't need this option.
2025-03-03 16:21:48 -08:00
Andrew Trick
1b51aa8829 LifetimeDependenceScopeFixup: extend store_borrow scopes
This is require to handle '@'_addressable arguments on the caller side.
2025-03-03 16:21:48 -08:00
Andrew Trick
af878cc9af LifetimeDependenceInsertion: support '@'_addressable parameters 2025-03-03 11:56:37 -08:00
Andrew Trick
bc6200e592 SwiftCompilerSources: bridge '@'_addressable dependencies 2025-03-03 11:56:37 -08:00
Andrew Trick
e280c52825 Fix DestroyHoisting: don't ignore pointer escapes.
A pointer escape means the liveness is incomplete. Don't hoist destroys with
incomplete liveness.
2025-02-26 02:13:05 -08:00
Andrew Trick
353bef7904 Fix DestroyHoisting to visit all interior uses.
Set the visitInnerUses flag. This is only a quick, partial fix.

InteriorUseWalker does not generate complete liveness for two reasons

1. pointer escapes. The client must always check for escapes before assuming
complete liveness.

2. dead end blocks. Until we have complete OSSA lifetimes, the algorithm for
handling nested borrows is incorrect. The visitInnerUses flag works around this
problem, but it isn't well tested and I'm not sure it's properly records escapes yet.
2025-02-26 00:40:12 -08:00
Erik Eckstein
57a236e671 InitializeStaticGlobals: support statically initializing globals which are or contain inline arrays
For example:

```
struct S {
  static let slab: Slab = [1, 2, 3, 4]
}
```

rdar://143005996
2025-02-12 22:37:49 +01:00
eeckstein
dff88f968b Merge pull request #79317 from eeckstein/remove-alloc-vector
Remove the experimental FixedArray
2025-02-12 17:03:06 +01:00
Erik Eckstein
5b93eb31bf Optimizer: remove the AllocVectorLowering pass
It's not needed anymore, because the "FixedArray" experimental feature is replaced by inline-arrays.
2025-02-12 10:51:14 +01:00
Erik Eckstein
3f95ce9645 Optimizer: fix spelling of the Simplifiable protocol
Rename `Simplifyable` -> `Simplifiable`

NFC
2025-02-12 09:01:11 +01:00
Andrew Trick
c2842e8e19 LifetimeDependenceInsertion: remove a bailout on ~Copyable
Needed to diagnose MutableSpan and OutputSpan.

For now, simply remove the bailout and TODO. The next change will introduce more
logic to force a diagnostic error in rare cases that can't be handled completely.

Fixes rdar://143584461 (Extended exclusive borrow issues with
MutableSpan and OutputSpan)
2025-02-10 09:13:27 -08:00
Andrew Trick
39bae0bb58 LifetimeDependenceDiagnostics: immortal dependence on global 'let' 2025-02-10 09:11:22 -08:00
Andrew Trick
c3de120ca5 LifetimeDependence: simplify and fix multiple bugs.
Functional changes:

Improved modeling of dependence on local variable scopes.

For nested modify->read accesses, only extend the read accesses.

Avoid making a read access dependent on an inout argument.
The following needs to be an error to prevent span storage from being modified:

  @lifetime(owner)
  foo(owner: inout Owner) -> Span {
    owner.span
  }

Improve usability of borrowing trivial values (UnsafePointer). Allow:

  let span = Span(buffer.baseAddress)

Ignore access scopes for trivial values.

Structural changes:

Delete the LifetimeDependenceUseDefWalker.

Encapsulate all logic for variable introducers within the LifetimeDependenceInsertion pass. Once mark_dependence instructions are inserted, no subsequent pass needs to think about the "root" of a dependence.

Fixes: rdar://142451725 (Escape analysis fails with mutations)
2025-02-10 09:11:22 -08:00
Erik Eckstein
ce73deebc4 RedundantLoadElimination: add a "mandatory" redundant load elimination pass
And make `eliminateRedundantLoads` callable from other optimizations
2025-02-07 11:30:35 +01:00
Erik Eckstein
2af24703ab RedundantLoadElimination: insert mark_dependence instructions for a removed load
If the memory location depends on something, insert a dependency for the loaded value:
```
  %2 = mark_dependence %1 on %0
  %3 = load %2
```
->
```
  %2 = mark_dependence %1 on %0 // not needed anymore, can be removed eventually
  %3 = load %2
  %4 = mark_dependence %3 on %0
  // replace %3 with %4
```
2025-02-07 11:30:35 +01:00
Erik Eckstein
5acccf1802 RedundantLoadElimination: ignore memory effects of begin_access
Memory effects of begin_access are only defined to prevent the optimizer moving loads and stores across a begin_access.
But those memory effects are not relevant for RedundantLoadElimination
2025-02-07 11:30:35 +01:00
Erik Eckstein
ad2462f7f2 RedundantLoadElimination: optimize a load from a memory location which was written by copy_addr
For example:
```
  %1 = alloc_stack $B
  copy_addr %0 to [init] %1
  %3 = load [take] %1
  dealloc_stack %1
```
->
```
  %3 = load [copy] %0
```
2025-02-07 11:30:34 +01:00
Erik Eckstein
9b2dfbb741 DestroyHoisting: visit begin_borrows which don't have an end_borrow in dead-end blocks.
This makes sure that incomplete lifetimes are handled correctly.

Fixes an ownership violation.
rdar://144065326
2025-02-04 12:59:40 +01:00
Erik Eckstein
3ec5d7de24 SIL: replace the is_escaping_closure instruction with destroy_not_escaped_closure
The problem with `is_escaping_closure` was that it didn't consume its operand and therefore reference count checks were unreliable.
For example, copy-propagation could break it.
As this instruction was always used together with an immediately following `destroy_value` of the closure, it makes sense to combine both into a `destroy_not_escaped_closure`.
It
1. checks the reference count and returns true if it is 1
2. consumes and destroys the operand
2025-01-24 19:23:27 +01:00
Erik Eckstein
09f6f4f9b6 AutodiffClosureSpecialization: workaround a problem with OSSA.
Disable the closure specializer optimization for closures in OSSA until the underlying problem is fixed.
https://github.com/swiftlang/swift/issues/78847

Part of rdar://140229560
2025-01-23 16:10:32 +01:00
Andrew Trick
6849b66bb3 LifetimeDependenceDiagnostics; remove a bootstrapping hack.
This temporary hack was preventing diagnostics from kicking in. This could even
result in invalid SIL after the diagnostic failed to trigger.
2025-01-13 08:30:41 -08:00
Andrew Trick
b0f2ca03a7 AccessUtils: allow mark_deps to be tracked by the EnclosingScope.
This encourages AccessPathWalker clients to handle enclosing mark_deps. In
some cases, it is necessary. The accessBaseWithScopes API now provides both
nested begin_access and mark_dependence.
2025-01-11 15:40:22 -08:00
Erik Eckstein
e215ae990b CopyToBorrowOptimization: correctly handle unchecked_enum_data
A `unchecked_enum_data` which extracts a trivial payload out of a non-trivial enum ends the lifetime of its owned operand.

Fixes an ownership verification error
rdar://142644731
2025-01-10 09:08:31 +01:00
Erik Eckstein
a4c675ec88 CopyToBorrowOptimization: fix insertion order of end_borrows
In liferange exit blocks the end_borrows were inserted in the wrong order.

Fixes an ownership verification error
rdar://142632741
2025-01-10 08:56:42 +01:00
Andrew Trick
49136f237f Fix LifetimeDependenceScopeFixup to avoid rewriting mark_dependence.
This pass rewrites mark_depenendence to ignore "useless" borrow scopes. It was
also accidentally rewriting a dependence on a loaded value, which may redirect the
dependence to the access scope used to load that value. That access scope may be
narrower than the lifetime of the loaded value which could result in invalid
SIL. Do not rewrite this mark_dependence:

  %access = begin_access [read] [unknown] %base
  %load = load [trivial] %access
  end_access %access
  %adr = pointer_to_address
  %md = mark_dependence [unresolved] %adr on %load

Fixes rdar://142424000 (Swift compiler crashes with Assertion failed
(isa<UnreachableInst>(block->getTerminator())))
2025-01-07 15:36:52 -08:00
Erik Eckstein
cd7c533d42 Optimizer: add SingleValueInstruction.replace(with:) and use it throughout the optimizer
It replaces all uses and then erases the instruction.
2024-12-19 20:53:45 +01:00
Erik Eckstein
ca7facde35 SIL: add some use-list APIs
* `users`: maps from a sequence of operands to a sequence of instructions
* `users(ofType:)` : as `users`, but filters users of a certain instruction type
* `Value.users`: = `Value.uses.users`
2024-12-19 20:53:45 +01:00