When the error is an empty type, the return value for the error case needs to be an `undef` value of the result type, or `void`, if the result type is `void`
rdar://129359370
Second part of direct error support. This implements direct errors for async functions. Instead of always returning typed errors indirectly, we are returning them directly when possible.
Although I don't plan to bring over new assertions wholesale
into the current qualification branch, it's entirely possible
that various minor changes in main will use the new assertions;
having this basic support in the release branch will simplify that.
(This is why I'm adding the includes as a separate pass from
rewriting the individual assertions)
This is phase-1 of switching from llvm::Optional to std::optional in the
next rebranch. llvm::Optional was removed from upstream LLVM, so we need
to migrate off rather soon. On Darwin, std::optional, and llvm::Optional
have the same layout, so we don't need to be as concerned about ABI
beyond the name mangling. `llvm::Optional` is only returned from one
function in
```
getStandardTypeSubst(StringRef TypeName,
bool allowConcurrencyManglings);
```
It's the return value, so it should not impact the mangling of the
function, and the layout is the same as `std::optional`, so it should be
mostly okay. This function doesn't appear to have users, and the ABI was
already broken 2 years ago for concurrency and no one seemed to notice
so this should be "okay".
I'm doing the migration incrementally so that folks working on main can
cherry-pick back to the release/5.9 branch. Once 5.9 is done and locked
away, then we can go through and finish the replacement. Since `None`
and `Optional` show up in contexts where they are not `llvm::None` and
`llvm::Optional`, I'm preparing the work now by going through and
removing the namespace unwrapping and making the `llvm` namespace
explicit. This should make it fairly mechanical to go through and
replace llvm::Optional with std::optional, and llvm::None with
std::nullopt. It's also a change that can be brought onto the
release/5.9 with minimal impact. This should be an NFC change.
In preparation for moving to llvm's opaque pointer representation
replace getPointerElementType and CreateCall/CreateLoad/Store uses that
dependent on the address operand's pointer element type.
This means an `Address` carries the element type and we use
`FunctionPointer` in more places or read the function type off the
`llvm::Function`.
The special convention currently means three things:
1. There is no async FP symbol for the function. Calls should go directly
to the function symbol, and an async context of fixed static size should be
allocated. This is mandatory for calling runtime-provided async functions.
2. The callee context should be allocated but not initialized. The main
context pointer passed should be the caller's context, and the continuation
function pointer and callee context should be passed as separate arguments.
The function will resume the continuation function pointer with the caller's
context. This is a micro-optimization appropriate for functions that are
expected to frequently return immediately; other functions shouldn't bother.
3. Generic arguments should be suppressed. This is a microoptimization for
certain specific runtime functions where we happen to know that the runtime
already stores the appropriate information internally. Other functions
probably don't want this.
Obviously, these different treatments should be split into different
predicates so that functions can opt in to different subsets of them.
I've also set the code up so that runtime functions can more easily
request a specific static async context size. Previously, it was a
confusingly embedded assumption that the static context size was always
exactly two pointers more than the header.
We were not marking the async function pointer as constant but adding it
to the `.rdata` section which the Windows linker helped identify as a
problem: we were adding data with "rw" to a section that is expected to
be "rd". Marking the data as constant results in error propagation
breaking (presumably due to failure to materialize parameters properly
as bindiff'ing the Concurrency library indicates that the functions are
nearly identical with some argument loads elided). This repairs the
emission of read/write data into the readonly section.
With PE/COFF, one cannot reference a data symbol directly across the
binary module boundary. Instead, the reference must be indirected
through the Import Address Table (IAT) to allow for position
independence.
When generating a reference to a AsyncFunctionPointer ({i8*, i32}), we
tag the pointer as being indirected by tagging bit 1 (with the
assumption that native alignment will ensure 4/8 byte alignment, freeing
the bottom 2 bits at least for bit-packing). We tweak the
v-table/witness table emission such that all references to the
AsyncFunctionPointer are replaced with the linker synthetic import
symbol with the bit packing:
~~~
.quad __imp_$s1L1CC1yyYaKFTu+1
~~~
rather than
~~~
.quad $s1L1CC1yyYaKFTu
~~~
Upon access of the async function pointer reference, we open-code the
check for the following:
~~~
pointer = (pointer & 1) ? *(void **)(pointer & ~1) : pointer;
~~~
Thanks to @DougGregor for the discussion and the suggestion for the
pointer tagging. Thanks to @aschwaighofer for pointers to the code that
I had missed. Also, thanks to @SeanROlszewski for the original code
sample that led to the reduced test case.
Fixes: SR-15399
This is to deal with the fact that LLVM's coroutine can't handle instructions
with side-effects well that are inserted before the coro.begin.
rdar://81113950
Changes the task, taskGroup, asyncLet wait funtion call ABIs.
To reduce code size pass the context parameters and resumption function
as arguments to the wait function.
This means that the suspend point does not need to store parent context
and resumption to the suspend point's context.
```
void swift_task_future_wait_throwing(
OpaqueValue * result,
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
AsyncTask *task,
ThrowingTaskFutureWaitContinuationFunction *resume,
AsyncContext *callContext);
```
The runtime passes the caller context to the resume entry point saving
the load of the parent context in the resumption function.
This patch adds a `Metadata *` field to `GroupImpl`. The await entry
pointer no longer pass the metadata pointer and there is a path through
the runtime where the task future is no longer available.
Previously, AsyncFunctionPointer constants were signed as code. That
was incorrect considering that these constants are in fact data. Here,
that is fixed.
rdar://76118522
Throwing functions pass the error result in `swiftself` to the resume
partial function.
Therefore, `() async -> ()` to `() async throws -> ()` is not ABI compatible.
TODO: go through remaining failing IRGen async tests and replace the
illegal convert_functions.
The `coro.end.async` intrinsic allow specifying a function that is to be
tail-called as the last thing before returning.
LLVM lowering will inline the `must-tail-call` function argument to
`coro.end.async`. This `must-tail-call` function can contain a
`musttail` call.
```
define @my_must_tail_call_func(void (*)(i64) %fnptr, i64 %args) {
musttail call void %fnptr(i64 %args)
ret void
}
define @async_func() {
...
coro.end.async(..., @my_must_tail_call_func, %return_continuation, i64 %args)
unreachable
}
```
First, just call an async -> T function instead of forcing the caller
to piece together which case we're in and perform its own copy. This
ensures that the task is actually kept alive properly.
Second, now that we no longer implicitly depend on the waiting tasks
being run synchronously, go ahead and schedule them to run on the
global executor.
This solves some problems which were blocking the work on TLS-ifying
the task/executor state.
Previously, the error stored in the async context was of type SwiftError
*. In order to enable the context to be callee released, make it
indirect and change its type to SwiftError **.
rdar://71378532
This increases the level of abstraction a bit and makes it easier to stage
in the requisite support for async method calls. For now, I've kept the
existing, incomplete logic for those.
Part of rdar://problem/73625623.
This adds new kinds of link entities corresponding to the three
dispatch thunk link entity kinds:
- DispatchThunkAsyncFunctionPointer
- DispatchThunkInitializerAsyncFunctionPointer
- DispatchThunkAllocatorAsyncFunctionPointer
For this, store those 3 values on the stack at function entry and update them with the return values of coro_suspend_async intrinsic calls.
This fixes a correctness issue, because the executor may be different after a resume.
It also is more efficient, because this means that the 3 values don't have to preserved in the context over a suspension point.
Previously, when looking up a protocol method, the witness table was
always exepcted to be the final argument passed to the function.
That is true for sync protocol witnesses but not for async witnesses.
In the async case, the witness table is embedded in the async context.
Here, the witness table is dug out of the async context.
rdar://problem/71491604
Metadata for an instance of a type is resolved by extracting it from an
instance of the class. When doing method lookup for an instance method
of a resilient class, the lowered self value was being obtained from the
list of arguments directly by indexing. That does not apply to async
functions where self is embedded within the async context. Here, the
self parameter is extracted from the async context so that the metadata
can in turn be extracted from it.
rdar://problem/71260862
An AsyncFunctionPointer, defined in Task.h, is a struct consisting of
two i32s: (1) the relative address of the async function and (2) the
size of the async context to be allocated when calling that function.
Here, such structs are emitted for every async SILFunction that is
emitted.