Commit Graph

691 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
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
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
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
Aidan Hall
ea0f86ed29 Merge pull request #85408 from aidan-hall/164256638
Only print SIL before sub-passes of selected passes with -sil-print-every-subpass
2025-11-19 15:25:50 +00:00
Aidan Hall
305a5efaef SILOptimizer: Disable PackSpecialization pass to unblock SWBs
rdar://164515160
2025-11-17 17:38:13 +00:00
Aidan Hall
ec14566021 Optimizer: SILPrintEverySubpass: restrict to selected functions 2025-11-10 11:29:31 +00: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
Aidan Hall
8632e58825 Create Pack Specialisation pass 2025-10-30 14:28:16 +00: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
Erik Eckstein
32a85b1090 Optimizer: don't run AccessPathVerification
This pass has a complexity problem and can let compilation time get very long.
AccessPathVerification is not that important anymore because new passes written in Swift are using SmallProjectionPath instead.

rdar://162433770
2025-10-14 20:17:43 +02: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
8efafc7e3b Optimizer: remove the -experimental-swift-based-closure-specialization option 2025-10-06 12:02:48 +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
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
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
Erik Eckstein
2f124cf564 Remove the -enable-ossa-modules option.
OSSA modules are enabled by default.
The compiler still accepts this option but it has no effect.
2025-09-26 08:01:08 +02:00
Kavon Farvardin
4a943d464d sil: provide ability to run CopyPropagation in -Onone
This does not enable it by default. Use either of the flags:

```
-enable-copy-propagation
-enable-copy-propagation=always
```

to enable it in -Onone. The previous frontend flag
`-enable-copy-propagation=true` has been renamed to
`-enable-copy-propagation=optimizing`, which is currently default.

rdar://107610971
2025-09-19 16:23:19 -07:00
Erik Eckstein
ddea9f6aa0 Optimizer: switch to the new ConstantCapturePropagation pass in the pass pipeline 2025-09-04 08:15:46 +02: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
Erik Eckstein
667de83339 Optimizer: move DiagnoseStaticExclusivity after MandatoryAllocBoxToStack
This is needed because MandatoryAllocBoxToStack can convert dynamic accesses to static accesses.
Also, it improves diagnostics for closure captures.
2025-08-30 07:28:33 +02:00
Jakub Florek
07ac8b3478 Add new loop invariant code motion. 2025-08-28 21:00:33 +01:00
Meghana Gupta
3ef10405f8 Add options to print the SIL module after SILGen and SIL passes 2025-08-25 13:05:41 -07:00
Erik Eckstein
65c9828cb3 SwiftCompilerSources: move the Context protocols from the Optimizer to the SIL module
This allows to move many SIL APIs and utilities, which require a context, to the SIL module.

The SIL-part of SwiftPassInvocation is extracted into a base class SILContext which now lives in SIL.

Also: simplify the begin/end-pass functions of the SwiftPassInvocation.
2025-07-28 14:19:07 +02:00
Erik Eckstein
1a6ad0c512 Optimizer: add var insertedPhis in SSAUpdater 2025-07-04 11:10:27 +02:00
Erik Eckstein
35edadca6c Revert "Optimizer: revert to legacy alloc-box-to-stack optimization"
This reverts commit 18499e2bbd.
2025-07-02 19:15:26 +02:00
Erik Eckstein
18499e2bbd Optimizer: revert to legacy alloc-box-to-stack optimization
The new implementation causes some problems
rdar://154686063, rdar://154713388
2025-07-01 07:02:36 +02:00
Erik Eckstein
6714a72256 Optimizer: re-implement and improve the AllocBoxToStack pass
This pass replaces `alloc_box` with `alloc_stack` if the box is not escaping.
The original implementation had some limitations. It could not handle cases of local functions which are called multiple times or even recursively, e.g.

```
public func foo() -> Int {
  var i = 1

  func localFunction() { i += 1 }

  localFunction()
  localFunction()
  return i
}

```

The new implementation (done in Swift) fixes this problem with a new algorithm.
It's not only more powerful, but also simpler: the new pass has less than half lines of code than the old pass.

The pass is invoked in the mandatory pipeline and later in the optimizer pipeline.
The new implementation provides a module-pass for the mandatory pipeline (whereas the "regular" pass is a function pass).
This is required because the mandatory pass needs to remove originals of specialized closures, which cannot be done from a function-pass.
In the old implementation this was done with a hack by adding a semantic attribute and deleting the function later in the pipeline.

I still kept the sources of the old pass for being able to bootstrap the compiler without a host compiler.

rdar://142756547
2025-06-20 08:15:04 +02:00
Erik Eckstein
2b9b2d243c Optimizer: improve TempLValueOpt
* re-implement the pass in swift
* support alloc_stack liveranges which span over multiple basic blocks
* support `load`-`store` pairs, copying from the alloc_stack (in addition to `copy_addr`)

Those improvements help to reduce temporary stack allocations, especially for InlineArrays.

rdar://151606382
2025-06-05 06:45:18 +02:00
Erik Eckstein
198d4ab0bb Optimizer: run TempRValueElimination also at Onone
Introduce a new pass MandatoryTempRValueElimination, which works as the original TempRValueElimination, except that it does not remove any alloc_stack instruction which are associated with source variables.

Running this pass at Onone helps to reduce copies of large structs, e.g. InlineArrays or structs containing InlineArrays.
Copying large structs can be a performance problem, even at Onone.

rdar://151629149
2025-05-23 18:56:56 +02:00
Hamish Knight
edca7c85ad Adopt ABORT throughout the compiler
Convert a bunch of places where we're dumping to stderr and calling
`abort` over to using `ABORT` such that the message gets printed to
the pretty stack trace. This ensures it gets picked up by
CrashReporter.
2025-05-19 20:55:01 +01:00
Erik Eckstein
c6b1e3e854 TempRValueElimination: re-implement the pass in swift
Beside cleaning up the source code, the motivation for the translation into Swift is to make it easier to improve the pass for some InlineArray specific optimizations (though I'm not sure, yet if we really need those).
Also, the new implementation doesn't contain the optimize-store-into-temp optimization anymore, because this is covered by redundant load elimination.
2025-05-06 13:08:09 +02:00
Erik Eckstein
6c31eb0c43 embedded: rewrite the diagnostic pass for embedded swift
1. move embedded diagnostics out of the PerformanceDiagnostics pass. It was completely separated from the other logic in this pass, anyway.
2. rewrite it in swift
3. fix several bugs, that means: missed diagnostics, which led to IRGen crashes
  * look at all methods in witness tables, including base protocols and associated conformances
  * visit all functions in the call tree, including generic functions with class bound generic arguments
  * handle all instructions, e.g. concurrency builtins
4. improve error messages by adding meaningful call-site information. For example:
  * if the error is in a specialized function, report where the generic function is originally specialized with concrete types
  * if the error is in a protocol witness method, report where the existential is created
2025-04-18 06:58:40 +02:00
Artem Chikin
281f84da0f [Compile Time Values] Rewrite the 'Diagnose Unknown Compile Time Values' diagnostic pass in Swift 2025-03-28 10:30:07 -07:00
Artem Chikin
72a420919a [Compile Time Values] Add mandatory optimization pipeline driver for '@const' globals 2025-03-27 14:33:38 -07:00
Artem Chikin
d484ec7c1f [Compile Time Values] Implement a mandatory SIL pass to verify '@const' values 2025-03-27 14:33:35 -07:00
Erik Eckstein
cf8c8561ca Optimizer: move optimizer bridging code from PassManager.cpp into its own file.
The bridging code was in PassManager.cpp only for historical reasons.
It's now in OptimizerBridging.cpp.

NFC
2025-03-19 09:28:53 +01:00
Erik Eckstein
62ea5b1c81 PassManager: cleanup Passes.def
* move the "SILCombine passes" into a separate file `Simplifications.def` which lives in the SILCombiner directory
* group passes by kind
* rename PASS -> LEGACY_PASS and add a comment to make clear that new passes should be implemented in Swift

NFC
2025-03-18 18:34:52 +01:00
Erik Eckstein
37455b6ab6 Optimizer: use formal types instead of SIL types for classifying dynamic casts.
Casts always work with formal rather than lowered types.
This fixes a potential bug when lowered types are different than formal types, like function types.
2025-03-14 09:45:27 +01:00
Andrew Trick
619eb42a24 Remove an incorrect PassPipeline comment.
A pass was deleted from the PassPipeline without removing its comments!
2025-03-12 14:47:33 -07:00
Meghana Gupta
3fe1029ef8 [NFC] Reorganize and rename ArrayBoundsCheckOpts.cpp 2025-02-28 09:50:58 -08:00
Erik Eckstein
9b143d876b PassManager: invalidate analysis if a pass forgot to do so.
If a pass forgot to call invalidateAnalysis but deleted some instructions, the pass-manager can fix this.

Currently following passes do not invalidate analysis when they change the SIL:
* LowerTupleAddrConstructor
* DestroyAddrHoisting
* MoveOnlyChecker
* PredictableDeadAllocationElimination

Ideally we should fix those passes. But with this addition in the pass-manager it's not strictly necessary.

Fixes a compiler crash.
2025-02-14 08:08:43 +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
ba4081ee76 Optimizer: replace PredictableMemoryAccessOptimizations with MandatoryRedundantLoadElimination in the pass pipeline
PredictableMemoryAccessOptimizations has become unmaintainable as-is.
RedundantLoadElimination does (almost) the same thing as PredictableMemoryAccessOptimizations.
It's not as powerful but good enough because PredictableMemoryAccessOptimizations is actually only needed for promoting integer values for mandatory constant propagation.
And most importantly: RedundantLoadElimination does not insert additional copies which was a big problem in PredictableMemoryAccessOptimizations.

Fixes rdar://142814676
2025-02-07 11:30:35 +01:00
Meghana Gupta
6f9167c29e Serialize after high level passes for -emit-sib 2025-01-30 17:10:04 -08:00
Nate Chandler
1d22288f24 [NFC] SIL: Subpass runs can take values.
Allow continueWithNextSubpassRun to take a SILValue.
2025-01-16 08:18:29 -08:00
Meghana Gupta
571498289a [NFC] Print final ossa module when enabled 2024-12-23 08:31:31 -08:00
Erik Eckstein
35af29aaa0 Optimizer: don't run the UsePrespecialized pass in embedded mode
There are not pre-specialized parts of the stdlib in embedded mode.

Fixes a compiler crash.
Unfortunately I con't have a test case for this.

https://github.com/swiftlang/swift/issues/78167
2024-12-17 11:36:21 +01:00
Andrew Trick
98da813f02 [NFC] SwiftCompilerSources: add isConvertPointerToPointerArgument 2024-12-14 22:46:54 -08:00