Commit Graph

1272 Commits

Author SHA1 Message Date
Erik Eckstein ddb0141141 TempRValueElimination: support alloc_stacks with multi-block lifetime
So far the optimization just handled the case where all uses of the alloc_stack are in the same basic block.
Now we can handle arbitrary liveranges of the alloc_stack.
Also, remove the destroy-hoisting part of the algorithm because this is already handle by the dedicated DestroyAddrHoisting pass
2026-02-11 06:43:46 +01:00
Erik Eckstein 95d300c062 SimplifyAllocStack: support non-destructive enums and other improvements
Rewrite the enum -> single payload optimization to handle non-destructive `unchecked_take_enum_data_addr` correctly.
Also, we can handle more cases now.
2026-02-11 06:43:46 +01:00
Erik Eckstein a965f825a4 MandatoryPerformanceOptimizations: make sure to break infinite loops and complete lifetimes
Those tasks are already done within the optimization in `runSimplification`. However, afterwards we specialize generics in the function.
And specialization can create unreachable blocks and incomplete lifetimes.

Fixes a compiler crash
rdar://169554780
2026-02-06 15:44:45 +01:00
eeckstein 2bf3979f95 Merge pull request #86974 from eeckstein/simplification-pass
Optimizer: don't remove unused `destructure_struct` of a non-copyable value
2026-02-05 07:26:49 +01:00
Erik Eckstein 9f0a9d77c0 DeinitDevirtualizer: don't devirtualize destroy_value [dead_end]
It doesn't make sense to de-virtualize `destroy_value [dead_end]` because such operations are no-ops anyway.
This is especially important for Embedded Swift, because introducing calls to generic deinit functions after the mandatory pipeline can result in IRGen crashes.

rdar://168171608
2026-02-04 09:10:24 +01:00
Erik Eckstein 7ea1756fa4 Optimizer: don't remove unused destructure_struct of a non-copyable value
Because `destructure_struct` acts as lifetime-ending use. Removing this instruction results in an ownership error.
This can happen if a non-copyable struct only has trivial fields.

Fixes a verifier crash
https://github.com/swiftlang/swift/issues/86901
rdar://169285436
2026-02-04 08:47:42 +01:00
Erik Eckstein 6dde4c942e MandatoryPerformanceOptimizations: force de-virtualizing value-type deinits
Do this even if the function then contains references to other functions with wrong linkage.
MandatoryPerformanceOptimization fixes the linkage afterwards.
This is similar to what we already do with de-virtualizing class and witness methods: https://github.com/swiftlang/swift/pull/76032

rdar://168171608
2026-02-02 19:36:48 +01:00
Adrian Prantl 8b7d18ae00 Merge pull request #86902 from adrian-prantl/168622625
[TempRValueElimination] Make AllocStackInst.hasUses analysis global
2026-02-01 18:55:34 -08:00
Adrian Prantl d7ca6483a0 [TempRValueElimination] Make AllocStackInst.hasUses analysis global
Wihtout this change an alloc_stack instruction that is defined in a different
basic block than its use could result in instructions that are not dominated by
its operands. In an asserts build this is caught by the SIL verifier, but in a
non-asserts build it can crash the compiler.

Thanks to Erik Eckstein for the actual implementation of the fix!

rdar://168622625
2026-01-30 14:01:19 -08:00
Erik Eckstein 5cd70731da LifetimeCompletion/DiagnoseUnreachable: fix a wrong "will never be executed" warning
Make sure that debug locations are correct so that instruction which are inserted by DI after a no-return call doesn't cause DiagnoseUnreachable to print a wrong warning.
Also, add `extend_lifetime` to the list of excluded instructions in DiagnoseUnreachable.
2026-01-30 11:52:49 +01:00
eeckstein ad787dc6d4 Merge pull request #86840 from eeckstein/deinit-opts
Optimizer: fix two problems related to value-type deinits
2026-01-29 07:33:36 +01:00
eeckstein afdaf838a5 Merge pull request #86817 from eeckstein/fix-rle
RedundantLoadElimination: fix a complexity problem when replacing a huge amount of `load`s with a common value
2026-01-28 22:38:44 +01:00
Erik Eckstein 9d0b6c8417 RedundantLoadElimination: fix a complexity problem when replacing a huge amount of loads with a common value
As RedundantLoadElimination processing the loads in reverse control flow order, the replaced loads might accumulate quite a lot of users.
This happens if the are many loads from the same location in a row.
To void quadratic complexity in `uses.replaceAll`, we swap both load instructions and move the uses from the `existingLoad` (which usually has a small number of uses) to this load - and delete the `existingLoad`.

This came up in the Sema/large_int_array.swift.gyb test, which tests a 64k large Int array.
With this fix, the compile time gets down from 3 minutes to 5 seconds.
I also changed the test:
* run the compiler with the timeout script to detect build time regressions
* re-enabled the SIL verifier because the problem there is already fixed (https://github.com/swiftlang/swift/pull/86781)
* run the compiler with -O to also test the whole optimizer pipeline and not only the mandatory pipeline
* assigned the array to a real variable (instead of `_`) to not let the optimizer remove the whole array too early
* run the compiler with and without `-parse-as-library` because this makes a huge difference how the global array is being generated
2026-01-28 17:54:37 +01:00
Erik Eckstein bdf5a70258 DeinitDevirtualizer: don't create an invalid function_ref in a serialized function.
Serialized functions may not reference non-public functions.

Fixes a compiler crash
rdar://169022052
2026-01-28 13:10:30 +01:00
Alejandro Alonso a4fdb7d9ec Simplify the identity for dereference borrows 2026-01-27 11:04:25 -08:00
Alejandro Alonso 9f95dc7695 Simplify init_borrow_addr when the borrow type is statically known
make sure we register as well as add test
2026-01-27 11:03:53 -08:00
Joe Groff 9a417d4c28 Handle Borrow instructions in LifetimeCompletion 2026-01-23 10:03:23 -08:00
Joe Groff 5f49668577 Builtin.dereferenceBorrow should maintain the memory location of addressable values. 2026-01-23 08:02:09 -08:00
Joe Groff b11e8c985a SIL: Handle dereference_borrow returns in SILGenCleanup.
Make sure an `end_borrow` is emitted on the `dereference_borrow` so that
SILGenCleanup recognizes this pattern and lowers it to a `return_borrow`
as it does for returned `load_borrow`s. Add support to the Swift implementation
of `BorrowingInstruction` for `DereferenceBorrow`.
2026-01-23 08:02:09 -08:00
Joe Groff bc53d4ecb4 SIL: Handle Borrow instructions in more utility visitors. 2026-01-23 08:02:09 -08:00
eeckstein ee398d1b18 Merge pull request #86644 from eeckstein/lifetime-completion
Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
2026-01-23 06:14:10 +01:00
Erik Eckstein 7af1e1ffd1 TempRValueElimination: fix a problem with load-store copy elimination
If a value is "copied" to the stack location via a `load` and `store` instruction pair and the source location is written or de-allocated between both instructions,
the optimization generated wrong SIL.
The fix is to make sure that writes to the source locations are always checked between the `load` and `store`.

rdar://168595700
2026-01-22 18:03:02 +01:00
Erik Eckstein 5ea44a4a70 CopyToBorrowOptimization: remove special handling of dead-end blocks
Which is now possible with complete OSSA lifetimes
2026-01-22 17:41:48 +01:00
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00
Erik Eckstein 7b6247332f Optimizer: add FunctionPassContext.updateAnalysis()
This is useful if a pass needs an updated analysis after invalidating the SIL of a function.
2026-01-22 17:41:24 +01:00
Erik Eckstein 0f0aa0c17b Optimizer: require that there are no unreachable blocks and infinite loops in OSSA
These two new invariants eliminate corner cases which caused bugs if optimization didn't handle them.
Also, it will significantly simplify lifetime completion.

The implementation basically consists of these changes:
* add a flag in SILFunction which tells optimization if they need to take care of infinite loops
* add a utility to break infinite loops
* let all optimizations remove unreachable blocks and break infinite loops if necessary
* add verification to check the new SIL invariants

The new `breakIfniniteLoops` utility breaks infinite loops in the control flow by inserting an "artificial" loop exit to a new dead-end block with an `unreachable`.
It inserts a `cond_br` with a `builtin "infinite_loop_true_condition"`:
```
bb0:
  br bb1
bb1:
  br bb1              // back-end branch
```
->
```
bb0:
  br bb1
bb1:
  %1 = builtin "infinite_loop_true_condition"() // always true, but the compiler doesn't know
  cond_br %1, bb2, bb3
bb2:                  // new back-end block
  br bb1
bb3:                  // new dead-end block
  unreachable
```
2026-01-22 17:41:23 +01:00
Erik Eckstein 34aa3c00d3 Optimizer: move var needFixStackNesting from MutatingContext to FunctionPassContext 2026-01-22 17:41:23 +01:00
Erik Eckstein 16cb80b60d Optimizer: implement all of cond_fail simplification as instruction simplification
Inserts an unreachable after an unconditional fail:
```
  %0 = integer_literal 1
  cond_fail %0, "message"
  // following instructions
```
->
```
  %0 = integer_literal 1
  cond_fail %0, "message"
  unreachable
deadblock:
  // following instructions
```

Remove the old SILCombine implementation because it's not working well with OSSA lifetime completion.
This also required to move the `shouldRemoveCondFail` utility function from SILCombine to InstOptUtils.
2026-01-22 17:41:22 +01:00
Erik Eckstein 2860c2df77 Optimizer: add DominatorTree.getImmediateDominator and DominatorTree.getDominanceOrder 2026-01-22 17:41:22 +01:00
Erik Eckstein 1a4eb8ca7e MandatoryDestroyHoisting: correct handling of destroy_value [dead_end]
Make sure to create `destroy_value` with correct dead_end flags.
Especially, in a dead-end region where the original value's lifetime was ended with a `destroy_value [dead_end]`, the optimization must not re-create a destroy without the dead_end flag.

^ Conflicts:
^	test/SILOptimizer/mandatory-destroy-hoisting.sil
2026-01-22 17:41:21 +01:00
Erik Eckstein 4755aa828e DestroyHoisting: correct handling of destroy_value [dead_end]
Make sure to create `destroy_value` with correct dead_end flags.
Especially, in a dead-end region where the original value's lifetime was ended with a `destroy_value [dead_end]`, the optimization must not re-create a destroy without the dead_end flag.

^ Conflicts:
^	test/SILOptimizer/destroy-hoisting.sil
2026-01-22 17:41:21 +01:00
Aidan Hall 37e89902a3 Merge pull request #85957 from aidan-hall/fix-debug-info-again
Retain more debug info in SIL optimization passes
2026-01-13 17:13:36 +00:00
Erik Eckstein a85c34452a DestroyHoisting: don't bail for lexical liveranges
We don't need to check for lexical liveranges anymore because we now have "fixed" liveranges throughout the optimizer pipeline (https://github.com/swiftlang/swift/pull/85334).
2026-01-12 14:05:47 +01:00
Erik Eckstein 0d0f5f6e99 SimplifyDestroyValue: don't re-create a destroy_value [dead_end] as a non-dead-end destroy_value
This can cause several problems, e.g. false performance errors or even mis-compiles.
Instead, just ignore dead-end destroys as we don't want to "move" them away from `unreachable` instructions, anyway.

rdar://167553623
2026-01-07 11:53:34 +01:00
Aidan Hall 0ef2094279 [DebugInfo] Salvage more during SIL optimization passes
This reverts commit b1eb70bf45.

The original PR (#85244) was reverted (#85836) due to rdar://165667449

This version fixes the aforementioned issue, and (potentially) improves overall
debug info retention by salvaging info in erase(instructionIncludingDebugUses:),
rather than inserting many explicit salvageDebugInfo calls throughout the code
to make the test cases pass.

Bridging: Make salvageDebugInfo a method of MutatingContext

This feels more consistent than making it a method of Instruction.

DebugInfo: Salvage from trivially dead instructions

This handles the case we were checking in constantFoldBuiltin, so we do not need to salvage debug info there any more.
2026-01-06 12:01:20 +00:00
Erik Eckstein b2791f1b60 LoopInvariantCodeMotion: don't hoist load [take]
Usually `load [take]` is not hoisted anyway, because there must be another instruction in the loop which re-initializes the loaded memory location.
However, this is not necessarily true for alloc_stack locations with dynamic lifetime, e.g. a pack-loop which is specialized for a single pack element (at runtime the loop is only executed once).

Fixes a SIL ownership verifier crash
rdar://167504916
2026-01-05 10:41:44 +01:00
Daniil Kovalev 7f0963e23f Fix conformance-related warnings appearing after PR85757 (#86183)
The conformances `Type: Comparable` and `EnumCase: Equatable` were
previously introduced in #85757 for implementing AutoDiff closure
specialization logic. This patch moves the latter directly to the SIL
module. The conformance `Type: Comparable` is deleted, and `sort(by:)`
is used instead of `sort` to mimic the same behavior in tests. These
changes address warnings mentioned in the comment:
https://github.com/swiftlang/swift/pull/85757#issuecomment-3681636278
2026-01-02 11:58:29 +00:00
AZero13 5325085551 use subst directly instead of calling bridgeToSwiftCall.substitutionMap again 2025-12-26 20:25:13 -05:00
Daniil Kovalev 1f77138afe [AutoDiff] Closure specialization: specialize branch tracing enums (#85757)
This patch contains part of the changes intended to resolve #68944.

1. Closure info gathering logic.
2. Branch tracing enum specialization logic.
3. Specialization of branch tracing enum basic block arguments in VJP.
4. Specialization of branch tracing enum payload basic block arguments
in pullback.

Note that mangling-related logic is implemented in C++ since at this
moment we have no Swift bridged for that.

Here is a simplified example of how branch tracing enum (BTE)
specialization looks like.

Before specialization:

```
enum $_AD__xxx {
  case bb0(((Float) -> Float))
}

func vjp(...) {
  // ...
  %foo      = function_ref $foo         : (Float, Float) -> Float
  %pa1      = partial_apply %foo(%arg1) : (Float) -> Float
  %payload1 = tuple (%pa1)              : ((Float) -> Float)
  %bte      = enum $_AD__xxx.bb0!enumelt, %payload1
  // ...
}

func pullback(%bte, ...) {
  // ...
  %payload2 = unchecked_enum_data %bte, $_AD__xxx.bb0!enumelt : ((Float) -> Float)
  %pa2      = tuple_extract %payload2, 0                      : (Float) -> Float
  %res      = apply %pa2(%arg2)                               : Float
  // ...
}
```

After specialization:

```
enum $_AD__xxx_spec_bb0_0 {
  case bb0(((Float)))
}

func vjp(...) {
  // ...
  %captured1 = tuple (%arg1)      : (Float)
  %payload1  = tuple (%captured1) : ((Float))
  %bte_spec  = enum $_AD__xxx_spec_bb0_0.bb0!enumelt, %payload1
  // ...
}

func pullback_spec(%bte_spec, ...) {
  // ...
  %payload2  = unchecked_enum_data %bte, $_AD__xxx_spec_bb0_0.bb0!enumelt : ((Float))
  %captured2 = tuple_extract %payload2, 0                                 : (Float)
  %arg1      = tuple_extract %captured2, 0                                : Float
  %foo       = function_ref $foo                                          : (Float, Float) -> Float
  %res       = apply %foo(%arg2, %arg1)                                   : Float
  // ...
}
```
2025-12-21 00:33:50 +00:00
Erik Eckstein 7ace2c5736 CopyToBorrowOptimization: need to update borrowed-from instructions when changes are made
When ownership is changed from owned to guaranteed, the enclosing values of a guaranteed value can change.
Fixes a SIL verifier error.
2025-12-19 17:44:00 +01:00
Erik Eckstein fb5015832e SimplifyDestructure: convert destructure_tuple/destructure_struct with guaranteed ownership to to tuple_extract/struct_extract 2025-12-19 17:44:00 +01:00
Erik Eckstein d5afd16fbf Optimizer: rename SimplifyMisc.swift -> SimplifyTypeValue.swift 2025-12-19 17:43:59 +01:00
Erik Eckstein 9631d6cdf8 SimplifyLoad/SimplifyLoadBorrow: add two peephole optimizations
* Replace address casts of heap objects
```
  %1 = unchecked_addr_cast %0 : $*SomeClass to $*OtherClass
  %2 = load [copy] %1
```
with ref-casts of the loaded value
```
  %1 = load [copy] %0
  %2 = unchecked_ref_cast %1 : $SomeClass to $OtherClass
```

* Replace a `load_borrow` of a `store_borrow` with a `begin_borrow`:
```
  %1 = alloc_stack $T
  %2 = store_borrow %0 to %1
  ...
  %3 = load_borrow %2
  // ... uses of %3
  end_borrow %3
```
->
```
  %1 = alloc_stack $T
  %2 = store_borrow %0 to %1
  ...
  %3 = begin_borrow %0
  // ... uses of %3
  end_borrow %3
```
2025-12-19 17:43:59 +01:00
Erik Eckstein a250a30e8c SimplifyBeginBorrow: remove inner borrow scopes and other improvements
* remove borrow scopes which are borrowing an already guaranteed value
* allow optimizing lexical `begin_borrows` outside the mandatory pipeline
* fix: don't remove `begin_borrow [lexical]` of a `thin_to_thick_function` in the mandatory pipeline
2025-12-19 17:43:58 +01:00
Erik Eckstein 0271a4fd03 SimplifyBeginBorrow: ignore type-dependent operands when converting borrowed -> owned 2025-12-19 17:43:58 +01:00
Erik Eckstein 2868663963 Optimizer: handle debug_value in begin_borrow simplification
When trying to remove a borrow scope by replacing all guaranteed uses with owned uses, don't bail for values which have debug_value uses.
Also make sure that the debug_value instructions are located within the owned value's lifetime.
2025-12-19 17:43:58 +01:00
Erik Eckstein ec8fe839c5 SimplifyBeginBorrow: small refactoring
* rename `lookThroughSingleForwardingUses` -> `lookThroughOwnedConvertibaleForwardingChain`
* fix the comment of `replaceGuaranteed`
2025-12-19 17:43:58 +01:00
Erik Eckstein f67a310861 Optimizer: split SimplifyBeginAndLoadBorrow.swift into SimplifyBeginBorrow.swift and SimplifyLoadBorrow.swift 2025-12-19 17:43:57 +01:00
Meghana Gupta 5c4ce2f942 Merge pull request #86023 from meg-gupta/miscborrowfixes
Minor fixes to borrow accessors
2025-12-16 20:03:19 -08:00
Meghana Gupta 0c5fe56b7f Bailout on address apply result while computng argument escaping effects 2025-12-15 13:02:13 -08:00