Commit Graph

1719 Commits

Author SHA1 Message Date
Erik Eckstein
5104c317ca TempRValueElimination: fix a problem with non-copyable types
In case of a non-copyable type the final destroy (or take) of a stack location can be missing if the value has only trivial fields.
The optimization inserted a `destroy_addr` in this case although it wasn't there before.

Beside fixing this problem I also refactored the code a bit to make it more readable.
2025-10-10 21:37:27 +02:00
Andrew Trick
d653b0ccd0 Merge pull request #84739 from atrick/lifedep-unsafeaddress
LifetimeDependenceDefUseWalker: store to unsafeMutableAddress
2025-10-09 18:40:32 -07: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
87a9d4ca2e Optimizer: notify that operand instructions of a deleted instruction have changed
This makes sure that instruction simplification doesn't terminate too early, missing some optimization opportunities.
2025-10-08 17:48:37 +02:00
Andrew Trick
4378995a78 LifetimeDependenceDefUseWalker: store to unsafeMutableAddress
Handle storing to a mutable property implemented as unsafeMutableAddress. In
SIL, the stored address comes from pointer_to_address. Recognize the addressor
pattern and handle the store as if it writes to a regular property of 'self'.

Required for UnsafePointer<~Escapable>.pointee.
2025-10-07 13:22:27 -07:00
Andrew Trick
4a7895e15b SwiftCompilerSources: bridge Function.isAddressor() 2025-10-07 10:44:42 -07:00
Andrew Trick
0d496b5404 SwiftCompilerSources: bridge Type.unsafePointerElementType 2025-10-07 10:44:42 -07:00
eeckstein
757de6e2a6 Merge pull request #84711 from eeckstein/fix-licm
LoopInvariantCodeMotion: fix check for hoisting `load_borrow` instructions
2025-10-07 11:40:29 +02:00
eeckstein
401a2ac2bc Merge pull request #84704 from eeckstein/closure-specialization
ClosureSpecialization: support for OSSA and a big overhaul
2025-10-07 06:59:08 +02:00
Andrew Trick
c2171ea9b0 Merge pull request #84703 from atrick/lifedep-diag-init
Lifetimes: add a diagnostic note for implicit accessors
2025-10-06 12:29:51 -07:00
Erik Eckstein
55cdc31936 LoopInvariantCodeMotion: a small refactoring
which is now possible as we removed the "fallthrough" from the previous case
2025-10-06 17:57:12 +02:00
Erik Eckstein
e88096e971 LoopInvariantCodeMotion: fix check for hoisting load_borrow instructions
We need to check aliasing for all kind of side-effect instructions, not just stores and destroys
2025-10-06 17:57:12 +02:00
Erik Eckstein
df20d36255 ClosureSpecialization: support for OSSA and a big overhaul
Beside supporting OSSA, this change significantly simplifies the pass.
The main change is that instead of starting at a closure (e.g. `partial_apply`) and finding all call sites, we now start at a call site and look for closures for all arguments. This makes a lot of things much simpler, e.g. not so many intermediate data structures are required to track all the states.

I needed to remove the 3 unit tests because the things those tests were testing are not there anymore. However, the pass is tested with a lot of sil tests (and I added quite a few), which should give good test coverage.

The old ClosureSpecializer pass is still kept in place, because at that point in the pipeline we don't have OSSA, yet. Once we have that, we can replace the old pass withe the new one.
However, the autodiff closure specializer already runs in the OSSA pipeline and there the new changes take effect.
2025-10-06 12:02:48 +02:00
Erik Eckstein
89bba668e2 Mangling: add a closure specialization mangling for arguments which specialize for the same closure as a previous argument
For example:
```
  %1 = partial_apply %closure
  apply %f(%1, %1)    // first argument: `.closure(%1)`
                      // second argument: `.previousArgumentIndex(0)`
```
2025-10-06 09:47:41 +02:00
Erik Eckstein
08696eeb92 Cloner: set the cloner's builder insertion point to the entry block when creating a new entry block in the cloned function
This allows clients to directly clone specific instructions into the new entry block
2025-10-06 09:47:40 +02:00
Erik Eckstein
898b8754bf SIL: add some Instruction/Builder APIs
* `var UncheckedValueCastInst.fromValue`
* `BeginApplyInst.isNonThrowing` and `BeginApplyInst.isNonAsync`
* `Builder.createUncheckedValueCast`
2025-10-06 09:47:40 +02:00
Erik Eckstein
2cd625a367 Optimizer: add the Builder.insertCleanupAtFunctionExits utility 2025-10-06 09:47:40 +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
Andrew Trick
771e9b522e Lifetimes: add a diagnostic note for implicit accessors
Lifetime diagnostics may report an error within an implicit initializer or
accessor. The source location is misleading in these cases and causes much
consternation.
2025-10-05 20:16:44 -07:00
Andrew Trick
bed80eed72 [NFC] LifetimeDependence computeAddressRange comments and test case 2025-10-03 20:48:07 -07:00
Andrew Trick
ac31a2f619 LifetimeDependenceDiagnostics: extend temp alloc to unreachable.
When a non-Escapable value depends on the address of a trivial value, we use a
special computeAddressableRange analysis to compute the trivial value's
scope. Extend that analysis to include unreachable paths.

Fixes this pattern:

    inlineStorage.span.withUnsafeBytes

where inlineStorage is a trivial type defined in the user module. This
does not reproduce directly with InlineArray, but it is a problem for
user modules that have their own trivial wrapper around an InlineArray.

Fixes rdar://161630684 (Incorrect diagnostic: lifetime-dependent value escapes its scope)
2025-10-03 20:47:59 -07:00
Andrew Trick
7197f63ce2 Comment LifetimeDependenceScopeFixup. Explain unreachable paths. 2025-10-03 20:44:17 -07:00
Erik Eckstein
171607afa7 DeadStoreElimination: fix a corner case of storing a trivial case of a non-trivial enum
Storing a trivial enum case in a non-trivial enum must be treated like a non-trivial init or assign, e.g.
```
  %1 = enum $Optional<String>, #Optional.none!enumelt
  store %1 to [trivial] %0  // <- cannot delete this store!
  store %2 to [assign] %0
```
2025-10-02 19:20:35 +02:00
nate-chandler
5945606067 Merge pull request #84577 from nate-chandler/rdar161433604
[Optimizer] Use valid inst range to broadcast inlining changes.
2025-10-01 14:08:52 -07:00
Arnold Schwaighofer
7853ba0a7f Merge pull request #84178 from aschwaighofer/inline_always
Add experimental feature `@inline(always)`
2025-10-01 07:23:24 -07:00
Arnold Schwaighofer
25a071efc8 Add experimental feature @inline(always)
The intent for `@inline(always)` is to act as an optimization control.
The user can rely on inlining to happen or the compiler will emit an error
message.

Because function values can be dynamic (closures, protocol/class lookup)
this guarantee can only be upheld for direct function references.

In cases where the optimizer can resolve dynamic function values the
attribute shall be respected.

rdar://148608854
2025-09-30 08:36:26 -07:00
Erik Eckstein
b527020364 LoopInvariantCodeMotion: bail on split load [take]
We currently don't support split `load [take]`, i.e. `load [take]` which does _not_ load all non-trivial fields of the initial value.
2025-09-30 10:39:51 +02:00
Erik Eckstein
fc6302e3e9 LoopInvariantCodeMotion: correctly handle load [copy]
When moving loads and stores out of a loop, a `load [copy]` must be replaced by a `copy_value`.
2025-09-30 10:39:51 +02:00
Erik Eckstein
a6fb1876ef LoopInvariantCodeMotion: correctly create projections for owned values
Owned structs and tuples must be projected by `destructure_struct` and `destructure_tuple`, respectively.

rdar://161467837
2025-09-30 10:39:51 +02:00
Erik Eckstein
7bbe5c6fe2 LoopInvariantCodeMotion: don't hoist loads and stores if the memory location is not initialized at loop exits.
If the memory is not initialized at all exits, it would be wrong to insert stores at exit blocks.
2025-09-30 10:39:51 +02:00
Nate Chandler
07d75186ba [Optimizer] Don't walk to deleted.
During inlining, some instructions in the caller may be deleted.  So
when publishing this best effort list of instructions which were
"changed" during inlining, don't start from a deleted instruction.
Instead just don't publish, as already happens in other cases.

Without actually addressing
```
// TODO: get a list of cloned instructions from the `inlineFunction`
```
this is somewhat better than checking for having reached the end of the
function during the walk because that will result in falsely
broadcasting that some unchanged instructions have changed whereas this
change only results in not broadcasting which is already being done in
some cases (e.g. when a `begin_apply` is immediately followed by an
`end_apply`).
2025-09-29 20:52:18 -07:00
Nate Chandler
b62798381e [Optimizer] Don't walk from deleted.
During inlining, the apply is deleted.  So when publishing this best
effort list of which instructions were "changed" during inlining, start
from the instruction before the deleted apply.
2025-09-29 20:52:18 -07:00
Nate Chandler
36205d90d2 [Gardening] Detypo'd "inlining". 2025-09-29 13:56:29 -07:00
Erik Eckstein
273874cd59 ConstantCapturePropagation: don't propagate keypaths with multiple uses in non-OSSA
We cannot do this because we don't know where to insert the compensating release after the propagated `partial_apply`.
A required `strong_retain` may have been moved over the `partial_apply`.
Then we would release the keypath too early.

Fixes a mis-compile
rdar://161321614
2025-09-29 18:42:39 +02:00
Erik Eckstein
12626475c3 ConstantCapturePropagation: refactor Value.isConstant 2025-09-29 18:42:39 +02:00
Erik Eckstein
e3055673f4 ConstantCapturePropagation: support sub-pass bisecting 2025-09-29 18:42:39 +02:00
Kavon Farvardin
d8e23cb2d4 Merge pull request #84523 from kavon/manual-ownership/usability-fixes-4
Usability improvements for ManualOwnership, part 4
2025-09-26 06:07:31 -07:00
Kavon Farvardin
32263bb9b8 ManualOwnership: add workaround for vars
For a proof-of-concept quality feature,
we can just skip the pass causing problems until
a proper solution is implemented.
2025-09-25 15:53:18 -07:00
Michael Gottesman
c1959f8cfd Merge pull request #84516 from gottesmm/pr-c70794ebe028f9c9476b9f9b19b1c5a74a4e2e61
[cmake] Make SwiftCompilerSources support debug info in RelWithDebInfoMode and use -Os instead of -O with MinSizeRel.
2025-09-25 13:58:47 -05:00
eeckstein
16ce6b85ea Merge pull request #84511 from eeckstein/fix-init-static-globals
InitializeStaticGlobals : reapply support of non-loadable enums with a fix
2025-09-25 18:46:16 +02:00
eeckstein
9412e192c1 Merge pull request #84482 from eeckstein/smallprojectionpath-tests
SIL: use `Test` for the SmallProjectionPath's unit tests
2025-09-25 17:37:04 +02:00
Michael Gottesman
810f5b5088 [cmake] Make SwiftCompilerSources support debug info in RelWithDebInfoMode and use -Os instead of -O with MinSizeRel. 2025-09-25 08:16:20 -05:00
Erik Eckstein
d590b94109 InitializeStaticGlobals: fix handling of nested non-loadable enums
Fixes a compiler crash
rdar://160880083
2025-09-25 10:11:18 +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:
8f7af45115/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
Erik Eckstein
648aa411a7 Reapply "InitializeStaticGlobals: support non-loadable enums"
This reverts commit 586f8a4694.
2025-09-25 08:22:26 +02: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
Jakub Florek
aebebd9ee2 Merge pull request #84463 from MAJKFL/fix-licm-missing-earlier-materializable-projection-check
LICM fix missing materializable projection check
2025-09-24 17:19:39 +01:00
Jakub Florek
6788017cfb Add earlier check before load projection that bails when it's not materializable. 2025-09-24 11:49:59 +01:00
Erik Eckstein
39b9969049 SIL: use Test for the SmallProjectionPath's unit tests
Now that we have `Test` available in the SIL module, we can use it for the SmallProjectionPath's unit tests and get rid of the RunUnitTests pass.
2025-09-24 11:46:34 +02: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