Commit Graph

190 Commits

Author SHA1 Message Date
Aidan Hall 070f7923d9 Bridging: Rename FunctionConvention.results to resultsWithError
This matches the name of the C++ method it bridges, and avoids the ambiguity of
the previous name.
2026-05-18 14:47:05 +01:00
Daniil Kovalev aa8f1d7efd [AutoDiff] Fix crash due to use after consume in differentiable_function (#88918)
The patch implements proper sil-combiner handling of
`differentiable_function` for cases when extractee has non-trivial
ownership. In such casese, it is consumed by the differentiable_function
instruction. We must copy the extractee before the consumption point so
the copy remains live afterward.

Fixes #88816
2026-05-13 21:33:13 +00:00
Joe Groff 097b0d3400 SIL: Split unchecked_*_enum_data_addr according to ownership and effects.
We cannot use spare bits or other overlapping storage layout tricks with fundamentally
address-only enums, and we can take advantage of this to do borrowing switches or other
in-place projections without copying the value. However, for resilient enums, the
implementation may use spare bit packing, but the type must be handled address-only
outside of its defining module, and we didn't have a way to express that with
borrowing switch. Optimization passes have also been running into problems with the
complexity that we were using `unchecked_take_enum_data_addr` sometimes as a pure
operation. This patch splits the instruction into three:

- `unchecked_inplace_enum_data_addr` represents a nondestructive in-place enum
  projection. It is only allowed for enums whose projection operation is
  nondestructive.
- `unchecked_take_enum_data_addr` represents a destructive enum projection,
  invalidating the enum and leaving the payload to be further consumed.
  This matches the current instruction's semantics.
- `unchecked_borrow_enum_data_addr` represents a borrowing enum projection.
  The instruction takes a second operand for "scratch" space, which the
  enum representation may be copied into in order to avoid invalidating the
  enum value, so the result is dependent on the lifetime of both the
  original enum and the scratch buffer. This allows for borrowing switches
  over resilient enums.

`unchecked_borrow_enum_data_addr` is implemented by taking advantage of the
"address-only enums can't do spare bit optimization" property at runtime.
We inspect the operand type's bitwise-borrowability from its metadata. If
the type is bitwise-borrowable, then we are allowed to bitwise-copy the
enum to the scratch space and apply the projection to the scratch space,
preserving the original value. If the type is not bitwise-borrowable, then
we cannot use spare bit optimization in its layout, so we apply the
projection in-place.

Fixes rdar://174952822.
2026-04-27 15:40:37 -07:00
Andrew Trick aafb6ced4c Enable load_borrow simplification at -Onone
Required for Builtin.borrowAt. SILGen may generate dead borrow scopes for
loadable values used in a return expression that for a borrow access that uses
guaranteed_address convention.

rdar://175382154 (Enable load_borrow simplification at -Onone)
2026-04-22 17:23:09 -07:00
Erik Eckstein 0494037b1e Optimizer: fix optimization of unconditional cond_fails
When the option `-remove-runtime-asserts` is used all `cond_fail` instructions are removed.
However, the cast optimizer inserts such unconditional fails for failing casts. This ended up in an infinite optimization loop in SILCombine.
The fix is
1. don't remove unconditional `cond_fail`s, even if with the `-remove-runtime-asserts` option. This also has the benefit that it enables later optimizations to remove all the dead code after such an unconditional `cond_fail`.
2. Don't optimize a failing cast if it is already preceded by an unconditional `cond_fail`

This bug was introduced by https://github.com/swiftlang/swift/pull/88258

Fixes a compiler hang
rdar://174185165
2026-04-09 16:42:29 +02:00
Erik Eckstein cc3c701462 Optimizer: move the cond_fail true optimization out of SILCombine into its own optimization pass
This optimization handles unconditional `cond_fail` instructions, i.e. `cond_fail`s with a non-zero `integer_literal` operand.
It cuts off the control flow after such a `cond_fail` by inserting an `unreachable` instruction.
However, this optimization cannot be done as instruction simplification, because it can leave OSSA lifetimes uncompleted.
Other simplification may depend on complete lifetimes.
Similar for constant folding failing casts: we also cannot insert an `unreachable` there.

Instead, do this optimization a new function pass (which can do lifetime completion).

Fixes a SIL verification error
rdar://173728487
2026-04-02 07:56:25 +02:00
Erik Eckstein bd1af9283f Optimizer: fix the enum tag comparison optimization
This optimization replaces (the very inefficient) RawRepresentable comparison to a simple compare of enum tags.
However if the raw type is a custom type we don't know how the comparison is implemented.
A custom raw type can implement the case comparison in a way that comparing different cases will return `true`.
Therefore only do the optimization for known stdlib raw value types.

Fixes a mis-compile
https://github.com/swiftlang/swift/issues/87906
rdar://172746003
2026-03-24 08:54:09 +01:00
Daniil Kovalev 0266a0a0df [AutoDiff][sil-combine] Support differentiable_function with borrowed scopes (#87826)
Support folding `differentiable_function_extract` of
`differentiable_function` in presence of borrowed scopes. Such folding
is crucial for VJP inlining, which is required for AutoDiff closure
specialization (ADCS) pass working properly.

Such handling was not required previously, but now ADCS runs in presence
of OSSA, making handling of borrowed scopes essential.

The folding logic is based on similar logic for
`struct`/`struct_extract` simplification.

Note that the `AutoDiff/SILOptimizer/licm_context.swift` test needs to
be modified since it relies on specific inlining behavior. Particularly,
we need to force inlining of the implicitly generated VJP of `B.a()`
into the VJP of `q()`. Without `@inline(__always)`, this particular
inlining decision stops happening on MacOS because the SIL combiner
changes from this patch affect the inlining decisions.

The changes from this patch make some new inlining decisions possible to
be taken befor attempting to inline the VJP of `B.a()` into the VJP of
`q()`. As a result, the VJP of `B.a()` becomes bigger because of other
VJPs being inlined into that, and the inlining cost of `B.a()` VJP
becomes too high when trying to perform inlining inside the VJP of
`q()`.

Depends on #87859 to allow force-inlining in
`AutoDiff/SILOptimizer/licm_context.swift`.
2026-03-18 18:06:18 +00:00
Erik Eckstein b7e5b9e423 SimplifyApply: insert the correct cast instruction when propagating the concrete type of an existential
When propagating a concrete type of an existential to an apply/try_apply instruction, we need to insert either an `unchecked_addr_cast` for address-only (= general) existentials or an `unchecked_ref_cast` for class existentials.

Fixes a SIL verification crash
rdar://172758483
2026-03-17 18:49:40 +01:00
John McCall d45af1c021 Allow alloc_ref and alloc_ref_dynamic to be marked [non_nested]
This hopefully unblocks fixing the stack nesting of the
concellation and priority escalation handler builtins.
2026-03-13 19:40:21 -04:00
Erik Eckstein 77f64398e5 Optimizer: run SimpilfyStructExtract also in SILCombine 2026-03-10 07:56:51 +01:00
Erik Eckstein 95ad832102 SimplifyStruct: split destructure_struct of copies
```
  %3 = struct $S(%1, %2)  // owned
  ...
  %4 = copy_value %3
  (%5, %6) = destructure_struct %5
```
->
```
  ...
  %5 = copy_value %1
  %6 = copy_value %2
```
2026-03-10 07:56:51 +01:00
Erik Eckstein b155f18741 simplify CheckedCastBranchInst: remove dead checked_cast_br instructions and run the simplification in SILCombine
For example:

```
  checked_cast_br B in %1 to X, bb1, bb2
bb1(%2 : @owned $X):
  destroy_value %2         // no other instructions in this block
  br bb3
bb2(%4 : @owned $B):
  destroy_value %4         // no other instructions in this block
  br bb3
```
2026-03-10 07:56:51 +01:00
Erik Eckstein 2554ecc8a8 SimplifyDestroyValue: support fix_lifetime when optimizing forwarding instructions
```
  %3 = struct $S (%1, %2)
  fix_lifetime %3
  destroy_value %3         // the only use of %3, except `fix_lifetime`
```
->
```
  fix_lifetime %1
  fix_lifetime %2
  destroy_value %1
  destroy_value %2
```
2026-03-10 07:56:50 +01:00
Erik Eckstein 55e1266255 SimplifyBeginBorrow: remove a borrow scope of all uses can directly use the enclosing owned value 2026-03-10 07:56:50 +01:00
Erik Eckstein 59e78b71b9 SimplifyLoadBorrow: handle projections when replacing a load_borrow from a store_borrow 2026-03-10 07:56:50 +01:00
Erik Eckstein 2d2b457be4 Optimizer: simplify move_value
The `move_value` instruction is only used to specify flags.
Remove a `move_value` which either doesn't specify any flags or which flags are not relevant outside the mandatory pipeline, like `[lexical]`.
2026-03-10 07:56:49 +01:00
Alejandro Alonso 32b6831b80 Ensure we emit an end_borrow after simplifying init_borrow_addr 2026-02-18 19:24:31 -08: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
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
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 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
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
Erik Eckstein 8aa911ba2f Optimizer: add simplifications for destroy_value
Attempt to optimize by forwarding the destroy to operands of forwarding instructions.

```
  %3 = struct $S (%1, %2)
  destroy_value %3         // the only use of %3
```
->
```
  destroy_value %1
  destroy_value %2
```

The benefit of this transformation is that the forwarding instruction can be removed.

Also, handle `destroy_value` for phi arguments.
This is a more complex case where the destroyed value comes from different predecessors via a phi argument.
The optimization moves the `destroy_value` to each predecessor block.

```
bb1:
  br bb3(%0)
bb2:
  br bb3(%1)
bb3(%3 : @owned T):
  ...                // no deinit-barriers
  destroy_value %3   // the only use of %3
```
->
```
bb1:
  destroy_value %0
  br bb3
bb2:
  destroy_value %1
  br bb3
bb3:
  ...
```
2025-12-03 15:53:55 +01:00
Adrian Prantl 99cf35cdce [SILOptimzer] Fix a crash caused by SILCombine mishandling inlined variables
This showed up on and off again on the source-compatibility testsuite project hummingbird.

The gist of the problem is that transformations may not rewrite the
type of an inlined instance of a variable without also createing a
deep copy of the inlined function with a different name (and e.g., a
specialization suffix). Otherwise the modified inlined variable will
cause an inconsistency when later compiler passes try to create the
abstract declaration of that inlined function as there would be
conflicting declarations for that variable.

Since SILDebugScope isn't yet available in the SwiftCompilerSources
this fix just drop these variables, but it would be absolutely
possible to preserve them by using the same mechanism that SILCloner
uses to create a deep copy of the inlined function scopes.

rdar://163167975
2025-11-07 17:06:33 -08: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 https://github.com/swiftlang/swift/pull/83728/commits/eb1d5f484c9f4dae73a3779191bfdf917fd07a49.
2025-10-16 10:12:33 +02:00
Erik Eckstein 82bffd3b21 Simplification: fold tuple - copy_value - destructure_tuple sequences
We already do this for structs.
Also, refactor the simplification to share the logic between structs and tuples
2025-10-14 10:20:17 +02:00
Erik Eckstein 181b2f1f6d Optimizer: eliminate struct_extracts of an owned struct where the struct_extracts are inside a borrow scope
This is done by splitting the `begin_borrow` of the whole struct into individual borrows of the fields (for trivial fields no borrow is needed).
And then sinking the `struct` to it's consuming use(s).

```
  %3 = struct $S(%nonTrivialField, %trivialField)  // owned
  ...
  %4 = begin_borrow %3
  %5 = struct_extract %4, #S.nonTrivialField
  %6 = struct_extract %4, #S.trivialField
  use %5, %6
  end_borrow %4
  ...
  end_of_lifetime %3
```
->
```
  ...
  %5 = begin_borrow %nonTrivialField
  use %5, %trivialField
  end_borrow %5
  ...
  %3 = struct $S(%nonTrivialField, %trivialField)
  end_of_lifetime %3
```

This optimization is important for Array code where the Array buffer is constantly wrapped into structs and then extracted again to access the buffer.
2025-10-08 17:48:37 +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
Anthony Latsis 3d898f71e5 SwiftCompilerSources/SIL: More robust IntegerLiteralInst construction
ac619010e3 backfired when building the
stdlib on rebranch. This time the problem is reversed: we should be
interpreting an integer as unsigned where we no longer do, here:
https://github.com/swiftlang/swift/blob/8f7af45115e373e05d3419ab272f02700bd8a48c/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyLoad.swift#L78.

Rather than treating integers as signed by default, make
`Builder.createIntegerLiteral` accept a generic `FixedWidthInteger`, and
manipulate the value based on the generic type argument's signedness.

This doesn't entirely define away unintentional sign extensions, but
makes this mistake of humouring the parameter type less likely.
2025-09-25 08:05:57 +01:00
Anthony Latsis 275deaf154 Merge pull request #84052 from swiftlang/jepa-main2
SwiftCompilerSources/SIL: Fix APInt assertion failure on rebranch
2025-09-24 17:39:04 +01:00
Anthony Latsis ac619010e3 SwiftCompilerSources/SIL: Fix APInt assertion failure on rebranch
The assertion is hit through `TypeValueInst.simplify` when constructing
an integer literal instruction with a negative 64-bit `Swift.Int` and a
bit width of 32 (the target pointer bit width for arm64_32 watchOS).
This happens because we tell the `llvm::APInt` constructor to treat the
input integer as unsigned by default in `getAPInt`, and a negative
64-bit signed integer does not fit into 32 bits when interpreted as
unsigned.

Fix this by flipping the default signedness assumption for the Swift API
and introducing a convenience method for constructing a 1-bit integer
literal instruction, where the correct signedness assumption depends on
whether you want to use 1 or -1 for 'true'.

In the context of using an integer to construct an `llvm::APInt`, there
are 2 other cases where signedness matters that come to mind:
1. A non-decimal integer literal narrower than 64 bits, such as
   `0xABCD`, is used.
2. The desired bit width is >64, since `llvm::APInt` can either
   zero-extend or sign-extend the 64-bit integer it accepts.

Neither of these appear to be exercised in SwiftCompilerSources, and
if we ever do, the caller should be responsible for either (1)
appropriately extending the literal manually, e.g.
`Int(Int16(bitPattern: 0xABCD))`, or (2) passing along the appropriate
signedness.
2025-09-24 09:37:42 +01:00
Jakub Florek 38f28c1049 Reapply "Merge pull request #84045 from MAJKFL/new-sil-licm-pass-copy-ownership"
This reverts commit d2cd281d4c.
2025-09-19 16:06:35 +01:00
Jakub Florek d2cd281d4c Revert "Merge pull request #84045 from MAJKFL/new-sil-licm-pass-copy-ownership"
This reverts commit a5c6156525, reversing
changes made to 2b6ea81b9e.
2025-09-17 15:52:48 +01:00
Jakub Florek df24019195 Rename Cloner.cloneRecursivelyToGlobal. 2025-09-10 16:18:50 +01:00
Erik Eckstein 844217d58c Optimizer: replace explicit_copy_value and explicit_copy_addr with their non-explicit counterparts
The `explicit_copy_value` and `explicit_copy_addr` instructions are only used for non-copyable diagnostics in the mandatory pipeline.
After that we can replace them by their non-explicit counterparts so that optimizations (which only know of `copy_value` and `copy_addr`) can do their work.

rdar://159039552
2025-09-04 19:40:53 +02:00
Jakub Florek e3140e0ae0 Add new generalized cloner. 2025-08-28 20:57:57 +01:00
Erik Eckstein 56521f0c3d Optimizer: fix handling of dependent existential archetypes in alloc_stack and apply simplification
When replacing an opened existential type with the concrete type, we didn't consider that the existential archetype can also be a "dependent" type of the root archetype.
For now, just bail in this case. In future we can support dependent archetypes as well.

Fixes a compiler crash.
rdar://158594365
2025-08-26 18:01:10 +02:00
Andrew Trick eb1d5f484c [NFC] SwiftCompilerSources: add a correctly named filterUsers API
Rename existing filterUsers to filterUses.
2025-08-14 09:08:11 -07:00
Erik Eckstein 41a6b8e257 SwiftCompilerSources: move SIL-related Context APIs from Optimizer to the SIL module 2025-07-28 14:19:11 +02:00
Erik Eckstein 5064297400 InstructionSimplification: simplify negated integer comparsions
Replaces a builtin "xor", which negates its operand comparison
```
  %3 = builtin "cmp_slt_Int64"(%1, %2) : $Builtin.Int1
  %4 = integer_literal $Builtin.Int1, -1
  %5 = builtin "xor_Int1"(%3, %4) : $Builtin.Int1
```
with the negated comparison
```
  %5 = builtin "cmp_ge_Int64"(%1, %2) : $Builtin.Int1
```

This makes LLVM's IPSCCP happy.

rdar://154950810
2025-07-18 07:43:51 +02:00
Erik Eckstein 12d9311b15 SILCombine: run builtin simplification as part of SILCombine
That means: make `BuiltinInst` conform to `SILCombineSimplifiable`, but still also run the legacy builtin simplification in SILCombine
2025-07-18 07:43:51 +02:00