Commit Graph

1269 Commits

Author SHA1 Message Date
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
Erik Eckstein
c822615dc2 Optimizer: convert the UpdateBorrowedFromPass pass to a test
And remove the now empty TestPasses directory.
2025-12-15 10:01:51 +01:00
Erik Eckstein
bff873dea0 Optimizer: convert the SILPrinter and TestInstructionIteration passes to tests 2025-12-15 10:01:41 +01:00
Erik Eckstein
c639c716b9 Optimizer: convert the RangeDumper pass to a test 2025-12-15 10:01:41 +01:00