Commit Graph

68 Commits

Author SHA1 Message Date
swift-ci
2667df0799 Merge pull request #67760 from atrick/fix-closure-moveonly-arg
Fix compiler crashes with consuming and borrowing keywords.
2023-08-11 00:32:41 -07:00
Andrew Trick
f46d79149d ClosureLifetimeFixup review feedback 2023-08-10 18:51:48 -07:00
Michael Gottesman
29350907fc Convert TransitiveAddressWalker to use CRTP instead of virtual functions. 2023-08-10 12:58:50 -07:00
Andrew Trick
9c24933bd4 Fix compiler crashes with consuming and borrowing keywords.
Without this fix, the new 'consuming' and 'borrowing' keywords cannot
be used with trivial types. Which means, for example, they can't be
used in macro expansions that work on various types.

Fixes patterns like:

public func test1(i: consuming Int) -> Int {
  takeClosure { [i = copy i] in i }
}

public func test2(i: borrowing Int) -> Int {
  takeClosure { [i = copy i] in i }
}

public func test3(i: consuming Int) -> Int {
  takeClosure { i }
}

// Sadly, test4 is still incorrectly diagnosed.
public func test4(i: borrowing Int) -> Int {
  takeClosure { i }
}

Fixes rdar://112795074 (Crash compiling function that has a macro annotation and uses `consuming`)
2023-08-10 11:17:45 -07:00
Erik Eckstein
6b1697eb06 use new llvm::Optional APIs to fix deprecation warnings 2023-06-28 14:28:38 +02:00
Joe Groff
ed2cbca04f ClosureLifetimeFixup: Remove copy of borrowed move-only nonescaping captures when possible.
SILGen introduces a copy of the capture, because the semantics of escaping partial_apply's
requires the closure to take ownership of the parameters. We don't know when a closure is
strictly nonescaping or its final lifetime until ClosureLifetimeFixup runs, but that replaces
the consume of the copy with a borrow of the copy normally, hoping later passes fix it up.
We can't wait that long for move-only types, which can't be copied, so try to remove the
copy up front when the copy lives long enough and has no interfering uses other than the
partial_apply. rdar://110137169
2023-06-20 12:10:31 -07:00
Michael Gottesman
59c8cff917 [borrowing] Add support for borrowing/consuming copyable types to be a noimplicitcopy type.
rdar://108383660
2023-06-06 18:12:29 -04:00
Erik Eckstein
4b33b99ee2 MemoryLifetimeVerifier: be more precise with indirect function arguments.
Optimizations can rely on alias analysis to know that an in-argument (or parts of it) is not actually read.
We have to do the same in the verifier: if alias analysis says that an in-argument is not read, there is no need that the memory location is initialized.

Fixes a false verifier error.
rdar://106806899
2023-05-03 14:33:45 +02:00
Joe Groff
69e4b95fb8 SIL: Model noescape partial_applys with ownership in OSSA.
Although nonescaping closures are representationally trivial pointers to their
on-stack context, it is useful to model them as borrowing their captures, which
allows for checking correct use of move-only values across the closure, and
lets us model the lifetime dependence between a closure and its captures without
an ad-hoc web of `mark_dependence` instructions.

During ownership elimination, We eliminate copy/destroy_value instructions and
end the partial_apply's lifetime with an explicit dealloc_stack as before,
for compatibility with existing IRGen and non-OSSA aware passes.
2023-02-16 21:43:53 -08:00
Arnold Schwaighofer
508708919a ClosureLifetimeFixup: Fix corner case of unconnected basic blocks
Dominator based algorithms don't like to run over dead basic blocks.

rdar://103531926
2022-12-21 05:54:36 -08:00
Nate Chandler
9ad44a5056 [ClosureLifetimeFixup] Dealloc args on frontier.
Previously, the dealloc_stacks created for the alloc_stacks used to pass
@in_guaranteed arguments to on_stack closures were created after the
users of the closure.  When SILGen created these alloc_stacks in the
same block as the users, this happened to work.  Now that
AddressLowering creates such alloc_stacks elsewhere, this approach
results in invalid SIL.

Here, the dealloc_stacks are instead at the end of each block in the
dominance frontier of the alloc_stack.
2022-12-13 11:46:47 -08:00
Erik Eckstein
c180d1363e SIL: simplify deleting instruction while iterating over instructions.
Add `deletableInstructions()` and `reverseDeletableInstructions()` in SILBasicBlock.
It allows deleting instructions while iterating over all instructions of the block.
This is a replacement for `InstructionDeleter::updatingRange()`.
It's a simpler implementation than the existing `UpdatingListIterator` and `UpdatingInstructionIteratorRegistry`, because it just needs to keep the prev/next pointers for "deleted" instructions instead of the iterator-registration machinery.
It's also safer, because it doesn't require to delete instructions via a specific instance of an InstructionDeleter (which can be missed easily).
2022-12-12 19:08:54 +01:00
Nate Chandler
bfd865b6b6 [ApplySite] Renamed insertAfterApplication.
Now that it can be called on partial_apply instructions,
insertAfterFullEvaluation does not name what the function does.  One
could imagine a function which inserted after the applies of
(non-escaping) partial_applies.
2022-11-03 13:52:42 -07:00
Meghana Gupta
dccb5ac56d ClosureLifetimeFixup : Ensure borrow scope is inserted on both none/some
path for an optional type.
2022-10-19 19:54:27 -07:00
Michael Gottesman
1e6187c4f4 [sil] Update all usages of old API SILValue::getOwnershipKind() in favor of new ValueBase::getOwnershipKind().
Andy some time ago already created the new API but didn't go through and update
the old occurences. I did that in this PR and then deprecated the old API. The
tree is clean, so I could just remove it, but I decided to be nicer to
downstream people by deprecating it first.
2022-07-26 11:46:23 -07:00
Meghana Gupta
defafa7d52 ClosureLifetimeFixup : Fix bug in lifetime extension of non escaping closure 2022-05-31 11:31:50 -07:00
Joe Groff
439edbce1f Handle multiple awaits and suspend-on-exit for async let tasks.
Change the code generation patterns for `async let` bindings to use an ABI based on the following
functions:

- `swift_asyncLet_begin`, which starts an `async let` child task, but which additionally
  now associates the `async let` with a caller-owned buffer to receive the result of the task.
  This is intended to allow the task to emplace its result in caller-owned memory, allowing the
  child task to be deallocated after completion without invalidating the result buffer.
- `swift_asyncLet_get[_throwing]`, which replaces `swift_asyncLet_wait[_throwing]`. Instead of
  returning a copy of the value, this entry point concerns itself with populating the local buffer.
  If the buffer hasn't been populated, then it awaits completion of the task and emplaces the
  result in the buffer; otherwise, it simply returns. The caller can then read the result out of
  its owned memory. These entry points are intended to be used before every read from the
  `async let` binding, after which point the local buffer is guaranteed to contain an initialized
  value.
- `swift_asyncLet_finish`, which replaces `swift_asyncLet_end`. Unlike `_end`, this variant
  is async and will suspend the parent task after cancelling the child to ensure it finishes
  before cleaning up. The local buffer will also be deinitialized if necessary. This is intended
  to be used on exit from an `async let` scope, to handle cleaning up the local buffer if necessary
  as well as cancelling, awaiting, and deallocating the child task.
- `swift_asyncLet_consume[_throwing]`, which combines `get` and `finish`. This will await completion
  of the task, leaving the result value in the result buffer (or propagating the error, if it
  throws), while destroying and deallocating the child task. This is intended as an optimization
  for reading `async let` variables that are read exactly once by their parent task.

To avoid an epoch break with existing swiftinterfaces and ABI clients, the old builtins and entry
points are kept intact for now, but SILGen now only generates code using the new interface.

This new interface fixes several issues with the old async let codegen, including use-after-free
crashes if the `async let` was never awaited, and the inability to read from an `async let` variable
more than once.

rdar://77855176
2021-07-22 10:19:31 -07:00
Erik Eckstein
3c0d8a6c85 ClosureLifetimeFixup: fix a crash due to an iterator invalidation problem.
The fix is the use the InstructionDeleter to iterate over (the not yet deleted) instructions in a block.

rdar://80093482
2021-07-08 15:31:01 +02:00
Erik Eckstein
48ca690d88 ClosureLifetimeFixup: support the startAsyncLet builtin.
When the closure of startAsyncLet is no-escaping, the captured values (= the partial_apply arguments) must be kept alive until the endAsyncLet builtin.
ClosureLifetimeFixup adds the generated mark_dependence as a second operand to endAsyncLet, which keeps all the arguments alive until this point.
2021-04-20 21:38:14 +02:00
Erik Eckstein
b3a7792d1d Reinstate "SIL: add a StackList data structure with zero cost operations."
... with a fix for a non-assert build crash: I used the wrong ilist type for SlabList. This does not explain the crash, though. What I think happened here is that llvm miscompiled and put the llvm_unreachable from the Slab's deleteNode function unconditionally into the SILModule destructor.
Now by using simple_ilist, there is no need for a deleteNode at all.
2021-04-13 13:49:45 +02:00
Arnold Schwaighofer
ddfdf4779d Revert "SIL: add a StackList data structure with zero cost operations." 2021-04-12 12:48:16 -07:00
Erik Eckstein
0456d95cb0 SIL: Use StackList in BasicBlockWorklist and BasicBlockSetVector
plus: I moved both data structures into a separate header file.
2021-04-11 14:07:26 +02:00
Erik Eckstein
214b7a9929 Use the new BasicBlockWorklist utility in various places in the compiler.
It's a refactoring which simplifies the code.
NFC.
2021-02-12 11:15:55 +01:00
Erik Eckstein
fe10f98cf0 SIL: rename the SILBitfield.h header file to BasicBlockBits.h
NFC
2021-02-12 11:15:55 +01:00
Erik Eckstein
f48191966c SILOptimizer: use BasicBlockSet instead of SmallPtrSet in various transformations.
It reduces compile time.
2021-01-27 10:31:17 +01:00
Meghana Gupta
845e63f901 Support ownershipKind in SILSSAUpdater 2021-01-21 16:27:50 -08:00
Erik Eckstein
cf17fd4df4 SILOptimizer: Use BasicBlockData in the StackNesting utility 2021-01-20 16:09:01 +01:00
Slava Pestov
e675bee26c AST: Split off DependencyCollector.h from EvaluatorDependencies.h
Also remove some unnecessary #includes from DependencyCollector.h,
which necessitated adding #includes in various other files.
2020-12-23 00:00:25 -05:00
Michael Gottesman
d064241599 [ssa-updater] Modernize style before adding support for guaranteed parameters.
Specifically:

1. I made methods, variables camelCase.
2. I expanded out variable names (e.x.: bb -> block, predBB -> predBlocks, U -> wrappedUse).
3. I changed typedef -> using.
4. I changed a few c style for loops into for each loops using llvm::enumerate.

NOTE: I left the parts needed for syncing to LLVM in the old style since LLVM
needs these to exist for CRTP to work correctly for the SILSSAUpdater.
2020-08-06 15:41:00 -07:00
Anthony Latsis
9fd1aa5d59 [NFC] Pre- increment and decrement where possible 2020-06-01 15:39:29 +03:00
Meghana Gupta
27e826559a Fix analysis invalidation in ClosureLifetimeFixup (#31295)
Accumulate modifiedCFG when calling correctStackNesting.
Found this bug with -sil-verify-force-analysis=true flag
2020-04-24 16:47:11 -07:00
Meghana Gupta
8e800e49bf Recommit #29812 with fixes (#30342) 2020-03-13 19:34:16 -07:00
Rintaro Ishizaki
ccbc26d947 Revert "Use in_guaranteed for let captures (#29812)"
This reverts commit 13b9915c6f.
2020-03-10 16:08:08 -07:00
Meghana Gupta
13b9915c6f Use in_guaranteed for let captures (#29812)
* Use in_guaranteed for let captures

With this all let values will be captured with in_guaranteed convention
by the closure. Following are the main changes :

SILGen changes:
- A new CaptureKind::Immutable is introduced, to capture let values as in_guaranteed.
- SILGen of in_guaranteed capture had to be fixed.
  in_guaranteed captures as per convention are consumed by the closure. And so SILGen should not generate a destroy_addr for an in_guaranteed capture.
  But LetValueInitialization can push Dealloc and Release states of the captured arg in the Cleanup stack, and there is no way to access the CleanupHandle and disable the emission of destroy_addr while emitting the captures in SILGenFunction::emitCaptures.
  So we now create, temporary allocation of the in_guaranteed capture iduring SILGenFunction::emitCaptures without emitting destroy_addr for it.

SILOptimizer changes:
- Handle in_guaranteed in CopyForwarding.
- Adjust dealloc_stack of in_guaranteed capture to occur after destroy_addr for on_stack closures in ClosureLifetimeFixup.

IRGen changes :
  - Since HeapLayout can be non-fixed now, make sure emitSize is used conditionally
  - Don't consider ClassPointerSource kind parameter type for fulfillments while generating code for partial apply forwarder.
    The TypeMetadata of ClassPointSource kind sources are not populated in HeapLayout's NecessaryBindings. If we have a generic parameter on the HeapLayout which can be fulfilled by a ClassPointerSource, its TypeMetaData will not be found while constructing the dtor function of the HeapLayout.
    So it is important to skip considering sources of ClassPointerSource kind, so that TypeMetadata of a dependent generic parameters gets populated in HeapLayout's NecessaryBindings.
2020-03-10 12:23:02 -07:00
Joe Groff
f0fc78753e ClosureLifetimeFixup: Recognize substitution-only convert_function patterns 2020-02-24 12:14:21 -08:00
Michael Gottesman
990af4bdd3 [sil] Change TermInst::getSuccessorBlockArguments() to yield SILArguments instead of SILPhiArgument since I am going to be adding SwitchEnumResult (which the API can vend as well). 2020-01-03 11:12:48 -08:00
Michael Gottesman
321185e82f [sil] Rename TermInst::{getSuccessorBlockArguments,getSuccessorBlockArgumentLists}()
This method returns argument lists, not arguments! We should add in the future
an additional API that returns a flap mapped range over all such argument lists
to cleanup some of this code. But at least now the name is more accurate.
2019-12-28 15:33:30 -08:00
Andrew Trick
bddc69c8a6 Organize SILOptimizer/Utils headers. Remove Local.h.
The XXOptUtils.h convention is already established and parallels
the SIL/XXUtils convention.

New:
- InstOptUtils.h
- CFGOptUtils.h
- BasicBlockOptUtils.h
- ValueLifetime.h

Removed:
- Local.h
- Two conflicting CFG.h files

This reorganization is helpful before I introduce more
utilities for block cloning similar to SinkAddressProjections.

Move the control flow utilies out of Local.h, which was an
unreadable, unprincipled mess. Rename it to InstOptUtils.h, and
confine it to small APIs for working with individual instructions.
These are the optimizer's additions to /SIL/InstUtils.h.

Rename CFG.h to CFGOptUtils.h and remove the one in /Analysis. Now
there is only SIL/CFG.h, resolving the naming conflict within the
swift project (this has always been a problem for source tools). Limit
this header to low-level APIs for working with branches and CFG edges.

Add BasicBlockOptUtils.h for block level transforms (it makes me sad
that I can't use BBOptUtils.h, but SIL already has
BasicBlockUtils.h). These are larger APIs for cloning or removing
whole blocks.
2019-10-02 11:34:54 -07:00
Jordan Rose
844ae38722 Remove some Swift STLExtras that LLVM now provides (#26443)
No functionality change.
2019-07-31 18:34:52 -07:00
Michael Gottesman
3b0fcf97ec [closure-lifetime-fixup] Use GetValueAtEndOfBlock instead of GetValueInMiddleOfBlock for getting values in exits.
Otherwise we will leak values if the copy block is in the same block as the
terminator and we fail to identify a single destroy for the copy block. We are
generally pretty good at identifying those single destroy cases, so I am not
sure how often this actually happens.

Found by the ownership verifier.
2019-07-21 14:44:52 -07:00
Michael Gottesman
1b127d9c94 [closure-lifetime-fixup] Delete dead trivial phi nodes.
Given certain CFGs, the SSA updater will insert unnecessary phi arguments that
all take the same "initial" value (the .none from the entry block). As an
example, consider the following CFG:

```
+-------+     +------+
|   2   | <-- |  0   |
+-------+     +------+
  |             |
  |             |
  |             v
  |           +------+     +---+
  |           |  1   | --> | 3 |
  |           +------+     +---+
  |             |            |
  |             |            |
  |             v            |
  |           +------+       |
  |           |  4   |       |
  |           +------+       |
  |             |            |
  |             |            |
  |             v            |
  |           +------+       |
  +---------> |  5   |       |
              +------+       |
                |            |
                |            |
                v            |
+-------+     +------+       |
| Throw | <-- |  6   |       |
+-------+     +------+       |
                |            |
                |            |
                v            |
              +------+       |
              | Exit | <-----+
              +------+
```

In this case, if our some value is actually in BB3, we will actually insert a
phi node in BB5 that has all .none incoming values. This is causing us from the
perspective of the ownership verifier to be leaking that phi node in
BBThrow. The reason why is that arguments are a location in SIL where the
specific case of the enum is erased, forcing us to use @owned if the enum has
any non-trivial cases. These of course will not be balanced by any
destroy_values reachable from the copy_value (since otherwise, we would have a
.some definition along that path), so it makes sense. Rather than try to insert
destroy_values, we just realize that in this case we know that all the incoming
values are really the .none from the entry block and delete the argument,
eliminating the problem.
2019-07-19 16:01:55 -07:00
Erik Eckstein
237a3ef77f SIL: Extend cond_fail by a second operand, which is a static string literal, indicating the failure reason. 2019-07-16 12:31:10 +02:00
Brent Royal-Gordon
d5a2912a26 Revert "Better runtime failure messages (not yet enabled by default)" 2019-07-15 13:42:40 -07:00
Erik Eckstein
e2d313ef68 SIL: Extend cond_fail by a second operand, which is a static string literal, indicating the failure reason. 2019-07-12 14:03:13 +02:00
Michael Gottesman
cf0405c7f1 [clf] Simplify the double diamond lifetime extension for escaping swift funcs -> noescape blocks.
Specifically, when we optimize conversions such as:

  Optional<@escaping () -> ()>

  ->

  Optional<@noescape () -> ()>

  ->

  Optional<@noescape @convention(block) () -> ()>

previously we were lifetime extending over the @noescape lifetime barrier by
making a copy and then putting a mark_dependence from the copy onto the original
value. This was just a quick way to tell the ownership verifier that the copy
was tied to the other value and thus should not be eliminated. The correctness
of the actual lifetime extension comes from the optimizer being conservative
around rr insts.

This commit instead changes our optimization to borrow the copied optional
value, extract the payload, and use that instead.
2019-06-09 22:04:32 -07:00
Michael Gottesman
e11794bbfa [closure-lifetime-fixup] Make sure that all copy_value we insert have a data dependence on the cvt_escape_to_no_escape.
Otherwise, the ownership model doesn't understand the need for the copies and
just removes them.
2019-03-26 16:56:29 -07:00
Michael Gottesman
c27b1cbfad [closure-lifetime-fixup] Standardize style. 2019-03-26 15:14:24 -07:00
Michael Gottesman
f8d15143a5 [closure-lifetime-fixup] Expose a flag instead of allocating a new instruction.
Small inefficiency I noticed.
2019-03-25 15:00:35 -07:00
Slava Pestov
8915f96e3e SIL: Replace SILType::isTrivial(SILModule) with isTrivial(SILFunction) 2019-03-12 01:16:04 -04:00
Slava Pestov
c791c4a137 SIL: SILUndef must be aware of the resilience expansion
The ownership kind is Any for trivial types, or Owned otherwise, but
whether a type is trivial or not will soon depend on the resilience
expansion.

This means that a SILModule now uniques two SILUndefs per type instead
of one, and serialization uses two distinct sentinel IDs for this
purpose as well.

For now, the resilience expansion is not actually used here, so this
change is NFC, other than changing the module format.
2019-03-12 00:30:35 -04:00