Type annotations for instruction operands are omitted, e.g.
```
%3 = struct $S(%1, %2)
```
Operand types are redundant anyway and were only used for sanity checking in the SIL parser.
But: operand types _are_ printed if the definition of the operand value was not printed yet.
This happens:
* if the block with the definition appears after the block where the operand's instruction is located
* if a block or instruction is printed in isolation, e.g. in a debugger
The old behavior can be restored with `-Xllvm -sil-print-types`.
This option is added to many existing test files which check for operand types in their check-lines.
Instead, use the `%target-swift-5.1-abi-triple` substitution to compile the tests
for deployment to the minimum OS versions required for use of _Concurrency APIs.
We've been building up this exponential explosion of task-creation
builtins because it's not currently possible to overload builtins.
As long as all of the operands are scalar, though, it's pretty easy
to peephole optional injections in IRGen, which means we can at
least just use a single builtin in SIL and then break it apart in
IRGen to decide which options to set.
I also eliminated the metadata argument, which can easily be recreated
from the substitutions. I also added proper verification for the builtin,
which required (1) getting `@Sendable` right more consistently and (2)
updating a bunch of tests checking for things that are not actually
valid, like passing a function that returns an Int directly.
SILGen and IRGen would disagree on the return type of the
`swift_task_getMainExecutor()` runtime function if
`SILGenModule::getGetMainExecutor()` had ever been called. To address this,
consistently use the `buildMainActorExecutorRef` built-in and get rid of
`SILGenModule::getGetMainExecutor()`.
Resolves rdar://116472583
Fix the common error of using underscores instead of dashes.
In the rebranch this is an error (lit got more picky), but it also makes sense to fix the tests in the main branch
* Enable running tests from test/Concurrency/ directory in freestanding/minimal presets
* Mark failing Concurrency tests as XFAIL/SKIP on freestanding/minimal
This patch forces the main function to be protected behind MainActor
isolation. If no actor isolation is specified, the main function will
implicitly have MainActor isolation.
This patch changes the main task to inherit the context of the main
thread. This should assign the appropriate priority based on how the
program was invoked. I've also updated the tests to reflect these
changes.
This patch updates the asynchronous main function to run the first thunk
of the function synchronously through a call to `swift_job_run`.
The runloop is killed by exiting or aborting the task that it is running
on. As such, we need to ensure that the task contains an async function
that either calls exit explicitly or aborts. The AsyncEntryPoint, that
contains this code, was added in the previous patch. This patch adds the
pieces for the actual implementation of this behaviour as well as adding
the necessary code to start the runloop.
There are now four layers of main functions before hitting the "real"
code.
@main: This is the actual main entrypoint of the program. This
constructs the task containing @async_main, grabs the main executor,
runs swift_job_run to run the first part synchronously, and finally
kicks off the runloop with a call to _asyncMainDrainQueue. This is
generated in the call to `emitAsyncMainThreadStart`.
@async_main: This thunk exists to ensure that the main function calls
`exit` at some point so that the runloop stops. It also handles emitting
an error if the user-written main function throws.
e.g:
```
func async_main() async -> () {
do {
try await Main.$main()
exit(0)
} catch {
_errorInMain(error)
}
}
```
Main.$main(): This still has the same behaviour as with the
synchronous case. It just calls `try await Main.main()` and exists to
simplify typechecking.
Main.main(): This is the actual user-specified main. It serves the same
purpose as in the synchronous, allowing the programmer to write code,
but it's async!
The control flow in `emitFunctionDefinition` is a little confusing (to
me anyway), so here it is spelled out:
If the main function is synchronous, the `constant.kind` will be a
`SILDeclRef::Kind::EntryPoint`, but the `decl` won't be async, so it
drops down to `emitArtificalTopLevel` anyway.
If the main function is async and we're generating `@main`, the
`constant.kind` will be `SILDeclRef::Kind::AsyncEntryPoint`, so we also
call `emitArtificalTopLevel`. `emitArtificalTopLevel` is responsible for
detecting whether the decl is async and deciding whether to emit code to
extract the argc/argv variables that get passed into the actual main
entrypoint to the program. If we're generating the `@async_main` body,
the kind will be `SILDeclRef::Kind::EntryPoint` and the `decl` will be
async, so we grab the mainEntryPoint decl and call
`emitAsyncMainThreadStart` to generate the wrapping code.
Note; there is a curious change in `SILLocation::getSourceLoc()`
where instead of simply checking `isFilenameAndLocation()`, I change it
to `getStorageKind() == FilenameAndLocationKind`. This is because the
SILLocation returned is to a FilenameAndLocationKind, but the actual
storage returns true for the call to `isNull()` inside of the
`isFilenameAndLocation()` call. This results in us incorrectly falling
through to the `getASTNode()` call below that, which asserts when asked
to get the AST node of a location.
I also did a little bit of refactoring in the SILGenModule for grabbing
intrinsics. Previously, there was only a `getConcurrencyIntrinsic`
function, which would only load FuncDecls out of the concurrency
module. The `exit` function is in the concurrency shims module, so I
refactored the load code to take a ModuleDecl to search from.
The emitBuiltinCreateAsyncTask function symbol is exposed from
SILGenBuiltin so that it is available from SILGenFunction. There is a
fair bit of work involved going from what is available at the SGF to
what is needed for actually calling the CreateAsyncTask builtin, so in
order to avoid additional maintenance, it's good to re-use that.
Rather than blanket-disabling concurrency tests when we aren't using a
just-built concurrency library, enable them whenever we have a
suitable concurrency runtime, either just-built, in the OS, or via the
back-deployment libraries.
Windows doesn't have dlsym. Since I don't have a Windows box, I'm just
if-def'ing it out for the time being. Since we don't want Windows going
off and doing dangerous things, I threw in an abort just to be safe.
Adding execution and death test to ensure that we crash appropriately
when the main function throws an uncaught exception, and that the async
main runs correctly.
Also switching to doing the CFRunLoopRun lookup with `RTLD_DEFAULT`
since `RTLD_SELF` isn't available on Linux.
Switching to `try await` since `await try` is no longer the right way to
do that.
Using exit(0) instead of EXIT_SUCCESS since the C++ importer doesn't
mark imported macros with @actorIndependent yet.
This patch has two desirable effects for the price of one.
1. An uncaught error thrown from main will now explode
2. Move us off of using runAsyncAndBlock
The issue with runAsyncAndBlock is that it blocks the main thread
outright. UI and the main actor need to run on the main thread or bad
things happen, so blocking the main thread results in a bad day for
them.
Instead, we're using CFRunLoopRun to run the core-foundation run loop on
the main thread, or, dispatch_main if CFRunLoopRun isn't available.
The issue with just using dispatch_main is that it doesn't actually
guarantee that it will run the tasks on the main thread either, just
that it clears the main queue. We don't want to require everything that
uses concurrency to have to include CoreFoundation either, but dispatch
is already required, which supplies dispatch_main, which just empties
out the main queue.
This patch adds the async-main start-point for programs.
When a `static func main() async` is inserted into the main program, it
gets called through `_runAsyncMain` instead of calling directly. This
starts the program in an async context, which is good because then we
can do async stuff from there.
The following code
```
@main struct MyProgram {
static func main() async {
// async code
}
}
```
is turned into
```
@main struct MyProgram {
static func $main() {
_runAsyncMain(main)
}
static func main() async {
// async code
}
}
```
_runAsyncMain code-gen's to the same thing as runAsyncAndBlock, which
emits a call to `swift_task_runAndBlockThread`.