Commit Graph

1357 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
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
Andrew Trick 2dca2e48c4 Merge pull request #88980 from atrick/fix-immortal-init
LifetimeDependenceDiagnostics: calls with no deps are immortal
2026-05-09 14:22:17 -07:00
Andrew Trick f41daa2087 Merge pull request #88968 from atrick/fix-makeborrow-escape
LifetimeDependenceDiagnostics: add Builtin.makeBorrow support
2026-05-08 17:20:46 -07:00
Andrew Trick 4845b0bf4d LifetimeDependenceDiagnostics: calls with no deps are immortal
Fix lifetime diagnostics to consider an implicit initializer of a ~Escapable
type to be implicitly immortal. Required to handle Optional<~Escapable> stored
properties, such as:

struct Foo<Element: ~Escapable>: ~Escapable {
  var element: Element?

  @_lifetime(borrow c)
  init<C>(c: borrowing C) {
    // error: Lifetime-dependent variable 'self' escapes its scope
  }
}

The fix is simply to remove a temporary safeguard that I put in place to
compensate for our incomplete closure lifetimes. We now have the complete
representation of lifetimes on closures, so don't need the safeguard.

Representationally, a function that returns a ~Escapable value but has no
dependendencies is immortal. This was always the intended design, but the
temporary safeguard treated these cases as implicitly bound to some local scope.

Removing this safeguard has the effect of:

- Variable intialization is immortal (it cannot depend on anything by
  definition). The safety of the initializer is checked inside the implementation
  of those expressions rather than the caller.

- Empty ~Escapable types have an implicit immortal initializer (why not?)

- Calls to a function with @_unsafeNonescapableResult but no @_lifetime
  annotation produce an immortal value. This is reasonable, and we want to
  deprecate this attribute as soon as possible anyway. It is not for general use.

This is currently blocking usage of BorrowingSequence, such as a hypothetical BorrowingSequenceMapSequenceIterator.

Fixes rdar://176561897 ([nonescapable] initialization of Optional fields reports
a lifetime escape)
2026-05-08 16:47:56 -07:00
Andrew Trick 1ed083be0c LifetimeDependenceDiagnostics: add Builtin.makeBorrow support
Code like this currently looks like a lifetime escape:

  struct Ref<T: ~Copyable & ~Escapable>: ~Escapable {
    private let ref: Builtin.Borrow<T>

    @_lifetime(borrow target)
    init(_ target: borrowing T) {
      self.ref = Builtin.makeBorrow(target)
    }
  }

This is blocking the implementation of `Ref<~Escapable>`.

Fixes rdar://176564359 ([nonescapable] support Builtin.makeBorrow in
lifetime diagnostics)
2026-05-08 12:26:42 -07:00
Meghana Gupta ebd4d11225 Merge pull request #88847 from meg-gupta/fixeaborrow
Update SIL utilities for address results from borrow accessors
2026-05-07 20:57:06 -07:00
Daniil Kovalev a9a74aa8fe [AutoDiff] Find partial_apply of pullback w/o loop in closure spec pass (#88911)
Currently, AutoDiff Closure Specialization pass iterates over all VJP
instructions and checks each of them against a set of conditions which
`partial_apply` of pullback must satisfy.

This logic could be re-implemented w/o loop, checking conditions in
opposite direction, starting from `return` instruction and transitively
going to defining instructions of operands (`tuple` and `partial_apply`
for the desired pullback case).
2026-05-07 22:52:48 +00:00
Erik Eckstein ba0b04559e ComputeEscapeEffects: add a complexity limit for escape analysis of function arguments
Similar to what we do in AliasAnalysis

related to rdar://175999887
2026-05-07 09:52:14 +02:00
Erik Eckstein bdc1c4d34f AliasAnalysis: use a complexity limit in getApplyEffect
Like we do in other parts of AliasAnalysis which call into escape analysis.

Fixes a compile time problem.
rdar://175937160
2026-05-07 09:52:14 +02:00
Gábor Horváth cfeda37650 Merge pull request #88622 from Xazax-hun/tsan-effects-modeled
[SILOptimizer] Correctly compute the effects of TSan instrumentation
2026-05-06 12:20:31 +01:00
Meghana Gupta ff7724900f Fix EscapeAnalysis for address results of borrow accessors
Update escape walker to recognize that the returned address from borrow accessors
are dependent on the parameter.
2026-05-05 12:28:23 -07: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 5fadeb59d9 AliasAnalysis: speed up memory effect computation for builtin instructions
If a builtin has no memory effects defined (which is the case for most builtins) we don't need to do escape analysis to compute memory effects.
2026-04-30 17:53:40 +02:00
Erik Eckstein 7204a1524b EscapeUtils: use isFullApplySite instead of listing all conforming instruction classes 2026-04-30 17:53:39 +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
Gabor Horvath 12b6809813 [SILOptimizer] Correctly compute the effects of TSan instrumentation
Passing a C++ object to the TSanInOutAccess builtin resulted in an extra
temporary copy. This copy was not optimized out because the semantics of this
builtin was not understood by the optimizer. Teaching the utils that this
intrinsic does not actually modify the object, does not escape it,
and does not read it lets the optimizer eliminate this copy.

Strictly speaking, the test code that uses interop is not safe/correct,
this is why it had a lifetime issue.

rdar://173921363
2026-04-30 11:21:17 +01: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
Meghana Gupta 81cc84e06f Merge pull request #88648 from meg-gupta/fixanalysisinvalidation
Correctly invalidate analyses after keypath optimization
2026-04-24 19:57:00 -07:00
Meghana Gupta 784da0a090 Correctly invalidate analyses after keypath optimization
Keypath simplification can create new basic blocks when projecting
optional chain components (OptionalChainProjector splits the block and creates new conditional branches).
However, the Swift-side tryOptimizeKeypath was not notifying the pass manager about
CFG or instruction changes, leaving analyses like the dominator tree stale.
Fix this by calling notifyBranchesChanged() and notifyInstructionsChanged()
when tryOptimizeKeypath succeeds.
2026-04-24 09:43:42 -07:00
Andrew Trick 265b42d6b6 Merge pull request #88617 from atrick/simplify-load-borrow
Enable load_borrow simplification at -Onone
2026-04-23 10:20:16 -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
Meghana Gupta c431f654c8 Don't optimize alloc_stack with dynamic_lifetime in TempLValueElimination
The [dynamic_lifetime] attribute represents that the stack location's initialization state is tracked dynamically via a boolean flag — it may be uninitialized at certain program points. TempLValueElimination pass can replace an alloc_stack [dynamic_lifetime] with a destination alloc_stack that does not have dynamic_lifetime. This results in invalid SIL which triggers verifier errors due to lifetime mismatches in some program paths in ossa.

This PR fixes this issue by bailing out of TempLValueElimination for alloc_stack [dynamic_lifetime] in ossa.

Resolves rdar://175097584
2026-04-21 12:22:18 -07:00
Doug Gregor aad51cab01 [Embedded] Remove the ability to disable existentials in Embedded Swift
Support for existentials in Embedded Swift has been available for a
little while now and appears to be solid. Remove the ability to disable
them (via `-disable-experimental-feature EmbeddedExistentials`), both
because it simplifies the code and because it's an ABI break to
disable the feature.
2026-04-17 17:38:01 -07:00
Max Desiatov b589f05c10 Support untyped throws in Embedded Swift (#87617)
**Explanation**: We would like untyped throws to be available in Embedded Swift when system allocator is available.
**Scope**: limited to Embedded Swift.
**Risk**: low due to isolated scope, additive nature of the change, and no adoption of untyped throws in Embedded Swift so far.
**Testing**: added new lit tests.
**Issue**: rdar://171325402
2026-04-14 18:05:14 +01:00
eeckstein 668fb767b6 Merge pull request #88386 from eeckstein/fix-cond-fail-opt
Optimizer: fix optimization of unconditional `cond_fail`s
2026-04-10 07:15:53 +02: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 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
Meghana Gupta e260417aae Merge pull request #88278 from meg-gupta/fixea
Fix escape analysis for pointer_to_address
2026-04-03 12:53:30 -07:00
Andrew Trick d889cac8e5 Merge pull request #88212 from atrick/fix-builtin-borrow-ossa
Fix Builtin.Borrow<T> OSSA representation
2026-04-03 12:09:24 -07:00
Andrew Trick 7dc30f6a3d Merge pull request #88265 from atrick/fix-deinit-devirt
Fix DeinitDevirtualizer to handle non-generic deinitializer function
2026-04-03 08:40:33 -07:00
Erik Eckstein 080f9e6a81 Optimizer: add the ConformanceCheckOptimization optimization pass
Optimizes protocol conformance checking by pre-populating vtables with conformance information for "fast-cast" protocols that have superclass constraints.

This optimization works by:

1. Identifying classes that are eligible for optimization (have fixed metadata layout, are not open access, and belong to the current module)

2. Finding protocols, enabled for fast casting nad that have superclass constraints and belong to the current module

3. Pre-computing conformance checks for these protocols and storing the results directly in the vtable, eliminating the need for runtime conformance lookups
2026-04-03 07:49:35 +02:00
Erik Eckstein b97b3640f9 Optimizer: add some Context APIs
* `var isWholeModule`
* `var moduleDecl`
* `ClassDecl.hasFixedMetadataLayout`
2026-04-03 07:49:34 +02:00
Meghana Gupta 7b2d5fb212 Fix escape analysis for pointer_to_address
When a `pointer_to_address` reinterprets the type (i.e. the address type
differs from the originating `address_to_pointer`), the accumulated
projection path is no longer meaningful. Use `anyValueFields` to be
conservative in both the walk-down and walk-up directions.

Without this fix, escape analysis could incorrectly conclude that a store
to an `alloc_stack` does not escape when it is read back through a
type-reinterpreting `pointer_to_address`, causing DeadStoreElimination
to illegally remove the store.

rdar://171841812
2026-04-02 11:21:45 -07:00
Andrew Trick 09c5e7912d Fix Builtin.Borrow<T> OSSA representation
Builtin.Borrow<T> does not introduce a new borrow scope at the level of
SILValue. A SILValue that introduces a borrow scope is expected to be tracked by
OSSA--it cannot produce a trivial value. That borrow scope is expected to have a
scope-ending operation on all paths.

It's not clear how OSSA utilities and passes will handle the previous
implementation which doesn't honor those invariants. Fixing this is needed to
rely on Builtin.Borrow<T> more extensively.

Instead, treat the make_borrow instruction like an instantenous use. It produces
a Builtin.Borrow<T> value with ownership None. That value is completely ignored
by OSSA and does not contribute to liveness of the incoming value.

This is at least a coherent representation, but still incredibly dangerous. The
validity of SIL depends on the programmer using Builtin.makeBorrow
correctly. Add a TODO for implementing verification.

Fixes rdar://173800290 (Fix Builtin.Borrow<T> OSSA representation)
2026-04-01 23:39:55 -07: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
Andrew Trick 401d2ee072 Fix DeinitDevirtualizer to handle non-generic deinitializer function
Avoid passing an invalid substitution map into createApply.

Required conditions (from the bug report):
1. `~Copyable` struct with user-defined `deinit`
2. Nested inside a constrained extension where all generic parameters are concrete
3. A `destroy_value` or `destroy_addr` of the struct's value exists in some function
4. DeinitDevirtualizer runs (release-mode optimization pipeline)

Fixes rdar://173803881 ([GH:#88213] [SILOptimizer] DeinitDevirtualizer assertion
failure with ~Copyable type in all-concrete constrained extension)

Suggested by: coenttb
2026-04-01 20:56:42 -07:00
Erik Eckstein f7ff9c72c5 ObjectOutliner: don't outline objects in external functions because this would "duplicate" singletons
Fixes a miscompile
rdar://172766879
2026-03-29 13:01:45 +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
Peter Rong 2cc9a2f376 [SILOptimizer] Test ConstantCapturePropagation ODR violation with generic closures (#87916)
## Summary
This PR fixes the ODR violation detailed in
https://github.com/swiftlang/swift/issues/87917

## Impl

When specializeClosure determines the specialized closure remains
generic (`isGeneric == true`), clone the body without applying type
substitutions, and use `partial_apply` with the substitution map at the
call site instead of `thin_to_thick_function`. The body stays generic
with type parameters like `$*Optional<Self>`, which is correct since all
callers share the same shared symbol and apply their own concrete types
through the substitution map on the `partial_apply`.

## Tests
Add SIL and executable tests demonstrating that
ConstantCapturePropagation produces an ODR violation when specializing
generic closures with different concrete type substitutions but the same
constant captures.

The SIL test provides a minimal reproducer: two callers instantiate the
same generic closure with UInt8 and Int respectively, both capturing
constant `radix=10`. With `-enable-sil-verify-all`, the verifier catches
the type mismatch in the specialized function body.

The executable test exercises the real-world scenario through
`FixedWidthInteger.init?(_:radix:)`, where the miscompile causes Int and
`Int32` parsing to return garbage values because the closure body was
baked with `UInt8` type metadata.

Fixes: https://github.com/swiftlang/swift/issues/87917

[Assisted-by](https://t.ly/Dkjjk): [Claude Opus
4.6](https://www.anthropic.com/news/claude-opus-4-6)

cc @drodriguez @kyulee-com
2026-03-23 13:40:38 -07:00
eeckstein ef3d132575 Merge pull request #87977 from eeckstein/fix-constant-capture-propagation
ConstantCapturePropagation: fix two problems with function type representation
2026-03-20 15:30:18 +01:00
Erik Eckstein 6a02551361 ConstantCapturePropagation: fix two problems with function type representation
* convert "method"s to "thin" functions: We are removing arguments from the original function. If the removed argument is the "self" argument, the specialized function cannot be a "method" anymore.

* don't create `thin_to_thick_function` instructions for non-thin functions. Instead keep it a `partial_apply`

Fixes a SIL verifier crash.
rdar://172774069
2026-03-20 09:39:58 +01:00
Erik Eckstein 8110746b2e TempRValueElimination: delete debug_value instructions which are outside of the stack location's liverange
We already move `debug_value` instructions into the liverange in such cases.
But we didn't do this if the `debug_value`'s operand is a projection of the `alloc_stack`.
The fix is to delete such `debug_value` instructions. It's not ideal, however this is a very rare case.
Also, we need to delete dead projection instructions.
Dead projection instructions can appear outside of the liverange in case they were only used by an (now deleted) `debug_value` or `destroy_addr` instruction.

Fixes a SIL ownership verification error
https://github.com/swiftlang/swift/issues/87980
rdar://172950559
2026-03-20 09:36:42 +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