Skip to content

Commit 794d0e0

Browse files
authored
Merge pull request swiftlang#40832 from etcwilde/ewilde/async-top-level
A first pass at concurrency in top-level code
2 parents c65a469 + 834816a commit 794d0e0

File tree

11 files changed

+131
-41
lines changed

11 files changed

+131
-41
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2015,6 +2015,9 @@ class TopLevelCodeDecl : public DeclContext, public Decl {
20152015
SourceLoc getStartLoc() const;
20162016
SourceRange getSourceRange() const;
20172017

2018+
LLVM_READONLY
2019+
ASTContext &getASTContext() const { return DeclContext::getASTContext(); }
2020+
20182021
static bool classof(const Decl *D) {
20192022
return D->getKind() == DeclKind::TopLevelCode;
20202023
}

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ namespace swift {
393393
/// cases.
394394
bool EnableNonFrozenEnumExhaustivityDiagnostics = false;
395395

396+
/// Enable making top-level code support concurrency
397+
bool EnableExperimentalAsyncTopLevel = false;
398+
396399
/// Regex for the passes that should report passed and missed optimizations.
397400
///
398401
/// These are shared_ptrs so that this class remains copyable.

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,10 @@ def enable_experimental_pairwise_build_block :
301301

302302
def enable_resilience : Flag<["-"], "enable-resilience">,
303303
HelpText<"Deprecated, use -enable-library-evolution instead">;
304+
305+
def enable_experimental_async_top_level :
306+
Flag<["-"], "enable-experimental-async-top-level">,
307+
HelpText<"Enable experimental concurrency in top-level code">;
304308
}
305309

306310
// HIDDEN FLAGS

include/swift/SIL/SILDeclRef.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,14 @@ struct SILDeclRef {
240240
/// Produces a SILDeclRef for the entry-point of a main FileUnit.
241241
static SILDeclRef getMainFileEntryPoint(FileUnit *file);
242242

243+
/// Produces a SILDeclRef for the entry-point of an async main FileUnit.
244+
static SILDeclRef getAsyncMainFileEntryPoint(FileUnit *file);
245+
243246
bool isNull() const { return loc.isNull(); }
244247
explicit operator bool() const { return !isNull(); }
245-
248+
246249
bool hasDecl() const { return loc.is<ValueDecl *>(); }
250+
bool hasFileUnit() const { return loc.is<FileUnit *>(); }
247251
bool hasClosureExpr() const;
248252
bool hasAutoClosureExpr() const;
249253
bool hasFuncDecl() const;
@@ -260,11 +264,14 @@ struct SILDeclRef {
260264
return loc.get<FileUnit *>();
261265
}
262266

267+
/// Get ModuleDecl that contains the SILDeclRef
268+
ModuleDecl *getModuleContext() const;
269+
263270
/// Retrieves the ASTContext from the underlying AST node being stored.
264271
ASTContext &getASTContext() const;
265272

266273
llvm::Optional<AnyFunctionRef> getAnyFunctionRef() const;
267-
274+
268275
SILLocation getAsRegularLocation() const;
269276

270277
enum class ManglingKind {

lib/AST/DeclContext.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,14 +1221,15 @@ bool DeclContext::isClassConstrainedProtocolExtension() const {
12211221
bool DeclContext::isAsyncContext() const {
12221222
switch (getContextKind()) {
12231223
case DeclContextKind::Initializer:
1224-
case DeclContextKind::TopLevelCodeDecl:
12251224
case DeclContextKind::EnumElementDecl:
12261225
case DeclContextKind::ExtensionDecl:
12271226
case DeclContextKind::SerializedLocal:
12281227
case DeclContextKind::Module:
1229-
case DeclContextKind::FileUnit:
12301228
case DeclContextKind::GenericTypeDecl:
12311229
return false;
1230+
case DeclContextKind::FileUnit:
1231+
case DeclContextKind::TopLevelCodeDecl:
1232+
return getASTContext().LangOpts.EnableExperimentalAsyncTopLevel;
12321233
case DeclContextKind::AbstractClosureExpr:
12331234
return cast<AbstractClosureExpr>(this)->isBodyAsync();
12341235
case DeclContextKind::AbstractFunctionDecl: {

lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,16 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
473473
Opts.DisableImplicitConcurrencyModuleImport |=
474474
Args.hasArg(OPT_disable_implicit_concurrency_module_import);
475475

476+
Opts.EnableExperimentalAsyncTopLevel |=
477+
Args.hasArg(OPT_enable_experimental_async_top_level);
478+
476479
/// experimental distributed also implicitly enables experimental concurrency
477480
Opts.EnableExperimentalDistributed |=
478481
Args.hasArg(OPT_enable_experimental_distributed);
479482
Opts.EnableExperimentalConcurrency |=
480483
Args.hasArg(OPT_enable_experimental_distributed);
484+
Opts.EnableExperimentalConcurrency |=
485+
Args.hasArg(OPT_enable_experimental_async_top_level);
481486

482487
Opts.DiagnoseInvalidEphemeralnessAsError |=
483488
Args.hasArg(OPT_enable_invalid_ephemeralness_as_error);

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,14 @@ SILDeclRef SILDeclRef::getAsyncMainDeclEntryPoint(ValueDecl *decl) {
459459
return result;
460460
}
461461

462+
SILDeclRef SILDeclRef::getAsyncMainFileEntryPoint(FileUnit *file) {
463+
assert(file->hasEntryPoint() && !file->getMainDecl());
464+
SILDeclRef result;
465+
result.loc = file;
466+
result.kind = Kind::AsyncEntryPoint;
467+
return result;
468+
}
469+
462470
SILDeclRef SILDeclRef::getMainFileEntryPoint(FileUnit *file) {
463471
assert(file->hasEntryPoint() && !file->getMainDecl());
464472
SILDeclRef result;
@@ -492,6 +500,19 @@ FuncDecl *SILDeclRef::getFuncDecl() const {
492500
return dyn_cast<FuncDecl>(getDecl());
493501
}
494502

503+
ModuleDecl *SILDeclRef::getModuleContext() const {
504+
if (hasDecl()) {
505+
return getDecl()->getModuleContext();
506+
} else if (hasFileUnit()) {
507+
return getFileUnit()->getParentModule();
508+
} else if (hasClosureExpr()) {
509+
return getClosureExpr()->getParentModule();
510+
} else if (hasAutoClosureExpr()) {
511+
return getAutoClosureExpr()->getParentModule();
512+
}
513+
llvm_unreachable("Unknown declaration reference");
514+
}
515+
495516
bool SILDeclRef::isSetter() const {
496517
if (!hasDecl())
497518
return false;

lib/SILGen/SILGen.cpp

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,7 @@ namespace {
19461946
class SourceFileScope {
19471947
SILGenModule &sgm;
19481948
Optional<Scope> scope;
1949+
bool isAsyncTopLevel = false;
19491950
public:
19501951
SourceFileScope(SILGenModule &sgm, SourceFile *sf) : sgm(sgm) {
19511952
// If this is the script-mode file for the module, create a toplevel.
@@ -1955,30 +1956,39 @@ class SourceFileScope {
19551956
sgm.getASTContext().getEntryPointFunctionName()) &&
19561957
"already emitted toplevel?!");
19571958

1958-
RegularLocation TopLevelLoc = RegularLocation::getModuleLocation();
1959-
auto ref = SILDeclRef::getMainFileEntryPoint(sf);
1960-
auto *toplevel = sgm.getFunction(ref, ForDefinition);
1959+
auto mainEntryRef = SILDeclRef::getMainFileEntryPoint(sf);
1960+
SILFunction * toplevel = sgm.getFunction(mainEntryRef, ForDefinition);
19611961
toplevel->setBare(IsBare);
19621962

1963-
// Assign a debug scope pointing into the void to the top level function.
1964-
toplevel->setDebugScope(new (sgm.M) SILDebugScope(TopLevelLoc, toplevel));
1963+
if (sf->isAsyncContext()) {
1964+
isAsyncTopLevel = true;
1965+
auto asyncEntryRef = SILDeclRef::getAsyncMainFileEntryPoint(sf);
1966+
SILFunction * asyncTopLevel = sgm.getFunction(asyncEntryRef, ForDefinition);
1967+
SILGenFunction(sgm, *toplevel, sf).emitAsyncMainThreadStart(asyncEntryRef);
1968+
toplevel = asyncTopLevel;
1969+
}
19651970

19661971
sgm.TopLevelSGF = new SILGenFunction(sgm, *toplevel, sf);
19671972
sgm.TopLevelSGF->MagicFunctionName = sgm.SwiftModule->getName();
19681973
auto moduleCleanupLoc = CleanupLocation::getModuleCleanupLocation();
1969-
sgm.TopLevelSGF->prepareEpilog(None, true, moduleCleanupLoc);
19701974

1971-
// Create the argc and argv arguments.
1972-
auto prologueLoc = RegularLocation::getModuleLocation();
1973-
prologueLoc.markAsPrologue();
1974-
auto entry = sgm.TopLevelSGF->B.getInsertionBB();
1975-
auto context = sgm.TopLevelSGF->getTypeExpansionContext();
1976-
auto paramTypeIter = sgm.TopLevelSGF->F.getConventions()
1977-
.getParameterSILTypes(context)
1978-
.begin();
1979-
entry->createFunctionArgument(*paramTypeIter);
1980-
entry->createFunctionArgument(*std::next(paramTypeIter));
1975+
sgm.TopLevelSGF->prepareEpilog(None, true, moduleCleanupLoc);
19811976

1977+
// emitAsyncMainThreadStart will handle creating argc argv
1978+
// for the async case
1979+
if (!sf->isAsyncContext()) {
1980+
// Create the argc and argv arguments.
1981+
auto prologueLoc = RegularLocation::getModuleLocation();
1982+
prologueLoc.markAsPrologue();
1983+
auto entry = sgm.TopLevelSGF->B.getInsertionBB();
1984+
auto context = sgm.TopLevelSGF->getTypeExpansionContext();
1985+
auto paramTypeIter = sgm.TopLevelSGF->F.getConventions()
1986+
.getParameterSILTypes(context)
1987+
.begin();
1988+
1989+
entry->createFunctionArgument(*paramTypeIter);
1990+
entry->createFunctionArgument(*std::next(paramTypeIter));
1991+
}
19821992
scope.emplace(sgm.TopLevelSGF->Cleanups, moduleCleanupLoc);
19831993
}
19841994
}
@@ -1998,8 +2008,23 @@ class SourceFileScope {
19982008
auto returnLoc = returnInfo.second;
19992009
returnLoc.markAutoGenerated();
20002010

2001-
SILType returnType = SGF.F.getConventions().getSingleSILResultType(
2002-
SGF.getTypeExpansionContext());
2011+
SILFunction *exitFunc = nullptr;
2012+
2013+
SILType returnType;
2014+
if (isAsyncTopLevel) {
2015+
FuncDecl *exitFuncDecl = sgm.getExit();
2016+
assert(exitFuncDecl && "Failed to find exit function declaration");
2017+
exitFunc = sgm.getFunction(
2018+
SILDeclRef(exitFuncDecl, SILDeclRef::Kind::Func, /*isForeign*/true),
2019+
NotForDefinition);
2020+
SILFunctionType & funcType = *exitFunc->getLoweredType().getAs<SILFunctionType>();
2021+
returnType = SILType::getPrimitiveObjectType(
2022+
funcType.getParameters().front().getInterfaceType());
2023+
} else {
2024+
returnType = SGF.F.getConventions().getSingleSILResultType(
2025+
SGF.getTypeExpansionContext());
2026+
}
2027+
20032028
auto emitTopLevelReturnValue = [&](unsigned value) -> SILValue {
20042029
// Create an integer literal for the value.
20052030
auto litType = SILType::getBuiltinIntegerType(32, sgm.getASTContext());
@@ -2060,8 +2085,16 @@ class SourceFileScope {
20602085
}
20612086

20622087
// Return.
2063-
if (SGF.B.hasValidInsertionPoint())
2064-
SGF.B.createReturn(returnLoc, returnValue);
2088+
if (SGF.B.hasValidInsertionPoint()) {
2089+
2090+
if (isAsyncTopLevel) {
2091+
SILValue exitCall = SGF.B.createFunctionRef(moduleLoc, exitFunc);
2092+
SGF.B.createApply(moduleLoc, exitCall, {}, {returnValue});
2093+
SGF.B.createUnreachable(moduleLoc);
2094+
} else {
2095+
SGF.B.createReturn(returnLoc, returnValue);
2096+
}
2097+
}
20652098

20662099
// Okay, we're done emitting the top-level function; destroy the
20672100
// emitter and verify the result.

lib/SILGen/SILGenFunction.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
864864
entryBlock->createFunctionArgument(*std::next(paramTypeIter)); // argv
865865

866866
// Lookup necessary functions
867-
swift::ASTContext &ctx = entryPoint.getDecl()->getASTContext();
867+
swift::ASTContext &ctx = entryPoint.getASTContext();
868868

869869
B.setInsertionPoint(entryBlock);
870870

@@ -880,7 +880,7 @@ void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
880880

881881
// Call CreateAsyncTask
882882
FuncDecl *builtinDecl = cast<FuncDecl>(getBuiltinValueDecl(
883-
getASTContext(),
883+
ctx,
884884
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::CreateAsyncTask))));
885885
auto subs = SubstitutionMap::get(builtinDecl->getGenericSignature(),
886886
{TupleType::getEmpty(ctx)},
@@ -922,6 +922,7 @@ void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
922922
JobType, {}, {task});
923923
jobResult = wrapCallArgs(jobResult, swiftJobRunFuncDecl, 0);
924924

925+
ModuleDecl * moduleDecl = entryPoint.getModuleContext();
925926
// Get main executor
926927
FuncDecl *getMainExecutorFuncDecl = SGM.getGetMainExecutor();
927928
if (!getMainExecutorFuncDecl) {
@@ -931,18 +932,18 @@ void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
931932
// @_silgen_name("swift_task_getMainExecutor")
932933
// internal func _getMainExecutor() -> Builtin.Executor
933934

934-
ParameterList *emptyParams = ParameterList::createEmpty(getASTContext());
935+
ParameterList *emptyParams = ParameterList::createEmpty(ctx);
935936
getMainExecutorFuncDecl = FuncDecl::createImplicit(
936-
getASTContext(), StaticSpellingKind::None,
937+
ctx, StaticSpellingKind::None,
937938
DeclName(
938-
getASTContext(),
939-
DeclBaseName(getASTContext().getIdentifier("_getMainExecutor")),
939+
ctx,
940+
DeclBaseName(ctx.getIdentifier("_getMainExecutor")),
940941
/*Arguments*/ emptyParams),
941942
{}, /*async*/ false, /*throws*/ false, {}, emptyParams,
942-
getASTContext().TheExecutorType,
943-
entryPoint.getDecl()->getModuleContext());
943+
ctx.TheExecutorType,
944+
moduleDecl);
944945
getMainExecutorFuncDecl->getAttrs().add(
945-
new (getASTContext())
946+
new (ctx)
946947
SILGenNameAttr("swift_task_getMainExecutor", /*implicit*/ true));
947948
}
948949

@@ -972,8 +973,7 @@ void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
972973
DeclBaseName(getASTContext().getIdentifier("_asyncMainDrainQueue")),
973974
/*Arguments*/ emptyParams),
974975
{}, /*async*/ false, /*throws*/ false, {}, emptyParams,
975-
getASTContext().getNeverType(),
976-
entryPoint.getDecl()->getModuleContext());
976+
getASTContext().getNeverType(), moduleDecl);
977977
drainQueueFuncDecl->getAttrs().add(new (getASTContext()) SILGenNameAttr(
978978
"swift_task_asyncMainDrainQueue", /*implicit*/ true));
979979
}

lib/Sema/TypeCheckEffects.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,8 +1491,10 @@ class Context {
14911491

14921492
static Context forTopLevelCode(TopLevelCodeDecl *D) {
14931493
// Top-level code implicitly handles errors.
1494-
// TODO: Eventually, it will handle async as well.
1495-
return Context(/*handlesErrors=*/true, /*handlesAsync=*/false, None);
1494+
return Context(/*handlesErrors=*/true,
1495+
/*handlesAsync=*/
1496+
D->getASTContext().LangOpts.EnableExperimentalAsyncTopLevel,
1497+
None);
14961498
}
14971499

14981500
static Context forFunction(AbstractFunctionDecl *D) {

0 commit comments

Comments
 (0)