Commit Graph

2150 Commits

Author SHA1 Message Date
Michael Gottesman
1bb65d8def Merge pull request #85165 from gottesmm/rdar153207557
[sil] Change SILIsolationInfo inference for classmethods to use SILDeclRef instead of using the AST directly.
2025-11-07 02:02:50 -08:00
eeckstein
552b665a9e Merge pull request #85334 from eeckstein/mandatory-destroy-hoisting
Optimizer: make destroy hoisting a mandatory pass
2025-11-07 06:45:03 +01:00
Michael Gottesman
8016bf2332 [sil] Change SILIsolationInfo inference for classmethods to use SILDeclRef instead of using the AST directly.
We are creating/relying on a contract between the AST and SIL... that SILDeclRef
should accurately describe the method/accessor that a class_method is from. By
doing this we eliminate pattern matching on the AST which ties this code too
tightly to the AST and makes it brittle in the face of AST changes. This also
fixes an issue where we were not handling setters correctly.

I am doing this now since it is natural to fix it along side fixing the
ref_element_addr issue in the previous commit since they are effectively doing
the same thing.

rdar://153207557
2025-11-06 20:25:23 -08:00
Anton Korobeynikov
89a7663f1d [AutoDiff] Initial support for differentiation of throwing functions (#82653)
This adds initial support for differentiation of functions that may produce `Error` result. 

Essentially we wrap the pullback into `Optional` and emit a diamond-shape control flow pattern depending on whether the pullback value is available or not. VJP emission was modified to accommodate for this. In addition to this, some additional tricks are required as `try_apply` result is not available in the instruction parent block, it is available in normal successor basic block.

As a result we can now:
- differentiate an active `try_apply` result (that would be produced from `do ... try .. catch` constructions)
- `try_apply` when error result is unreachable (usually `try!` and similar source code constructs)
- Support (some) throwing functions with builtin differentiation operators. stdlib change will follow. Though we cannot support typed throws here (yet)
- Correctly propagate error types during currying around differentiable functions as well as type-checking for `@derivative(of:)` attribute, so we can register custom derivatives for functions producing error result
- Added custom derivative for `Optional.??` operator (note that support here is not yet complete as we cannot differentiate through autoclosures, so `x ?? y` works only if `y` is not active, e.g. a constant value).

Some fixes here and there
2025-11-06 13:12:43 -08:00
Erik Eckstein
04688a69ec Optimizer: Always respect deinit barriers when hoisting destroys.
Also for non-lexical lifetimes
2025-11-06 21:00:45 +01:00
Erik Eckstein
62786b01e2 Optimizer: add the mandatory destroy hoisting pass
It hoists `destroy_value` instructions for non-lexical values.

```
  %1 = some_ownedValue
  ...
  last_use(%1)
  ... // other instructions
  destroy_value %1
```
->
```
  %1 = some_ownedValue
  ...
  last_use(%1)
  destroy_value %1    // <- moved after the last use
  ... // other instructions
```

In contrast to non-mandatory optimization passes, this is the only pass which hoists destroys over deinit-barriers.
This ensures consistent behavior in -Onone and optimized builds.
2025-11-06 21:00:44 +01:00
John McCall
8d231d20c6 Rewrite StackNesting to be a non-iterative single-pass algorithm.
The previous algorithm was doing an iterative forward data flow analysis
followed by a reverse data flow analysis. I suspect the history here is that
it was a reverse analysis, and that didn't really work for infinite loops,
and so complexity accumulated.

The new algorithm is quite straightforward and relies on the allocations
being properly jointly post-dominated, just not nested. We simply walk
forward through the blocks in consistent-with-dominance order, maintaining
the stack of active allocations and deferring deallocations that are
improperly nested until we deallocate the allocations above it. The only
real subtlety is that we have to delay walking into dead-end regions until
we've seen all of the edges into them, so that we can know whether we have
a coherent stack state in them. If the state is incoherent, we need to
remove any deallocations of previous allocations because we cannot talk
correctly about what's on top of the stack.

The reason I'm doing this, besides it just being a simpler and hopefully
faster algorithm, is that modeling some of the uses of the async stack
allocator properly requires builtins that cannot just be semantically
reordered. That should be somewhat easier to handle with the new approach,
although really (1) we should not have runtime functions that need this and
(2) we're going to need a conservatively-correct solution that's different
from this anyway because hoisting allocations is *also* limited in its own
way.

I've attached a rather pedantic proof of the correctness of the algorithm.

The thing that concerns me most about the rewritten pass is that it isn't
actually validating joint post-dominance on input, so if you give it bad
input, it might be a little mystifying to debug the verifier failures.
2025-11-03 11:51:17 -08:00
Aidan Hall
8632e58825 Create Pack Specialisation pass 2025-10-30 14:28:16 +00:00
Aidan Hall
c7af4c584e Bridging: APIs for PackSpecialization pass 2025-10-26 13:44:34 +00:00
Meghana Gupta
e116df3628 Introduce return_borrow instruction 2025-10-23 05:18:59 -07:00
Slava Pestov
4eaf33f0a5 Merge pull request #85029 from jamieQ/remove-strip-debug-pass
[NFC][SILOptimizer]: remove seemingly unused StripDebugInfo pass
2025-10-21 17:23:37 -04:00
Jamie
7bb97a581d [NFC][SILOptimizer]: remove seemingly unused StripDebugInfo pass 2025-10-21 08:32:14 -05:00
Erik Eckstein
7a7004927c Optimizer: remove the CopyForwarding pass
This pass removes `copy_addr` instructions.
However, it has some problems which causes compiler crashes.
It's not worth fixing these bugs because
1. Most copy_addrs can be eliminated by TempRValueElimination and TempLValueElimination.
2. Once we have opaque value we don't need copy_addr elimination, anyway.

rdar://162212460
2025-10-20 20:19:54 +02:00
Michael Gottesman
828bf45e4e [rbi] Ensure that we error when two 'inout sending' parameters are in the same region at end of function.
The caller is allowed to assume that the 'inout sending' parameters are not in
the same region on return so can be sent to different isolation domains safely.
To enforce that we have to ensure on return that the two are /actually/ not in
the same region.

rdar://138519484
2025-10-17 12:07:09 -07:00
Erik Eckstein
65e4c10113 Optimizer: remove the obsolete SpeculativeDevirtualization pass
This pass has been disabled since a very long time (because it's terrible for code size).
It does not work for OSSA. Therefore it cannot be enabled anymore (as is) once we have OSSA throughout the pipeline.
So it's time to completely remove it.
2025-10-13 10:49:17 +02:00
Erik Eckstein
df20d36255 ClosureSpecialization: support for OSSA and a big overhaul
Beside supporting OSSA, this change significantly simplifies the pass.
The main change is that instead of starting at a closure (e.g. `partial_apply`) and finding all call sites, we now start at a call site and look for closures for all arguments. This makes a lot of things much simpler, e.g. not so many intermediate data structures are required to track all the states.

I needed to remove the 3 unit tests because the things those tests were testing are not there anymore. However, the pass is tested with a lot of sil tests (and I added quite a few), which should give good test coverage.

The old ClosureSpecializer pass is still kept in place, because at that point in the pipeline we don't have OSSA, yet. Once we have that, we can replace the old pass withe the new one.
However, the autodiff closure specializer already runs in the OSSA pipeline and there the new changes take effect.
2025-10-06 12:02:48 +02:00
Erik Eckstein
89bba668e2 Mangling: add a closure specialization mangling for arguments which specialize for the same closure as a previous argument
For example:
```
  %1 = partial_apply %closure
  apply %f(%1, %1)    // first argument: `.closure(%1)`
                      // second argument: `.previousArgumentIndex(0)`
```
2025-10-06 09:47:41 +02:00
Mishal Shah
03a599c5be Merge pull request #84606 from swiftlang/rebranch
Merge clang 21.x rebranch into main
2025-10-02 20:17:05 -07:00
Arnold Schwaighofer
25a071efc8 Add experimental feature @inline(always)
The intent for `@inline(always)` is to act as an optimization control.
The user can rely on inlining to happen or the compiler will emit an error
message.

Because function values can be dynamic (closures, protocol/class lookup)
this guarantee can only be upheld for direct function references.

In cases where the optimizer can resolve dynamic function values the
attribute shall be respected.

rdar://148608854
2025-09-30 08:36:26 -07:00
swift-ci
d5a03fa0e4 Merge remote-tracking branch 'origin/main' into rebranch 2025-09-26 22:36:42 -07:00
Erik Eckstein
7217722c83 Optimizer: remove the now unused NonTransparentFunctionOwnershipModelEliminator pass
Also remove the `skipStdlibModule` flag from the OwnershipModelEliminator, because it's always false
2025-09-26 08:01:09 +02:00
swift-ci
92d91df7c2 Merge remote-tracking branch 'origin/main' into rebranch 2025-09-25 08:37:30 -07:00
Erik Eckstein
39b9969049 SIL: use Test for the SmallProjectionPath's unit tests
Now that we have `Test` available in the SIL module, we can use it for the SmallProjectionPath's unit tests and get rid of the RunUnitTests pass.
2025-09-24 11:46:34 +02:00
Anthony Latsis
e1450e011e Manually merge remote-tracking branch 'origin/main' into rebranch
Conflicts:
*	utils/build_swift/build_swift/defaults.py
2025-09-04 14:07:50 +01:00
Erik Eckstein
bb3b0b2859 Optimizer: remove the old CapturePropagation pass 2025-09-04 08:15:47 +02:00
Erik Eckstein
efa9f9ebc0 Optimizer: rewrite and improve the ConstantCapturePropagation pass
(old name: CapturePropagation)

The pass is now rewritten in swift which makes the code smaller and simpler.
Compared to the old pass it has two improvements:

* It can constant propagate whole structs (and not only builtin literals). This is important for propagating "real" Swift constants which have a struct type of e.g. `Int`.
* It constant propagates keypaths even if there are other non-constant closure captures which are not propagated. This is something the old pass didn't do.

rdar://151185177
2025-09-04 08:15:46 +02:00
Erik Eckstein
8e86b5ce3b Optimizer: add a preserveGenericSignature flag to FunctionPassContext.createSpecializedFunctionDeclaration 2025-09-04 08:15:46 +02:00
Erik Eckstein
45b1a21e74 Optimizer: make ModulePassContext.specialize() also available in FunctionPassContext and add two argument flags
add `convertIndirectToDirect` and `isMandatory`
2025-09-04 08:15:45 +02:00
Erik Eckstein
231042b9a8 SIL: some Cloner cleanups and improvements
* move some Cloner utilities from ContextCommon.swift directly into Cloner.swift
* add an `cloneRecursively` overload which doesn't require the `customGetCloned` closure argument
* some small cleanups
2025-09-04 08:15:45 +02:00
Erik Eckstein
1a4bd76f95 Mangling: add specialization mangling for more complex constant propagated function arguments
So far, constant propagated arguments could only be builtin literals.
Now we support arbitrary structs (with constant arguments), e.g. `Int`.
This requires a small addition in the mangling scheme for function specializations.
Also, the de-mangling tree now looks a bit different to support a "tree" of structs and literals.
2025-09-04 08:15:44 +02:00
Erik Eckstein
bc244d1122 SIL: move the FunctionBuilderTy template argument from TypeSubstCloner to remapParentFunction 2025-09-04 08:15:44 +02:00
swift-ci
ac529bd9df Merge remote-tracking branch 'origin/main' into rebranch 2025-09-01 02:37:16 -07:00
Jakub Florek
eae7864370 Merge pull request #83988 from MAJKFL/new-sil-licm-pass-copy
New SIL LICM pass
2025-09-01 10:28:17 +01:00
swift-ci
1b057c0958 Merge remote-tracking branch 'origin/main' into rebranch 2025-08-29 20:59:22 -07:00
Michael Gottesman
391ad21583 [rbi] Make all PartitionOpErrors noncopyable types.
I am going to be adding support to passes for emitting IsolationHistory behind a
flag. As part of this, we need to store the state of the partition that created
the error when the error is emitted. A partition stores heap memory so it makes
sense to make these types noncopyable types so we just move the heap memory
rather than copying it all over the place.
2025-08-29 15:18:55 -07:00
swift-ci
93688bfe95 Merge remote-tracking branch 'origin/main' into rebranch 2025-08-29 14:57:15 -07:00
Michael Gottesman
6d20c74c3e Merge pull request #83903 from gottesmm/rdar152454571
[rbi] Teach RegionIsolation how to properly error when 'inout sending' params are returned.
2025-08-29 14:56:58 -07:00
swift-ci
76185d16a9 Merge remote-tracking branch 'origin/main' into rebranch 2025-08-29 04:51:27 -07:00
Jakub Florek
85aeb41bd0 Remove old LICM pass. 2025-08-28 22:57:46 +01:00
Jakub Florek
07ac8b3478 Add new loop invariant code motion. 2025-08-28 21:00:33 +01:00
Jakub Florek
3514b2b9df Bridge array semantics call and loop tree 2025-08-28 21:00:09 +01:00
Jakub Florek
bc86fe5a38 Hoist ArrayCallKind to a separate file 2025-08-28 20:50:33 +01:00
Erik Eckstein
87e7250750 Optimizer: fix an ownership violation when duplicating loops
If a guaranteed value is used in a dead-end exit block and the enclosing value is _not_ destroyed in this block, we end up missing the enclosing value as phi-argument after duplicating the loop.
TODO: once we have complete lifetimes we can remove this check again.

rdar://159125605
2025-08-28 18:40:54 +02:00
Michael Gottesman
8745ab00de [rbi] Teach RegionIsolation how to properly error when 'inout sending' params are returned.
We want 'inout sending' parameters to have the semantics that not only are they
disconnected on return from the function but additionally they are guaranteed to
be in their own disconnected region on return. This implies that we must emit
errors when an 'inout sending' parameter or any element that is in the same
region as the current value within an 'inout sending' parameter is
returned. This commit contains a new diagnostic for RegionIsolation that adds
specific logic for detecting and emitting errors in these situations.

To implement this, we introduce 3 new diagnostics with each individual
diagnostic being slightly different to reflect the various ways that this error
can come up in source:

* Returning 'inout sending' directly:

```swift
func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
  return x // expected-warning {{cannot return 'inout sending' parameter 'x' from global function 'returnInOutSendingDirectly'}}
  // expected-note @-1 {{returning 'x' risks concurrent access since caller assumes that 'x' and the result of global function 'returnInOutSendingDirectly' can be safely sent to different isolation domains}}
}
```

* Returning a value in the same region as an 'inout sending' parameter. E.x.:

```swift
func returnInOutSendingRegionVar(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
  var y = x
  y = x
  return y // expected-warning {{cannot return 'y' from global function 'returnInOutSendingRegionVar'}}
  // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' and the result of global function 'returnInOutSendingRegionVar' can be safely sent to different isolation domains}}
}
```

* Returning the result of a function or computed property that is in the same
region as the 'inout parameter'.

```swift
func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
  let y = x
  return useNonSendableKlassAndReturn(y) // expected-warning {{cannot return result of global function 'useNonSendableKlassAndReturn' from global function 'returnInOutSendingViaHelper'}}
  // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' and the result of global function 'returnInOutSendingViaHelper' can be safely sent to different isolation domains}}
}
```

Additionally, I had to introduce a specific variant for each of these
diagnostics for cases where due to us being in a method, we are actually in our
caller causing the 'inout sending' parameter to be in the same region as an
actor isolated value:

* Returning 'inout sending' directly:

```swift
extension MyActor {
  func returnInOutSendingDirectly(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
    return x // expected-warning {{cannot return 'inout sending' parameter 'x' from instance method 'returnInOutSendingDirectly'}}
    // expected-note @-1 {{returning 'x' risks concurrent access since caller assumes that 'x' is not actor-isolated and the result of instance method 'returnInOutSendingDirectly' is 'self'-isolated}}
  }
}
```

* Returning a value in the same region as an 'inout sending' parameter. E.x.:

```swift
extension MyActor {
  func returnInOutSendingRegionLet(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
    let y = x
    return y // expected-warning {{cannot return 'y' from instance method 'returnInOutSendingRegionLet'}}
    // expected-note @-1 {{returning 'y' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' is not actor-isolated and the result of instance method 'returnInOutSendingRegionLet' is 'self'-isolated}}
  }
}
```

* Returning the result of a function or computed property that is in the same region as the 'inout parameter'.

```swift
extension MyActor {
  func returnInOutSendingViaHelper(_ x: inout sending NonSendableKlass) -> NonSendableKlass {
    let y = x
    return useNonSendableKlassAndReturn(y) // expected-warning {{cannot return result of global function 'useNonSendableKlassAndReturn' from instance method 'returnInOutSendingViaHelper'; this is an error in the Swift 6 language mode}}
    // expected-note @-1 {{returning result of global function 'useNonSendableKlassAndReturn' risks concurrent access to 'inout sending' parameter 'x' since the caller assumes that 'x' is not actor-isolated and the result of instance method 'returnInOutSendingViaHelper' is 'self'-isolated}}
  }
}
```

To implement this, I used two different approaches depending on whether or not
the returned value was generic or not.

* Concrete

In the case where we had a concrete value, I was able to in simple cases emit
diagnostics based off of the values returned by the return inst. In cases where
we phied together results due to multiple results in the same function, we
determine which of the incoming phied values caused the error by grabbing the
exit partition information of each of the incoming value predecessors and seeing
if an InOutSendingAtFunctionExit would emit an error.

* Generic

In the case of generic code, it is a little more interesting since the result is
a value stored in an our parameter instead of being a value directly returned by
a return inst. To work around this, I use PrunedLiveness to determine the last
values stored into the out parameter in the function to avoid having to do a
full dataflow. Then I take the exit blocks where we assign each of those values
and run the same check as we do in the direct phi case to emit the appropriate
error.

rdar://152454571
2025-08-25 14:57:44 -07:00
swift-ci
843ad4c9f3 Merge remote-tracking branch 'origin/main' into rebranch 2025-08-20 13:36:43 -07:00
nate-chandler
d1637af144 Merge pull request #83789 from nate-chandler/nfc/20250818/1
[NFC] Renamed three SIL utilities.
2025-08-20 13:25:04 -07:00
Nate Chandler
5da38cb04b [NFC] OSSACanonicalizeGuaranteed: Renamed. 2025-08-18 09:45:27 -07:00
Nate Chandler
8f1d6616af [NFC] OSSACanonicalizeOwned: Renamed. 2025-08-18 09:45:21 -07:00
Nate Chandler
aa85694237 [NFC] OSSACompleteLifetime: Renamed. 2025-08-18 09:45:19 -07:00
swift-ci
65e945b84d Merge remote-tracking branch 'origin/main' into rebranch 2025-08-15 17:56:33 -07:00