Commit Graph

1230 Commits

Author SHA1 Message Date
Andrew Trick
1d1b260c8f Merge pull request #78199 from atrick/lifedep-cleanup
LifetimeDependence: minor diagnostic quality fixes and related utilities
2024-12-15 04:45:08 -08:00
Andrew Trick
c4a2200669 Fix lifetime_dependence_borrow_fail diagnostic.
Report the correct variable name.
2024-12-14 22:46:55 -08:00
Andrew Trick
05c501a8f6 Add AddressOwnershipLiveRangeTest 2024-12-14 22:46:55 -08:00
Andrew Trick
7cfe4a5660 LifetimeDependenceDiagnostics: fix global sourceLoc. 2024-12-14 22:46:55 -08:00
Andrew Trick
e871ce960d LifetimeDependenceDiagnostics pass order comments 2024-12-14 22:46:55 -08:00
Andrew Trick
46db7ce24e LifetimeDependenceDefUseWalker: recognize ConvertPointerToPointer
Look through a call to the ConvertPointerToPointerArgument compiler intrinsic
just like it is a copy of the pointer. At the source level, that's all it is:

Treat this like a direct use of the argument 'p' rather than the result of the
invisible pointer conversion call:

func foo(_: UnsafeRawPointer)

func bar(p: UnsafePointer<T>) {
  foo(p)
}
2024-12-14 22:46:54 -08:00
Andrew Trick
98da813f02 [NFC] SwiftCompilerSources: add isConvertPointerToPointerArgument 2024-12-14 22:46:54 -08:00
Andrew Trick
f5fc17804e [NFC] SwiftCompilerSources: Add VariableScopeInstruction utility
To diagnose dependence on trivial variables.
2024-12-14 22:46:54 -08:00
eeckstein
ec7a91db36 Merge pull request #78162 from eeckstein/improve-release-devirtualizer
ReleaseDevirtualizer: improve finding the last release of an allocation
2024-12-14 08:08:19 +01:00
Erik Eckstein
bf496aa4f6 Optimizer: add simplification for fix_lifetime
Canonicalize a `fix_lifetime` from an address to a `load` + `fix_lifetime`:
```
   %1 = alloc_stack $T
   ...
   fix_lifetime %1
```
->
```
   %1 = alloc_stack $T
   ...
   %2 = load %1
   fix_lifetime %2
```

This transformation is done for `alloc_stack` and `store_borrow` (which always has an `alloc_stack` operand).
The benefit of this transformation is that it enables other optimizations, like mem2reg.

This peephole optimization was already done in SILCombine, but it didn't handle store_borrow.
A good opportunity to make an instruction simplification out of it.

This is part of fixing regressions when enabling OSSA modules:
rdar://140229560
2024-12-13 12:06:20 +01:00
Erik Eckstein
9cdd9fabae ReleaseDevirtualizer: improve finding the last release of an allocation
With OSSA it can happen more easily that the final release is not immediately located before the related dealloc_stack_ref.
Therefore do a more precise check (using escape analysis) if any instruction between a release and a dealloc_stack_ref might (implicitly) release the allocated object.

This is part of fixing regressions when enabling OSSA modules:
rdar://140229560
2024-12-13 10:06:35 +01:00
Erik Eckstein
6990a195a3 Optimizer: rename GuaranteedPhiUpdater -> PhiUpdater
Because it now has the replacePhisWithIncomingValues utility, which works for all kind of phis.
2024-12-12 09:09:11 +01:00
Erik Eckstein
09a5a4487a Optimizer: add a utility to replaces phis with the unique incoming values if all incoming values are the same
This is needed after running the SSAUpdater for an existing OSSA value, because the updater can
insert unnecessary phis in the middle of the original liverange which breaks up the original
liverange into smaller ones:

```
   %1 = def_of_owned_value
   %2 = begin_borrow %1
   ...
   br bb2(%1)
 bb2(%3 : @owned $T): // inserted by SSAUpdater
   ...
   end_borrow %2      // use after end-of-lifetime!
   destroy_value %3
```

It's not needed to run this utility if SSAUpdater is used to create a _new_ OSSA liverange.
2024-12-12 08:57:57 +01:00
Erik Eckstein
bd08d6afa1 SIL: make Operand Equatable
To be able to use `!=` for operands.
2024-12-12 08:36:58 +01:00
Erik Eckstein
3e35df0983 Simplification: run begin_borrow simplification in SILCombine 2024-12-11 12:32:34 +01:00
Erik Eckstein
12626e39d5 Simplification: remove begin_borrow if the borrowed value is a thin_to_thick_function
`thin_to_thick_function` has "none" ownership and is compatible with guaranteed values.
Therefore the `begin_borrow` is not needed.
2024-12-11 12:32:33 +01:00
Erik Eckstein
6b38f2aab4 Optimizer: simplify load_borrow
* Remove dead `load_borrow` instructions (replaces the old peephole optimization in SILCombine)
* If the `load_borrow` is followed by a `copy_value`, combine both into a `load [copy]`
2024-12-11 12:32:33 +01:00
Erik Eckstein
73e36e2282 SimplifyDestructure: canonicalize destructure_tuple and destructure_struct for trivial tuples/structs
Replace destructure_tuple with tuple_extract instructions and destructure_struct with struct_extract instructions.
This canonicalization helps other optimizations to e.g. CSE tuple_extract/struct_extract.
2024-12-11 12:32:33 +01:00
eeckstein
81c65758e3 Merge pull request #78059 from eeckstein/destroy-hoisting
Optimizer: add a new destroy-hoisting optimization
2024-12-11 06:18:05 +01:00
Erik Eckstein
5be781a9a0 Optimizer: add a new destroy-hoisting optimization
It hoists `destroy_value` instructions  without shrinking an object's lifetime.
This is done if it can be proved that another copy of a value (either in an SSA value or in memory) keeps the referenced object(s) alive until the original position of the `destroy_value`.
```
  %1 = copy_value %0
  ...
  last_use_of %0
  // other instructions
  destroy_value %0       // %1 is still alive here
```
->
```
  %1 = copy_value %0
  ...
  last_use_of %0
  destroy_value %0
  // other instructions
```

The benefit of this optimization is that it can enable copy-propagation by moving destroys above deinit barries and access scopes.
2024-12-10 16:28:11 +01:00
Erik Eckstein
62b26dc8c4 SIL: make isEmpty and singleElement available for all Sequences
and not just for `CollectionLikeSequence`.
To support stdlib's lazy map and filter sequences.
2024-12-10 16:28:11 +01:00
Erik Eckstein
bcdbc05260 SIL: make Builde.insertionPoint public 2024-12-10 16:28:11 +01:00
Erik Eckstein
c5efad1e2d SIL: make isLexical a protocol requirement of Value
This avoids the need for checking if a value is a `move_value`, `begin_borrow` or function argument to get the is-lexical information.
2024-12-10 16:28:11 +01:00
Erik Eckstein
4b462004e7 Optimizer: Fix InstructionRange's begin instruction
Just don't store the begin instruction.
This led to problem if the "begin" was not actually an instruction but a block argument.
Using the first instruction of that block is not correct in case the range ends immediately at the first instruction, e.g.

```
  bb0(%0 : @owned $C):
    destroy_value %0
```
2024-12-10 16:28:10 +01:00
Erik Eckstein
dd78dc722b Optimizer: add an optimization to remove copy_value of a borrowed value.
It removes a `copy_value` where the source is a guaranteed value, if possible:

```
  %1 = copy_value %0   // %0 = a guaranteed value
  // uses of %1
  destroy_value %1     // borrow scope of %0 is still valid here
```
->
```
  // uses of %0
```

This optimization is very similar to the LoadCopyToBorrow optimization.
Therefore I merged both optimizations into a single file and renamed it to "CopyToBorrowOptimization".
2024-12-09 20:01:07 +01:00
Erik Eckstein
1fcfa11713 Optimizer: add InstructionRange.init(begin:,ends:) API 2024-12-09 20:00:13 +01:00
Erik Eckstein
b4ba750481 Optimizer: move Context.erase(instructions:) from Outliner to Context 2024-12-09 19:59:05 +01:00
Erik Eckstein
736d8d5e9c SimplifyLoad: fix removal of load operand instructions
Also consider that the (transitive) operand of a load can be a multi-value instruction, like begin_cow_mutation

rdar://140778782
2024-12-02 19:38:53 +01:00
eeckstein
ca50c55eb5 Merge pull request #77806 from eeckstein/rle-of-array-elements
Optimizer: remove the ArrayElementPropagation optimization
2024-12-02 07:13:08 +01:00
eeckstein
b63365c9d3 Merge pull request #77858 from eeckstein/fix-deinit-devirtualizer
Devirtualization: make sure to de-serialize the body of shared deinit functions
2024-12-02 07:11:56 +01:00
Erik Eckstein
e3df3da8a9 AliasAnalysis: fix the complexity limit for ARCSequenceOpts
The comment already says that we need a lower complexity limit for ARCSequenceOpts, but the actual budget was not set correctly to a lower limit.
2024-11-28 10:35:39 +01:00
Erik Eckstein
aa274a213b WalkUtils: handle mark_dependence instruction in the ValueUseDefWalker
It was already handled in the ValueDefUseWalker
2024-11-28 09:40:13 +01:00
Erik Eckstein
c25d915337 SimplifyLoad: remove a load from a global object, e.g. from an outlined array
Loading  array elements or the array's count/capacity can be replaced with the actual value if the array is a statically allocated global let-variable.
2024-11-28 09:40:12 +01:00
Erik Eckstein
6a0b7d1f8c ObjectOutliner: create outlined arrays as let variables
This will allow load-simplification to replace a load of such an array.
2024-11-28 09:40:12 +01:00
Erik Eckstein
9279a2c0d6 Devirtualization: make sure to de-serialize the body of shared deinit functions.
Sometimes it can happen that a deinit function, which is imported from another module, has shared linkage.
In this case it is important to de-serialize the function body. Otherwise it would be illegal SIL.

Unfortunately I don't have a test case for this.
2024-11-27 18:05:36 +01:00
Erik Eckstein
53bb72c3e4 EscapeUtils: don't follow the result of a partial_apply for not captured address operands.
A partial_apply copies the values from indirect-in arguments, but does not capture the address.
2024-11-27 12:16:43 +01:00
Erik Eckstein
b98608dfbe AliasAnalysis: fix memory-behavior of closures with inout arguments
Calls of such closures were not considered to read or modify the inout argument.

Fixes a miscompile.
rdar://140338313
2024-11-27 12:16:43 +01:00
Andrew Trick
0a70bdd428 LifetimeDependenceDiagnostics: handle undiagnosed mark_depends
Mark unresolved mark_depends as nonescaping so they don't leak into the
optimizer pipeline.
2024-11-18 22:31:07 -08:00
Andrew Trick
c05044c65c Add MarkDependenceInst.settleToEscaping
This allows emitting mark_dependence [unresolved] in some cases even if the
diagnostics can't currently handle them.
2024-11-18 22:02:44 -08:00
Andrew Trick
5be742fd8c SwiftCompilerSources: fix BeginApplyInst.endOperands.
isScopeEndingUse is not the same as endsLifetime.
2024-11-18 22:02:44 -08:00
Andrew Trick
e5069281d4 SwiftCompilerSources: Add Operand.isScopeEndingUse. 2024-11-18 22:02:44 -08:00
Andrew Trick
442739a176 [NFC] Add a Builder.insertionBlock API.
Some utilities, like Builder.insert(after:) pass a Builder object that
represents an insertion point. That insertion point is sometimes needed to
determine which instructions to create (endApply vs. abortApply). But there is
no way to recover the insertion point. We don't want to simply return an
instruction, because that could be interpreted in different ways. Instead we
provide insertion block, but only in those situations where it makes sense and can't
be used incorrectly.
2024-11-18 01:37:00 -08:00
Andrew Trick
5fc103b8ac [NFC] AccessUtils: add accessBaseWithScopes
And simplify enclosingAccessScope.

These two APIs now directly compute what is being asked for. Previously, each
invocation of enclosingAccessScope would recompute the base and all nested
scopes, but throw away that information. Sometimes we do not want to compute
that information, and other times we need all of it. Instead, provide separate
APIs that do exactly what is needed.

These are common APIs used by other utilities. This avoids quadratic traversals in those
cases. It is also easier to understand and debug.

These utilities will be used in LifetimeDependenceScopeFixup.
2024-11-18 01:37:00 -08:00
Andrew Trick
0fb3cb96de [NFC] Add AccessBase.address
LifetimeDependence uses the address of the AccessBase to compute liveness. It is
more convenient to switch over all AccessBase kinds here rather than force all
clients to do it.
2024-11-18 01:37:00 -08:00
Andrew Trick
ec0026f7e5 [NFC] AccessBase: correct initialization from pointer_to_address
AccessBase already identifies a base address as either a .global (addressor) or
a .pointer. When initializing an AccessBase from a pointer_to_address, precisely
identify one of these kinds of accesses, rather than simply marking it
.unidentified.

This used to be a special case in the AccessPathWalker. But that's not the right
place to handle it.
2024-11-18 01:37:00 -08:00
Andrew Trick
cdb646dc95 SwiftCompilerSources: add ScopedInstruction.endInstructions.
Add endInstructions requirement so it can be called on an unknown
ScopedInstruction.
2024-11-18 01:37:00 -08:00
Andrew Trick
801c192af1 SwiftCompilerSources: fix EndApplyInst to be SingleValueInstruction.
To be consistent with the C++ implementation.
2024-11-18 01:37:00 -08:00
Andrew Trick
b5bef612ed SwiftCompilerSources: fix BeginApply.endOperands()/endInstructions()
Only return the EndApplyInst and AbortApplyInst uses.
2024-11-18 01:37:00 -08:00
Andrew Trick
3e26cf81d0 SwiftCompilerSources: bridge createEndApply and createAbortApply. 2024-11-18 01:37:00 -08:00
Erik Eckstein
cea7da8d26 RedundantLoadElimination: correctly handle end_borrow instructions
Scope-ending instructions, like `end_borrow` are only irrelevant for RLE if the preceding load is not changed.
If it is changed from `load [copy]` -> `load [take]` the memory effects of those scope-ending instructions prevent that the `load [take]` will illegally mutate memory which is protected from mutation by the scope.

Fixes a memory verifier crash
rdar://139824805
2024-11-14 18:25:11 +01:00