Commit Graph

450 Commits

Author SHA1 Message Date
Aidan Hall
90e12147e0 Merge pull request #85456 from aidan-hall/pack-opt-fix-weather-swb
PackSpecialization: Fix result & type parameter handling
2025-12-02 15:38:32 +00:00
Aidan Hall
96dca43eb9 Merge pull request #85244 from aidan-hall/fixing-debug-info-rebase
Retain more debug info in optimized builds
2025-12-01 20:49:40 +00:00
eeckstein
9304ce951c Merge pull request #85707 from eeckstein/embedded-witness-method-specialization
embedded: change the function representation of directly called witness methods
2025-12-01 09:36:45 +01:00
Aidan Hall
a95d2979f9 [DebugInfo] Salvage more in -O builds
Specifically, improved debug info retention in:
* tryReplaceRedundantInstructionPair,
* splitAggregateLoad,
* TempLValueElimination,
* Mem2Reg,
* ConstantFolding.

The changes to Mem2Reg allow debug info to be retained in the case tested by
self-nostorage.swift in -O builds, so we have just enabled -O in that file
instead of writing a new test for it.

We attempted to add a case to salvageDebugInfo for unchecked_enum_data, but it
caused crashes in Linux CI that we were not able to reproduce.
2025-11-28 17:42:18 +00:00
Aidan Hall
97b7c35647 PackSpecialization: Fix result & type parameter handling
Refactor certain functions to make them simpler. and avoid calling
AST.Type.loweredType, which can fail. Instead, access the types of the
function's (SIL) arguments directly.

Correctly handle exploding packs that contain generic or opaque types by using
AST.Type.mapOutOfEnvironment().

@substituted types cause the shouldExplode predicate to be unreliable for AST
types, so restrict it to just SIL.Type. Add test cases for functions that have
@substituted types.

Re-enable PackSpecialization in FunctionPass pipeline.

Add a check to avoid emitting a destructure_tuple of the original function's
return tuple when it is void/().
2025-11-28 17:39:41 +00:00
Erik Eckstein
64dd574bea embedded: change the function representation of directly called witness methods
This is needed in Embedded Swift because the `witness_method` convention requires passing the witness table to the callee.
However, the witness table is not necessarily available.
A witness table is only generated if an existential value of a protocol is created.

This is a rare situation because only witness thunks have `witness_method` convention and those thunks are created as "transparent" functions, which means they are always inlined (after de-virtualization of a witness method call).
However, inlining - even of transparent functions - can fail for some reasons.

This change adds a new EmbeddedWitnessCallSpecialization pass:
If a function with `witness_method` convention is directly called, the function is specialized by changing the convention to `method` and the call is replaced by a call to the specialized function:

```
  %1 = function_ref @callee : $@convention(witness_method: P) (@guaranteed C) -> ()
  %2 = apply %1(%0) : $@convention(witness_method: P) (@guaranteed C) -> ()
...
sil [ossa] @callee : $@convention(witness_method: P) (@guaranteed C) -> () {
  ...
}
```
->
```
  %1 = function_ref @$e6calleeTfr9 : $@convention(method) (@guaranteed C) -> ()
  %2 = apply %1(%0) : $@convention(method) (@guaranteed C) -> ()
...
// specialized callee
sil shared [ossa] @$e6calleeTfr9 : $@convention(method) (@guaranteed C) -> () {
  ...
}
```

Fixes a compiler crash
rdar://165184147
2025-11-26 16:23:47 +01:00
Erik Eckstein
78cb4ca197 Optimizer: extract replacing an apply into a utility function ApplySite.replace(withCallTo:) 2025-11-26 16:23:47 +01:00
Erik Eckstein
ab2345a2ed FunctionPassContext: support setting arbitrary function type representations when creating specialized functions 2025-11-26 16:23:47 +01:00
Erik Eckstein
9a124742b0 Optimizer: add the DeadAccessScopeElimination optimization pass
It eliminates dead access scopes if they are not conflicting with other scopes.

Removes:
```
  %2 = begin_access [modify] [dynamic] %1
  ...                                       // no uses of %2
  end_access %2
```

However, dead _conflicting_ access scopes are not removed.
If a conflicting scope becomes dead because an optimization e.g. removed a load, it is still important to get an access violation at runtime.
Even a propagated value of a redundant load from a conflicting scope is undefined.

```
  %2 = begin_access [modify] [dynamic] %1
  store %x to %2
  %3 = begin_access [read] [dynamic] %1    // conflicting with %2!
  %y = load %3
  end_access %3
  end_access %2
  use(%y)
```
After redundant-load-elimination:
```
  %2 = begin_access [modify] [dynamic] %1
  store %x to %2
  %3 = begin_access [read] [dynamic] %1    // now dead, but still conflicting with %2
  end_access %3
  end_access %2
  use(%x)                                  // propagated from the store, but undefined here!
```
In this case the scope `%3` is not removed because it's important to get an access violation error at runtime before the undefined value `%x` is used.

This pass considers potential conflicting access scopes in called functions.
But it does not consider potential conflicting access in callers (because it can't!).
However, optimizations, like redundant-load-elimination, can only do such transformations if the outer access scope is within the function, e.g.

```
bb0(%0 : $*T):     // an inout from a conflicting scope in the caller
  store %x to %0
  %3 = begin_access [read] [dynamic] %1
  %y = load %3     // cannot be propagated because it cannot be proved that %1 is the same address as %0
  end_access %3
```

All those checks are only done for dynamic access scopes, because they matter for runtime exclusivity checking.
Dead static scopes are removed unconditionally.
2025-11-24 14:49:45 +01:00
Erik Eckstein
50c299e0bf LoopInvariantCodeMotion: don't reuse existing instructions in the loop pre-header
This is wrong for hoisted load instructions because we don't check for aliasing in the pre-header.
And for side-effect-free instructions it's not really necessary, because that can cleanup CSE afterwards.

Fixes a miscompile
rdar://164034503
2025-11-18 21:23:13 +01:00
Meghana Gupta
827c30f13c Merge pull request #85482 from meg-gupta/reduceendcowmutation
Avoid inserting end_cow_mutation_addr in some common cases
2025-11-13 19:07:45 -08:00
Meghana Gupta
1dc03fea25 Add early exit for Escapable and copyable types from mayHaveMutableSpan 2025-11-13 10:36:34 -08:00
Meghana Gupta
5e88f38152 Avoid inserting end_cow_mutation_addr in some common cases 2025-11-13 09:58:08 -08:00
Meghana Gupta
e2123e1b3b Merge pull request #85362 from meg-gupta/moreborrow
Add SIL verification for borrow and mutate accessors and some other minor fixes
2025-11-10 09:04:28 -08: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
Meghana Gupta
a0eb58fa07 Handle return_borrow in a few more places in SwiftCompilerSources 2025-11-06 10:55:31 -08:00
Andrew Trick
382529c73b Merge pull request #85232 from atrick/rdar159793739-lifedep-cast
LifetimeDependenceDiagnostics: handle dynamic casting of Span<T>
2025-10-31 08:35:36 -07:00
Andrew Trick
e11f7f1f11 LifetimeDependenceDiagnostics: diagnostic error on unknown uses
The common def-use walkers should not return .abortWalk without making a
diagnostic callback.
2025-10-30 23:28:25 -07: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
Andrew Trick
5494a24899 Merge pull request #85076 from atrick/lifedep-reassign
Lifetimes: handle MutableSpan reassignment and 'inout' arguments
2025-10-24 09:55:34 -07:00
Andrew Trick
ff4d053a44 [NFC] LifetimeDependenceDefUseWalker.inoutDependence entry point
Handle cases where there's no relevant operand.
2025-10-23 23:34:24 -07:00
Andrew Trick
a0f0c108b0 [NFC] Add a new entry point for DiagnoseDependence.reportError
Allow diagnosing values that have no relevant users. Such as an @inout argument.
2025-10-23 23:34:24 -07:00
Andrew Trick
3bb3e4d077 [NFC] Add ApplySite.parameterDependence(target:source:) 2025-10-23 23:34:23 -07:00
Erik Eckstein
6988b03c13 ClosureSpecialization: don't crash for recursive functions
Don't support self-recursive functions because that would result in mapping troubles when cloning.
2025-10-24 06:11:53 +02:00
Erik Eckstein
53f424e5f0 TempRValueOptimization: respect deinit-barriers when hoisting destroys
Fixes a mis-compile which causes a deinit to be called earlier than expected.

rdar://162299994
2025-10-23 20:45:11 +02:00
Erik Eckstein
5b8a1a7b68 LoopInvariantCodeMotion: don't extend "read" access scopes over memory writes to the same address.
We must not do this even if the write is _not_ in an access scope, because this would confuse alias analysis.

Fixes a mis-compile.
2025-10-22 20:55:22 +02:00
Erik Eckstein
dafb43b124 LoopInvariantCodeMotion: a small code cleanup
NFC
2025-10-22 20:55:22 +02:00
eeckstein
9074a1eec3 Merge pull request #85005 from eeckstein/remove-copy-forwarding
Optimizer: remove the CopyForwarding pass
2025-10-21 07:24:42 +02:00
Erik Eckstein
dbeda9612c TempRValueElimination: handle debug_value instructions 2025-10-20 20:19:54 +02:00
Erik Eckstein
62c3850d55 TempRValueElimination: allow elimination of dead alloc_stacks in non-OSSA 2025-10-20 20:19:54 +02:00
Erik Eckstein
8618a39ac5 TempRValueElimination: support consuming indirect apply operands 2025-10-20 20:19:53 +02:00
Meghana Gupta
0bd6825aa2 Update SIL utilities for borrow and mutate accessors under opaque values mode 2025-10-20 09:05:38 -07:00
Erik Eckstein
62e2871b2f MandatoryPerformanceOptimizations: run DeadStoreElimination for global init functions.
Cleanup leftovers from simplification.
The InitializeStaticGlobals pass cannot deal with dead stores in global init functions.
2025-10-17 20:25:19 +02:00
Erik Eckstein
794964adba MandatoryRedundantLoadElimination: remove redundant loads from global variables
This is important in the initializer functions of globals. It can enabled static initialization of globals in more cases.
2025-10-17 20:25:19 +02:00
Daniil Kovalev
75f80410e6 Run closure specialization only if ownership info is present in callee (#84956)
Calling `cloneRecursively` from `SpecializationInfo.cloneClosures`
requires the callee having ownership info. Otherwise, the cloner uses
`recordFoldedValue` instead of `recordClonedInstruction`, and
`postProcess` hook is not called, which leads to an assertion failure in
`BridgedClonerImpl::cloneInst`.
2025-10-17 10:51:57 -07:00
Erik Eckstein
610539a85f SIL: streamline Operand Sequence APIs
* remove `filterUsers(ofType:)`, because it's a duplication of `users(ofType:)`
* rename `filterUses(ofType:)` -> `filter(usersOfType:)`
* rename `ignoreUses(ofType:)` -> `ignore(usersOfType:)`
* rename `getSingleUser` -> `singleUser`
* implement `singleUse` with `Sequence.singleElement`
* implement `ignoreDebugUses` with `ignore(usersOfType:)`

This is a follow-up of eb1d5f484c.
2025-10-16 10:12:33 +02:00
Erik Eckstein
5104c317ca TempRValueElimination: fix a problem with non-copyable types
In case of a non-copyable type the final destroy (or take) of a stack location can be missing if the value has only trivial fields.
The optimization inserted a `destroy_addr` in this case although it wasn't there before.

Beside fixing this problem I also refactored the code a bit to make it more readable.
2025-10-10 21:37:27 +02:00
eeckstein
757de6e2a6 Merge pull request #84711 from eeckstein/fix-licm
LoopInvariantCodeMotion: fix check for hoisting `load_borrow` instructions
2025-10-07 11:40:29 +02:00
eeckstein
401a2ac2bc Merge pull request #84704 from eeckstein/closure-specialization
ClosureSpecialization: support for OSSA and a big overhaul
2025-10-07 06:59:08 +02:00
Andrew Trick
c2171ea9b0 Merge pull request #84703 from atrick/lifedep-diag-init
Lifetimes: add a diagnostic note for implicit accessors
2025-10-06 12:29:51 -07:00
Erik Eckstein
55cdc31936 LoopInvariantCodeMotion: a small refactoring
which is now possible as we removed the "fallthrough" from the previous case
2025-10-06 17:57:12 +02:00
Erik Eckstein
e88096e971 LoopInvariantCodeMotion: fix check for hoisting load_borrow instructions
We need to check aliasing for all kind of side-effect instructions, not just stores and destroys
2025-10-06 17:57:12 +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
Erik Eckstein
2cd625a367 Optimizer: add the Builder.insertCleanupAtFunctionExits utility 2025-10-06 09:47:40 +02:00
Erik Eckstein
c3612bafb8 SIL: make var OperandArray.values available for all kind of operand sequences 2025-10-06 09:47:40 +02:00
Andrew Trick
771e9b522e Lifetimes: add a diagnostic note for implicit accessors
Lifetime diagnostics may report an error within an implicit initializer or
accessor. The source location is misleading in these cases and causes much
consternation.
2025-10-05 20:16:44 -07:00
Andrew Trick
7197f63ce2 Comment LifetimeDependenceScopeFixup. Explain unreachable paths. 2025-10-03 20:44:17 -07:00
Erik Eckstein
171607afa7 DeadStoreElimination: fix a corner case of storing a trivial case of a non-trivial enum
Storing a trivial enum case in a non-trivial enum must be treated like a non-trivial init or assign, e.g.
```
  %1 = enum $Optional<String>, #Optional.none!enumelt
  store %1 to [trivial] %0  // <- cannot delete this store!
  store %2 to [assign] %0
```
2025-10-02 19:20:35 +02:00