Commit Graph

106 Commits

Author SHA1 Message Date
Emil Pedersen 07d542e6f9 [DebugInfo] Implement SILCloner support for debug basic blocks
Assisted-by: Claude
2026-05-13 16:03:53 +01: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
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
Slava Pestov 819738c83e AST: Rename mapTypeIntoContext() => mapTypeIntoEnvironment(), mapTypeOutOfContext() => mapTypeOutOfEnvironment() 2025-11-12 14:48:19 -05:00
Anton Korobeynikov 89a7663f1d [AutoDiff] Initial support for differentiation of throwing functions (#82653)
This adds initial support for differentiation of functions that may produce `Error` result. 

Essentially we wrap the pullback into `Optional` and emit a diamond-shape control flow pattern depending on whether the pullback value is available or not. VJP emission was modified to accommodate for this. In addition to this, some additional tricks are required as `try_apply` result is not available in the instruction parent block, it is available in normal successor basic block.

As a result we can now:
- differentiate an active `try_apply` result (that would be produced from `do ... try .. catch` constructions)
- `try_apply` when error result is unreachable (usually `try!` and similar source code constructs)
- Support (some) throwing functions with builtin differentiation operators. stdlib change will follow. Though we cannot support typed throws here (yet)
- Correctly propagate error types during currying around differentiable functions as well as type-checking for `@derivative(of:)` attribute, so we can register custom derivatives for functions producing error result
- Added custom derivative for `Optional.??` operator (note that support here is not yet complete as we cannot differentiate through autoclosures, so `x ?? y` works only if `y` is not active, e.g. a constant value).

Some fixes here and there
2025-11-06 13:12:43 -08:00
Erik Eckstein ecf7747335 autodiff: support the new array literal initialization pattern 2025-10-10 14:20:36 +02:00
Anton Korobeynikov 7668666ad2 Support differentiation of wrapped value modify accessors (#78794)
Some fixes for coroutines with normal results and `partial_apply` of coroutines were required.

Fixes #55084
2025-09-10 02:30:26 -07:00
Doug Gregor bc4cf1236b [SIL] Generalize CastingIsolatedConformances to CheckedCastInstOptions
We are going to need to add more flags to the various checked cast
instructions. Generalize the CastingIsolatedConformances bit in all of
these SIL instructions to an "options" struct that's easier to extend.

Precursor to rdar://152335805.
2025-06-04 17:12:28 -07:00
Anton Korobeynikov 799e0f81b0 [AutoDiff] Correct propagate adjoints for array literal values (#81676)
Fixes #81607
2025-05-22 03:03:28 -07:00
Anton Korobeynikov bc94ac3342 [AutoDiff] Better diagnose non-differentiability for throwing functions (#81669)
Fixes #81608
2025-05-21 09:13:18 -07:00
Daniil Kovalev 5d0bfed9e8 [AutoDiff] Fix adjoints for loop-local active values (#78374)
Fixes #78264
2025-04-15 06:49:15 -07:00
Doug Gregor e0b52cd20e [SIL] Extend checked-cast instructions with "prohibit isolated conformances" flag
When performing a dynamic cast to an existential type that satisfies
(Metatype)Sendable, it is unsafe to allow isolated conformances of any
kind to satisfy protocol requirements for the existential. Identify
these cases and mark the corresponding cast instructions with a new flag,
`[prohibit_isolated_conformances]` that will be used to indicate to the
runtime that isolated conformances need to be rejected.
2025-03-26 22:31:47 -07:00
Anton Korobeynikov 1e7a1d91fc Emit reabstraction thunks for implicit conversions between T.TangentType and Optional<T>.TangentType (#78076) 2025-02-05 20:57:52 -08:00
Anthony Latsis a84dfc8387 [Gardening] Fix some set but not used variables 2025-01-30 21:34:38 +00:00
Daniil Kovalev 0ba886d409 [AutoDiff] Fix adjoint for move_value (#78286)
Since `move_value` is a destroying operation, the adjoint of `y = move_value x` should be `adj[x] += adj[y]; adj[y] = 0` instead of just `adj[x] += adj[y]`.
2025-01-08 00:42:54 -08:00
Daniil Kovalev 95f34ebaca [AutoDiff] Fix derivative for array literal with tuple_element_addr elts (#78355)
The `adjIndex` was not incremented due to missed `remapType`.

Fixes #54214
2025-01-06 16:11:54 -08:00
Anton Korobeynikov 216111172e Explicitly use minimal type expansion for autodiff-related types (e.g. parameters and pullback result types) (#77831)
As autodiff happens on function types it is not in general possible to determine the real expansion context of the function being differentiated. Use of minimal context is a conservative approach that should work even when libraty evolution mode is enabled.

Fixes #55179
2024-12-02 15:02:09 -08:00
Slava Pestov 375363a473 AST: Move global conformance lookup entry points to ConformanceLookup.h 2024-08-08 23:35:58 -04:00
Anton Korobeynikov a751b076b6 Fixes inject_enum_addr handling: (#75459)
- Ensure it really accumulates the adjoint buffer
- Handle Optional.none case when there is no value to propagate to

Fixes #75280
2024-07-26 17:04:26 -07:00
Anton Korobeynikov 9d63e0fa36 [AutoDiff] Correctly propagate optional adjoint through switch_enum (#74985)
Fixes #74978
2024-07-11 21:48:00 -07:00
Slava Pestov 86d567f95a AST: ModuleDecl::lookupConformance() is a static method 2024-07-06 12:05:47 -04:00
Slava Pestov fae01d9776 AST: Remove ModuleDecl parameter from more places 2024-07-06 12:05:46 -04:00
Anton Korobeynikov 97ba96b8d8 [AutoDiff] Implement active Optional differentiation (#74977)
Fixes #74972
2024-07-04 22:27:23 -07:00
Anton Korobeynikov f8141e27b1 Ensure we are materializing adjoint value into buffer correctly for optionals: (#74964)
- Ue enum $Optional<T.TangentVector>, #Optional.some!enumelt, %wrappedAdjoint : $T for objects
- Use inject_enum_addr %optArgBuf : $*Optional<T.TangentVector>, #Optional.some!enumelt for addresses

Fixes #74841
2024-07-04 20:53:59 -07:00
Tim Kientzle 1d961ba22d Add #include "swift/Basic/Assertions.h" to a lot of source files
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
2024-06-05 19:37:30 -07:00
Slava Pestov 7d0e041572 AutoDiff: Local workaround for invariant violation 2024-05-16 23:00:44 -04:00
Emil Pedersen 9c78317a77 [DebugInfo] [AutoDiff] Strip var info for tangents 2024-05-10 16:12:56 -07:00
Anton Korobeynikov c7a216058f [AutoDiff] First cut of coroutines differentiation (#71461)
This PR implements first set of changes required to support autodiff for coroutines. It mostly targeted to `_modify` accessors in standard library (and beyond), but overall implementation is quite generic.

There are some specifics of implementation and known limitations:
 - Only `@yield_once` coroutines are naturally supported
 - VJP is a coroutine itself: it yields the results *and* returns a pullback closure as a normal return. This allows us to capture values produced in resume part of a coroutine (this is required for defers and other cleanups / commits)
 - Pullback is a coroutine, we assume that coroutine cannot abort and therefore we execute the original coroutine in reverse from return via yield and then back to the entry
 - It seems there is no semantically sane way to support `_read` coroutines (as we will need to "accept" adjoints via yields), therefore only coroutines with inout yields are supported (`_modify` accessors). Pullbacks of such coroutines take adjoint buffer as input argument, yield this buffer (to accumulate adjoint values in the caller) and finally return the adjoints indirectly.
 - Coroutines (as opposed to normal functions) are not first-class values: there is no AST type for them, one cannot e.g. store them into tuples, etc. So, everywhere where AST type is required, we have to hack around.
 - As there is no AST type for coroutines, there is no way one could register custom derivative for coroutines. So far only compiler-produced derivatives are supported
 - There are lots of common things wrt normal function apply's, but still there are subtle but important differences. I tried to organize the code to enable code reuse, still it was not always possible, so some code duplication could be seen
 - The order of how pullback closures are produced in VJP is a bit different: for normal apply's VJP produces both value and pullback closure via a single nested VJP apply. This is not so anymore with coroutine VJP's: yielded values are produced at `begin_apply` site and pullback closure is available only from `end_apply`, so we need to track the order in which pullbacks are produced (and arrange consumption of the values accordingly – effectively delay them)
 - On the way some complementary changes were required in e.g. mangler / demangler

This patch covers the generation of derivatives up to SIL level, however, it is not enough as codegen of `partial_apply` of a coroutine is completely broken. The fix for this will be submitted separately as it is not directly autodiff-related.

---------

Co-authored-by: Andrew Savonichev <andrew.savonichev@gmail.com>
Co-authored-by: Richard Wei <rxwei@apple.com>
2024-04-04 17:24:55 -07:00
Konrad `ktoso` Malawski 6132386371 [Distributed] Complete handling of protocol calls and witnesses using adjusted mangling scheme (#72416) 2024-03-23 23:54:23 +09:00
Emil Pedersen ca8c6d4270 [DebugInfo] [AutoDiff] Fix empty debug variables being created 2024-03-20 15:35:52 -07:00
Ben Barham ef8825bfe6 Migrate llvm::Optional to std::optional
LLVM has removed llvm::Optional, move over to std::optional. Also
clang-format to fix up all the renamed #includes.
2024-02-21 11:20:06 -08:00
Anton Korobeynikov f5cce4784f Make autdiff more robust in presence of unreachable blocks (#71356)
Unreachable blocks possess some challenges to autodiff since in reverse pass (pullback generation) we need to execute the function backwards, pushing the values from return BB back to entry block. As a result, unreachable blocks might become reachable from the return BB and this might cause all kind of issues.
2024-02-03 08:33:36 -08:00
Meghana Gupta 86b651330b Revert "Merge pull request #69807 from apple/revert-69450-uninarrayfix"
This reverts commit cabb5e109f, reversing
changes made to 09688abb02.
2023-12-06 08:29:50 -08:00
Mishal Shah e8de333daf Revert "Add a mark_dependence while emitting SIL for uninitialized array allocation " 2023-11-12 09:43:13 -08:00
Meghana Gupta baebc7d00b Handle mark_dependence in Differentiation 2023-10-31 11:07:36 -07:00
swift-ci a41a67e7cb Merge remote-tracking branch 'origin/main' into rebranch 2023-09-22 01:43:50 -07:00
Andrew Savonichev 2f7b42ceaf [AutoDiff] Handle init_enum_data_addr and inject_enum_addr for Optional (#68300)
Optional's `init_enum_data_addr` and `inject_enum_addr` instructions are generated in presence of non-loadable Optional values. The compiler used to treat these instructions as inactive, and this resulted in silent run-time
issues described in #64223.

The patch marks `init_enum_data_addr` as "active" if its Optional operand is also active, and in PullbackCloner we differentiate through it and the related `inject_enum_addr`.

However, we only determine this relation in simple cases when both instructions are in the same block. There is no def-use relation between them (both take the same Optional operand), so if there is more than one set of instructions
operating on the same Optional, or there is some control flow, we currently bail out.

In PullbackCloner, we walk over instructions in reverse order and start from `inject_enum_addr` and its `Optional<Wrapped>.TangentVector` operand. Assuming that is is already initialized, we emit an `unchecked_take_enum_data_addr` and set it as the adjoint buffer of `init_enum_data_addr`. The Optional value is
invalidated, and we have to destroy the enum data address later when we reach `init_enum_data_addr`.
2023-09-22 01:07:16 -07:00
swift-ci c2d0ed607a Merge remote-tracking branch 'origin/main' into rebranch 2023-09-19 11:33:34 -07:00
Erik Eckstein 5bc036661c SIL optimizer: add the LetPropertyLowering pass
It lowers let property accesses of classes.
Lowering consists of two tasks:

* In class initializers, insert `end_init_let_ref` instructions at places where all let-fields are initialized.
  This strictly separates the life-range of the class into a region where let fields are still written during
  initialization and a region where let fields are truly immutable.

* Add the `[immutable]` flag to all `ref_element_addr` instructions (for let-fields) which are in the "immutable"
  region. This includes the region after an inserted `end_init_let_ref` in an class initializer, but also all
  let-field accesses in other functions than the initializer and the destructor.

This pass should run after DefiniteInitialization but before RawSILInstLowering (because it relies on `mark_uninitialized` still present in the class initializer).
Note that it's not mandatory to run this pass. If it doesn't run, SIL is still correct.

Simplified example (after lowering):

  bb0(%0 : @owned C):                           // = self of the class initializer
    %1 = mark_uninitialized %0
    %2 = ref_element_addr %1, #C.l              // a let-field
    store %init_value to %2
    %3 = end_init_let_ref %1                    // inserted by lowering
    %4 = ref_element_addr [immutable] %3, #C.l  // set to immutable by lowering
    %5 = load %4
2023-09-19 15:10:30 +02:00
swift-ci 84738eeae9 Merge remote-tracking branch 'origin/main' into rebranch 2023-09-12 14:34:05 -07:00
Kshitij Jain d971f125d9 [AutoDiff] Handle materializing adjoints with non-differentiable fields (#67319) 2023-09-12 14:22:41 -07:00
swift-ci 894ef02ead Merge remote-tracking branch 'origin/main' into rebranch 2023-09-01 10:56:13 -07:00
Andrew Savonichev fc640dbc02 [AutoDiff] Emit a diagnostic for non-differentiable active values (#67697)
For some values we cannot compute types for differentiation (for example,
tangent vector type), so it is better to diagnose them earlier. Otherwise we hit
assertions when generating code for such invalid values.

The LIT test is a reduced reproducer from the issue #66996. Before the patch the
compiler crashed while trying to get a tangent vector type for the following
value (partial_apply):

    %54 = function_ref @$s4null1o2ffSdAA1FV_tFSdyKXEfu0_ :
      $@convention(thin) @substituted <τ_0_0> (@inout_aliasable Double)
      -> (@out τ_0_0, @error any Error) for <Double>

    %55 = partial_apply [callee_guaranteed] %54(%2) :
      $@convention(thin) @substituted <τ_0_0> (@inout_aliasable Double)
      -> (@out τ_0_0, @error any Error) for <Double>

Now we emit a diagnostic instead.

The patch resolves issues #66996 and #63331
2023-09-01 10:48:45 -07:00
swift-ci ae4b70bf28 Merge remote-tracking branch 'origin/main' into rebranch 2023-08-04 18:59:37 -07:00
Becca Royal-Gordon 3eebc6dddb Merge branch 'main' into rebranch
# Conflicts:
#	lib/SILOptimizer/Differentiation/Common.cpp
2023-08-04 15:09:50 -07:00
Slava Pestov 9ebb5f2e03 AST: Rename VarDecl::getType() to VarDecl::getTypeInContext()
This is a futile attempt to discourage future use of getType() by
giving it a "scary" name.

We want people to use getInterfaceType() like with the other decl kinds.
2023-08-04 14:19:25 -04:00
Anton Korobeynikov 03334a8f92 [AutoDiff] Generalize handling of semantic result parameters (#67230)
Introduce the notion of "semantic result parameter". Handle differentiation of inouts via semantic result parameter abstraction. Do not consider non-wrt semantic result parameters as semantic results

Fixes #67174
2023-08-03 09:33:11 -07:00
Evan Wilde 9b61bb4b8d More llvm::Optional::transform -> swift::transform
Translating more llvm::Optional::transform calls to swift::transform.
`llvm::Optional` had a transform function that ran a lambda on the
element stored in the optional if it existed. After migrating to
std::optional under the hood, that function went away. Replacing it with
calls to swift::optional in STLExtras.h.
2023-07-25 12:28:27 -07:00
Evan Wilde 309aed4925 Add SmallSetVector replacement
llvm::SmallSetVector changed semantics
(https://reviews.llvm.org/D152497) resulting in build failures in Swift.
The old semantics allowed usage of types that did not have an
`operator==` because `SmallDenseSet` uses `DenseSetInfo<T>::isEqual` to
determine equality. The new implementation switched to using
`std::find`, which internally uses `operator==`. This type is used
pretty frequently with `swift::Type`, which intentionally deletes
`operator==` as it is not the canonical type and therefore cannot be
compared in normal circumstances.

This patch adds a new type-alias to the Swift namespace that provides
the old semantic behavior for `SmallSetVector`. I've also gone through
and replaced usages of `llvm::SmallSetVector` with the
`Swift::SmallSetVector` in places where we're storing a type that
doesn't implement or explicitly deletes `operator==`. The changes to
`llvm::SmallSetVector` should improve compile-time performance, so I
left the `llvm::SmallSetVector` where possible.
2023-07-25 12:28:27 -07:00
Nate Chandler 19f82601d4 [PullbackCloner] Handled move_value instructions.
The handling is just the same as for begin_borrow and copy_value insts.
2023-07-12 10:34:21 -07:00