Commit Graph

1699 Commits

Author SHA1 Message Date
Erik Eckstein
5b8a1a7b68 LoopInvariantCodeMotion: don't extend "read" access scopes over memory writes to the same address.
We must not do this even if the write is _not_ in an access scope, because this would confuse alias analysis.

Fixes a mis-compile.
2025-10-22 20:55:22 +02:00
Erik Eckstein
dafb43b124 LoopInvariantCodeMotion: a small code cleanup
NFC
2025-10-22 20:55:22 +02:00
Erik Eckstein
4f1cbbd07d SIL Verifier: verify that inside a read-only access scope there are no stores to the memory location
This will e.g. catch violations like
```
  %1 = begin_access [read] %0
  store %2 to %0
  end_access %1
```

Also, fix all the sil tests which violate that.
2025-10-22 20:55:21 +02:00
Arnold Schwaighofer
a59f6c4a3c Fix formatting 2025-10-21 07:54:55 -07:00
eeckstein
9074a1eec3 Merge pull request #85005 from eeckstein/remove-copy-forwarding
Optimizer: remove the CopyForwarding pass
2025-10-21 07:24:42 +02:00
Erik Eckstein
dbeda9612c TempRValueElimination: handle debug_value instructions 2025-10-20 20:19:54 +02:00
Erik Eckstein
62c3850d55 TempRValueElimination: allow elimination of dead alloc_stacks in non-OSSA 2025-10-20 20:19:54 +02:00
Erik Eckstein
8618a39ac5 TempRValueElimination: support consuming indirect apply operands 2025-10-20 20:19:53 +02:00
Arnold Schwaighofer
22c8ea6af6 Add experimental feature flag EmbeddedExistentials
This flag can be used to gradually add the functionility that will allow use of
protocol values in embedded mode.
2025-10-20 10:18:45 -07:00
Meghana Gupta
0bd6825aa2 Update SIL utilities for borrow and mutate accessors under opaque values mode 2025-10-20 09:05:38 -07:00
Meghana Gupta
25f0e2f934 [NFC] Replace @guaranteed_addr by @guaranteed_address 2025-10-20 09:05:37 -07:00
Meghana Gupta
a0c939bd3b Use @inout result convention for mutate accessors 2025-10-20 09:05:32 -07:00
eeckstein
e74a7ecef9 Merge pull request #84979 from eeckstein/global-init-optimizations
Optimizer: some small (mandatory) optimization improvements for static initialization of globals
2025-10-20 07:32:03 +02:00
Michael Gottesman
a9d409d526 Merge pull request #83346 from gottesmm/pr-df6aafa41c61b9a9a6ee4965a1564ec2946a0dc9
[concurrency] Change #isolated to mask out the TBI bits of the witness pointer of the implicit isolated any Actor pointer so we can do optimizations on TBI supporting platforms in the future.
2025-10-17 17:02:43 -07:00
Erik Eckstein
62e2871b2f MandatoryPerformanceOptimizations: run DeadStoreElimination for global init functions.
Cleanup leftovers from simplification.
The InitializeStaticGlobals pass cannot deal with dead stores in global init functions.
2025-10-17 20:25:19 +02:00
Erik Eckstein
794964adba MandatoryRedundantLoadElimination: remove redundant loads from global variables
This is important in the initializer functions of globals. It can enabled static initialization of globals in more cases.
2025-10-17 20:25:19 +02:00
Erik Eckstein
110010856f AliasAnalysis: handle debug_step in computeMemoryEffect
The `debug_step` instruction does not have a memory effect on any specific address
2025-10-17 20:25:18 +02:00
Daniil Kovalev
75f80410e6 Run closure specialization only if ownership info is present in callee (#84956)
Calling `cloneRecursively` from `SpecializationInfo.cloneClosures`
requires the callee having ownership info. Otherwise, the cloner uses
`recordFoldedValue` instead of `recordClonedInstruction`, and
`postProcess` hook is not called, which leads to an assertion failure in
`BridgedClonerImpl::cloneInst`.
2025-10-17 10:51:57 -07:00
Michael Gottesman
fe9c21fd87 [sil] Add a new instruction cast_implicit_actor_to_optional_actor.
This instruction converts Builtin.ImplicitActor to Optional<any Actor>. In the
process of doing so, it masks out the bits we may have stolen from the witness
table pointer of Builtin.ImplicitActor. The bits that we mask out are the bottom
two bits of the top nibble of the TBI space on platforms that support TBI (that
is bit 60,61 on arm64). On platforms that do not support TBI, we just use the
bottom two tagged pointer bits (0,1).

By using an instruction, we avoid having to represent the bitmasking that we are
performing at the SIL level and can instead just make the emission of the
bitmasking an IRGen detail. It also allows us to move detection if we are
compiling for AArch64 to be an IRGen flag instead of a LangOpts flag.

The instruction is a guaranteed forwarding instruction since we want to treat
its result as a borrowed projection from the Builtin.ImplicitActor.
2025-10-16 10:52:04 -07: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 eb1d5f484c.
2025-10-16 10:12:33 +02:00
Daniil Kovalev
7c90f03032 Merge branch 'main' into users/kovdan01/ast-bridges-for-autodiff-closure-spec 2025-10-15 13:17:36 +03:00
Daniil Kovalev
02fcd218d7 Address review comments 2025-10-15 05:14:15 +03: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
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
Daniil Kovalev
b3d31c7d51 Bridging: Implement bridges required for ongoing AutoDiff changes
In #83926, part of the changes resolving #68944 is submitted. The AutoDiff
closure specialization optimizer pass relies on several bridges not
implemented yet.

This patch introduces these missing bridges. See the list of the changes below.

**AST:**

* Define `.asValueDecl` on each BridgedXXXDecl type that's also a ValueDecl.

* Define `.asNominalTypeDecl` on each BridgedXXXDecl type that's also a NominalTypeDecl.

* Define `.asGenericContext` on each BridgedXXXDecl type that's also a GenericContext.

* `class BridgedSourceFile`:
  - Make nullable
  - `func addTopLevelDecl(_ decl: BridgedDecl)`

* `class BridgedFileUnit`:
  - `func castToSourceFile() -> BridgedNullableSourceFile`

* `class BridgedDecl`:
  - `func getDeclContext() -> BridgedDeclContext`

* `class BridgedParamDecl`:
  - `func cloneWithoutType() -> BridgedParamDecl`
  - `func setInterfaceType(_ type : BridgedASTType)`

* Define `BridgedDecl.setImplicit()` instead of `BridgedParamDecl.setImplicit()`

* `class BridgedGenericContext`:
  - `setGenericSignature(_ genSig: BridgedGenericSignature)`

* Change return type of `BridgedEnumDecl.createParsed(/*...*/)` from `BridgedNominalTypeDecl` to `BridgedEnumDecl`

* `class BridgedValueDecl`:
  - `func setAccess(_ accessLevel: swift.AccessLevel)`

* `class BridgedNominalTypeDecl`:
  - `func addMember(_ member: BridgedDecl)`

* `class BridgedGenericTypeParamDecl`:
  - `func createImplicit(declContext: BridgedDeclContext, name: swift.Identifier, depth: UInt, index: UInt, paramKind: swift.GenericTypeParamKind)`

* `class ValueDecl`:
  - `var baseIdentifier: swift.Identifier`

* `class NominalTypeDecl`:
  - `var declaredInterfaceType: Type`

* `class EnumElementDecl`:
  - `var parameterList: BridgedParameterList`
  - `var nameStr: StringRef`

* `struct GenericSignature`:
  - `var canonicalSignature: CanGenericSignature`

* `struct CanGenericSignature`:
  - `var isEmpty: Bool`
  - `var genericSignature: GenericSignature`

* `struct Type`:
  - `func mapTypeOutOfContext() -> Type`
  - `func getReducedType(sig: GenericSignature) -> CanonicalType`
  - `func GenericTypeParam_getName() -> swift.Identifier`
  - `func GenericTypeParam_getDepth() -> UInt`
  - `func GenericTypeParam_getIndex() -> UInt`
  - `func GenericTypeParam_getParamKind() -> swift.GenericTypeParamKind`

* `struct CanonicalType`:
  - `func SILFunctionType_getSubstGenericSignature() -> CanGenericSignature`
  - `func loweredType(in function: SIL.Function) -> SIL.Type`

**SIL:**

* `class Argument`:
  - `func replaceAllUsesWith(newArg: Argument)`

* `class BasicBlock`:
  - `func insertPhiArgument(atPosition: Int, type: Type, ownership: Ownership, _ context: some MutatingContext) -> Argument`

* `struct Builder`:
  - `func createTuple(elements: [Value]) -> TupleInst`

* `protocol Context`:
  - `func getTupleType(elements: [AST.Type]) -> AST.Type`
  - `func getTupleTypeWithLabels(elements: [AST.Type], labels: [swift.Identifier]) -> AST.Type`

* `class Function`:
  - `var sourceFile: BridgedNullableSourceFile`
  - `func mapTypeIntoContext(_ type: Type) -> Type`

* `class PartialApplyInst`:
  - `var substitutionMap: SubstitutionMap`

* `class SwitchEnumInst`:
  - `var numCases: Int`
  - `public func getSuccessorForDefault() -> BasicBlock?`

* `Type`:
  - `var category: ValueCategory`
  - `func getEnumCasePayload(caseIdx: Int, function: Function) -> Type`
  - `func mapTypeOutOfContext() -> Type`
  - `static func getPrimitiveType(canType: CanonicalType, silValueCategory: ValueCategory) -> Type`

* `struct EnumCase`:
  - `let enumElementDecl: EnumElementDecl`

* `struct TupleElementArray`:
  - `func label(at index: Int) -> swift.Identifier`

* Define `enum ValueCategory` with `address` and `object` elements
2025-10-06 17:56:38 +03: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