Commit Graph

103 Commits

Author SHA1 Message Date
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
Michael Gottesman
36fc50370f [closure-lifetime-fixup] Use the SSAUpdater rather than memory to extend the lifetime to the end of the function.
This beyond being slightly cleaner ensures that we do not try to promote in
PredictableMemOpts any loads from the alloc_stack. Doing this would force us to
insert a copy in ossa which then would break is_escaping_closure even when we
don't escape.

rdar://problem/46188001
2019-02-25 19:13:56 -08:00
Arnold Schwaighofer
0c7b94ef7d ClosureLifetimeFixup: Don't insert dealloc_stack at unreachable 2019-01-17 15:30:17 -08:00
Arnold Schwaighofer
7e6588d830 Update closure lifetime fixup to use partial_apply [stack] 2019-01-16 13:55:03 -08:00
Arnold Schwaighofer
cb0c53abee SIL: Remove isEscapedByUser flag on convert_escape_to_noescape instruction
It was only used for materializeForSet and is now dead code.
2019-01-04 09:21:38 -08:00
Michael Gottesman
caa86c424e [gardening] Change a function with 4 space indent => 2 space indent and standardize variable names.
NFC.
2018-11-18 14:58:01 -08:00
Michael Gottesman
e4607a7191 [closure-lifetime-fixup] When emitting a load_borrow, make sure to emit the end_borrow for it as well.
In this commit I added a more convenient API for doing this sort of operation.
Specifically: SILBuilder::emitScopedBorrowOperation. This performs either a
load_borrow or begin_borrow, then calls a user provided closure, and finally
inserts the end_borrow after the scope has closed.

rdar://43398898
2018-10-26 11:11:01 -07:00
Robert Widmann
014fd952ef [NFC] Silence a bunch of Wunused-variable diagnostics 2018-08-24 15:16:40 -07:00
Andrew Trick
89ed064808 Fix several incorrect uses of ApplySite::getArgumentConvention.
At least most of these were latent bugs since the code was
unreachable in the PartialApply case. But that's no excuse to misuse
the API.

Also, whenever referring to an integer index, be explicit about
whether it is an applied argument or callee argument.
2018-07-28 00:05:40 -07:00
Jordan Rose
cefb0b62ba Replace old DEBUG macro with new LLVM_DEBUG
...using a sed command provided by Vedant:

$ find . -name \*.cpp -print -exec sed -i "" -E "s/ DEBUG\(/ LLVM_DEBUG(/g" {} \;
2018-07-20 14:37:26 -07:00
Arnold Schwaighofer
d735c1ef95 ClosureLifetimeFixup: Delete a dead store 2018-06-11 10:55:44 -07:00
Arnold Schwaighofer
968d2279a9 ClosureLifetimeFixup: Fix closure insertion point in deallocating deinits
We must not capture self beyond the call to super.deinit

rdar://40660799
2018-06-01 09:12:00 -07:00
Arnold Schwaighofer
261639d18d ClosureLifetimeFixup: We need to insert a None on the backedge of a loop after we destroyed the value
rdar://40221767
2018-05-15 08:02:39 -07:00
Arnold Schwaighofer
1f65ee25f6 Distinguish between withoutActuallyEscaping and passing @noescape
Objective C closures when reporting that a closure has escaped

rdar://39682865
2018-05-01 07:24:19 -07:00
Arnold Schwaighofer
1ae309c44c ClosureLifetimeFixup: Add support for copy_block_without_escaping instructions
Replace:

  %copy = copy_block_without_escaping %block withoutEscaping %closure

  ...
  destroy_value %copy

by (roughly) the instruction sequence:

  %copy = copy_block %block

  ...
  destroy_value %copy
  %e = is_escaping %closure
  cond_fail %e
  destroy_value %closure

rdar://39682865
2018-05-01 07:24:19 -07:00
Arnold Schwaighofer
b2d1554a2c ClosureLifetimeFixup: Add missing nullptr check
rdar://39548527
2018-04-19 08:14:08 -07:00