Commit Graph

754 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
Ben Cohen ad8a8f7cc8 SILOptimizer: add FunctionConvention.formalResults; use it in PackSpecialization
The C++ `SILFunctionType` exposes both `getResults()` (formal results only)
and `getResultsWithError()` (formal + error). The Swift mirror previously
only had `results`, bridging to the with-error variant. Add `formalResults`
for the formal-only view, matching the C++ split.

Switch PackSpecialization's three result-iteration sites to `formalResults`.
The bridged `createSpecializedFunctionDeclaration` preserves the error
result on its own, so iterating with-error included it twice in the new
function's signature.

Also forward the original apply's `nothrow`/`noasync` flags to the
specialized apply, required for SIL verification of a plain apply calling
a function with an error result.
2026-05-18 14:45:26 +01:00
elsa 83d4291709 CSE Optimizer Pass rewrite (#88248)
Resolves rdar://173862129
2026-05-15 19:11:10 +01:00
Erik Eckstein 8e6560aa78 SIL: fix handling of index_addr in AccessUtils
Fixes a miscompile when the index of `index_addr` is a negative integer constant. In this case two access paths were considered overlapping while in reality they reference two different array elements.

The miscompile manifested in the dead-store-elimination pass, but could potentially also show up in other passes, which use this utility.

https://github.com/swiftlang/swift/issues/77558
rdar://176820188
2026-05-12 19:59:37 +02:00
Erik Eckstein 78340fd42d Optimizer: de-virtualize deinits of non-copyable InlineArray elements
This is especially important for Embedded Swift because non de-virtualized deinits result in IRGen crashes.

Fixes a compiler crash in embedded
rdar://175984319
2026-05-05 07:27:13 +02:00
Erik Eckstein e942ae40b0 AliasAnalysis: correctly handle InlineArray in type-based alias analysis
Fixes a mis-compile where TBAA failed to recurse into `Builtin.FixedArray`'s element type.

rdar://176106882
2026-05-04 10:55:54 +02:00
Erik Eckstein d28549af34 Optimizer: workaround for fast type casting to the FullApplySite and ReturnInstruction protocols
Rather than doing a standard swift runtime cast to an existential, explicitly check for the conforming instruction classes, which is much faster.
The new `isFullApplySite` and `isReturnInstruction` casting utilities are used in the (very few) time critical places in the optimizer.

After toolchain builders are upgraded to a compiler version which includes the fix for this problem (https://github.com/swiftlang/swift/pull/88270), we don't need this workaround anymore and the regular `as`/`is` casts can be used again.

Now the runtime casts doesn't show up prominently in compile-time profiling data anymore - even with a host compiler which doesn't implement fast type checks, yet.

rdar://173916206
2026-04-30 17:53:39 +02:00
Doug Gregor 08fa11ecd6 Merge pull request #88678 from DougGregor/embedded-metatypes
[Embedded] Lift the restriction on the use of metatypes in Embedded Swift
2026-04-28 13:01:27 -07: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
Doug Gregor 46389f7d7e [Embedded] Start allowing metatypes in Embedded Swift
Now that we have generalized existentials in Embedded Swift, we also
have all of the infrastructure for metatypes. They're lazily
constructed on an as-needed basis, but otherwise work the same way as
in non-Embedded Swift.

Fixes rdar://145706221.
2026-04-27 14:02:03 -07:00
John McCall 58842cb584 Merge pull request #88373 from rjmccall/alloc-pack-metadata-stack-nesting
Allow alloc_pack_metadata to be marked as [non_nested]
2026-04-09 12:27:03 -04:00
John McCall 9b6777ff59 Allow alloc_pack_metadata to be marked as [non_nested].
This is inserted by SIL passes and so may not always be properly nested
with respect to non-unreorderable allocations such as async lets.
2026-04-08 17:56:47 -04:00
Erik Eckstein b18ba61e89 Optimizer: natively implement Instruction.isDeinitBarrier in swift
No need to bridge to the C++ implementation, because the swift implementation is very simple
2026-04-08 21:34:43 +02:00
Erik Eckstein 094e6d3481 Optimizer: fix deinit barrier detection for instructions which access memory via a pointer
The original implementation of `mayAccessPointer` did look through `address_to_pointer` - `pointer_to_address` pairs and therefore not detect such pointers.

Fixes a miscompile
rdar://174268466
2026-04-08 21:34:43 +02:00
Erik Eckstein e5a259415a SIL: mark instruction protocols as @_semantics("fast_cast")
This allows fast casting and improves compile time significantly

rdar://173916206
2026-04-03 07:49:36 +02:00
Erik Eckstein e1bb4f874f cosmetic: add a missing newline in Function.swift 2026-04-03 07:49:36 +02:00
Erik Eckstein 6d8aa71814 SIL: add conformance entries to SILVTable
Conformance entries are used for fast conformance lookup, which doesn't need to query the runtime's conformance lookup table.
A conformance entry specifies if the class conforms or does not conform to a protocol.
At runtime, a type cast instruction to an existential can directly load the witness table pointer from the VTable.
If null, the class does not conform to the protocol.
2026-04-03 07:49:33 +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 dd4f3073ca DestroyHoisting: add a complexity limit for very large functions
For very large functions this optimization can run into noticeable quadratic behavior.
Therefore, ignore functions with more than 100000 SIL instructions.
This limit is large enough to not affect most of real-world SIL functions.
2026-03-16 16:12:28 +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
eeckstein 8d8ca12f35 Merge pull request #87766 from eeckstein/ossa-optimizer-improvements
OSSA related optimization improvements
2026-03-11 06:40:47 +01:00
Erik Eckstein ce69b35a52 SIL: remove the now unused Context.getSpecializedConformance API 2026-03-10 13:22:59 +01:00
Erik Eckstein 0efc9a92fa SIL: add Builder.createFixLifetime 2026-03-10 07:56:50 +01:00
Erik Eckstein b449b8c7a1 SIL: fix PartialApplyInst.isNested
* All SIL modifications must go through a `MutatingContext`. Therefore replace the simple setter for `isNested` with `set(isNested:, context)`
* It's better to add a `isNested` parameter for `Builder.createPartialApply` than to set it after each construction of a `partial_apply`, which can easily be missed.
2026-03-09 18:04:37 +01:00
John McCall 374e3d37f0 Allow partial_apply [on_stack] to be flagged [non_nested]. 2026-03-06 03:15:28 -05:00
Alejandro Alonso 4d1d688365 Merge pull request #87336 from Azoy/ensure-end-borrow
[SILCombine] Ensure we emit an end_borrow after simplifying init_borrow_addr
2026-02-23 20:34:53 -08:00
Erik Eckstein a03ac54643 Cloner: ignore type-dependent operands when recursively cloning instructions
Fixes a crash
2026-02-20 18:28:12 +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 acd5227639 SIL: add isDestructive and mayBeDestructive to UncheckedTakeEnumDataAddrInst 2026-02-11 06:43:46 +01:00
Erik Eckstein 12a798de3a SIL: improve pushPredecessors and pushSuccessors of InstructionWorklist
* add a `isTransparent` closure argument to speed up iteration for transparent blocks.
* add documentation and tests
2026-02-11 06:43:45 +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 f2b55335c4 SIL: add Instruction.set(location:) 2026-01-28 17:54:37 +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 0f3ddfbcc8 Merge pull request #86545 from jckarter/builtin-borrow
`Builtin.Borrow` implementation
2026-01-26 07:32:31 -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 2f02c7cda3 SIL: Introduce instructions for forming and dereferencing Builtin.Borrow.
Since after address lowering, `Borrow` can remain loadable with a known-
layout address-only referent, we need instructions that handle three
forms:

- borrow and referent are both loadable values
- borrow is a value, but referent is address-only
- borrow and referent are both address-only
2026-01-23 08:02:01 -08:00
Erik Eckstein 535a58e3fb SIL: assume a read-effect for unused indirect arguments
Even if an indirect argument is unused, pretend that the function reads from it.
If the unused argument is passed to another generic function and that function is specialized,
the argument may be re-abstracted and the specializer inserts a load from the indirect argument.
Therefore we must be prepared that unused indirect argument might get loaded from at some time.

Fixes a compiler crash
rdar://168623362
2026-01-23 15:58:23 +01:00
Erik Eckstein 54347dbfd7 SIL Verifier: enable a check for end-borrows
This check requires complete OSSA lifetimes
2026-01-22 17:41:48 +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 e2ddbf79f0 SIL: fix the corner case of an empty BasicBlockRange
If no block was ever inserted in a BasicBlockRange, the "inclusive" range should be empty and not contain the "begin" block.
2026-01-22 17:41:21 +01:00
Erik Eckstein 1e476700af SIL: add Builder.createExtendLifetime and add isDeadEnd to createDestroyValue 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 87dc1c5d8b SIL verifier: accept "owned" ownership for borrowed-from's enclosing values
"none" is like "owned" and can happen e.g. if a non-trivial enum is constructed with a trivial case:
```
  %1 = enum $Optional<AnyObject>, #Optional.none!enumelt   // ownership: none
  ...
  %3 = borrowed %phi from (%1)
```

Fix a false verification error
https://github.com/swiftlang/swift/issues/86407
rdar://167833469
2026-01-12 08:56:31 +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
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
Erik Eckstein 6ce2df2ed1 SIL Verifier: workaround a MoveOnlyChecker pass bug
The MoveOnlyChecker is inserting a `destroy_addr` in a read-only access scope, which is illegal.
Relax the verification of read-only access scope by only looking at dynamic scopes.

Fixes a verifier crash.
rdar://166896665
2025-12-22 10:57:41 +01: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 439bda67c8 SIL: add Type.isHeapObjectReferenceType 2025-12-19 17:43:59 +01:00