Skip to content

Commit d240ffa

Browse files
authored
Merge pull request #67747 from zachary0kent/sil-gen-top-level
[SILGen] Unified Entry Point Emission
2 parents b05ceb9 + db1cdbd commit d240ffa

30 files changed

+838
-659
lines changed

lib/SILGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_swift_host_library(swiftSILGen STATIC
3535
SILGenRequests.cpp
3636
SILGenStmt.cpp
3737
SILGenThunk.cpp
38+
SILGenTopLevel.cpp
3839
SILGenType.cpp)
3940
target_link_libraries(swiftSILGen PRIVATE
4041
swiftSerialization

lib/SILGen/SILGen.cpp

Lines changed: 14 additions & 266 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "RValue.h"
1717
#include "SILGenFunction.h"
1818
#include "SILGenFunctionBuilder.h"
19+
#include "SILGenTopLevel.h"
1920
#include "Scope.h"
2021
#include "swift/AST/Decl.h"
2122
#include "swift/AST/DiagnosticsSIL.h"
@@ -51,7 +52,7 @@ using namespace Lowering;
5152
//===----------------------------------------------------------------------===//
5253

5354
SILGenModule::SILGenModule(SILModule &M, ModuleDecl *SM)
54-
: M(M), Types(M.Types), SwiftModule(SM), TopLevelSGF(nullptr),
55+
: M(M), Types(M.Types), SwiftModule(SM),
5556
FileIDsByFilePath(SM->computeFileIDMap(/*shouldDiagnose=*/true)) {
5657
const SILOptions &Opts = M.getOptions();
5758
if (!Opts.UseProfile.empty()) {
@@ -70,7 +71,6 @@ SILGenModule::SILGenModule(SILModule &M, ModuleDecl *SM)
7071
}
7172

7273
SILGenModule::~SILGenModule() {
73-
assert(!TopLevelSGF && "active source file lowering!?");
7474

7575
// Update the linkage of external private functions to public_external,
7676
// because there is no private_external linkage. External private functions
@@ -962,7 +962,6 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
962962
auto *pbd = var->getParentPatternBinding();
963963
unsigned idx = pbd->getPatternEntryIndexForVarDecl(var);
964964
auto *initDC = pbd->getInitContext(idx);
965-
auto captureInfo = pbd->getCaptureInfo(idx);
966965
auto *init = constant.getInitializationExpr();
967966
assert(init);
968967

@@ -971,17 +970,6 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
971970
PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f);
972971
f->createProfiler(constant);
973972
SILGenFunction SGF(*this, *f, initDC);
974-
975-
// If this is a stored property initializer inside a type at global scope,
976-
// it may close over a global variable. If we're emitting top-level code,
977-
// then emit a "mark_function_escape" that lists the captured global
978-
// variables so that definite initialization can reason about this
979-
// escape point.
980-
if (!var->getDeclContext()->isLocalContext() && TopLevelSGF &&
981-
TopLevelSGF->B.hasValidInsertionPoint()) {
982-
emitMarkFunctionEscapeForTopLevelCodeGlobals(var, captureInfo);
983-
}
984-
985973
SGF.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement=*/true);
986974
postEmitFunction(constant, f);
987975
break;
@@ -1107,9 +1095,15 @@ void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
11071095
case SILDeclRef::Kind::AsyncEntryPoint:
11081096
case SILDeclRef::Kind::EntryPoint: {
11091097
f->setBare(IsBare);
1098+
if (constant.hasFileUnit()) {
1099+
auto *File = constant.getFileUnit();
1100+
// In script mode
1101+
assert(isa<SourceFile>(File) && "Emitting entry-point of non source file?!");
1102+
auto *SF = cast<SourceFile>(File);
1103+
emitEntryPoint(SF, f);
1104+
return;
1105+
}
11101106

1111-
// TODO: Handle main SourceFile emission (currently done by
1112-
// SourceFileScope).
11131107
auto loc = constant.getAsRegularLocation();
11141108
preEmitFunction(constant, f, loc);
11151109
auto *decl = constant.getDecl();
@@ -1363,41 +1357,10 @@ void SILGenModule::emitDifferentiabilityWitness(
13631357
vjp);
13641358
}
13651359

1366-
void SILGenModule::
1367-
emitMarkFunctionEscapeForTopLevelCodeGlobals(SILLocation loc,
1368-
CaptureInfo captureInfo) {
1369-
assert(TopLevelSGF && TopLevelSGF->B.hasValidInsertionPoint()
1370-
&& "no valid code generator for top-level function?!");
1371-
1372-
SmallVector<SILValue, 4> Captures;
1373-
1374-
for (auto capture : captureInfo.getCaptures()) {
1375-
// Decls captured by value don't escape.
1376-
auto It = TopLevelSGF->VarLocs.find(capture.getDecl());
1377-
if (It == TopLevelSGF->VarLocs.end() ||
1378-
!It->getSecond().value->getType().isAddress())
1379-
continue;
1380-
1381-
Captures.push_back(It->second.value);
1382-
}
1383-
1384-
if (!Captures.empty())
1385-
TopLevelSGF->B.createMarkFunctionEscape(loc, Captures);
1386-
}
1387-
13881360
void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) {
13891361
// Emit default arguments and property wrapper initializers.
13901362
emitArgumentGenerators(AFD, AFD->getParameters());
13911363

1392-
// If this is a function at global scope, it may close over a global variable.
1393-
// If we're emitting top-level code, then emit a "mark_function_escape" that
1394-
// lists the captured global variables so that definite initialization can
1395-
// reason about this escape point.
1396-
if (!AFD->getDeclContext()->isLocalContext() &&
1397-
TopLevelSGF && TopLevelSGF->B.hasValidInsertionPoint()) {
1398-
emitMarkFunctionEscapeForTopLevelCodeGlobals(AFD, AFD->getCaptureInfo());
1399-
}
1400-
14011364
// If the declaration is exported as a C function, emit its native-to-foreign
14021365
// thunk too, if it wasn't already forced.
14031366
if (AFD->getAttrs().hasAttribute<CDeclAttr>()) {
@@ -1770,7 +1733,6 @@ void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) {
17701733
}
17711734

17721735
void SILGenModule::visitPatternBindingDecl(PatternBindingDecl *pd) {
1773-
assert(!TopLevelSGF && "script mode PBDs should be in TopLevelCodeDecls");
17741736
for (auto i : range(pd->getNumPatternEntries()))
17751737
if (pd->getExecutableInit(i))
17761738
emitGlobalInitialization(pd, i);
@@ -1964,225 +1926,8 @@ void SILGenModule::visitPoundDiagnosticDecl(PoundDiagnosticDecl *PDD) {
19641926
// Nothing to do for #error/#warning; they've already been emitted.
19651927
}
19661928

1967-
void SILGenModule::visitTopLevelCodeDecl(TopLevelCodeDecl *td) {
1968-
assert(TopLevelSGF && "top-level code in a non-main source file!");
1969-
1970-
if (!TopLevelSGF->B.hasValidInsertionPoint())
1971-
return;
1972-
1973-
TopLevelSGF->emitProfilerIncrement(td->getBody());
1974-
1975-
DebugScope DS(*TopLevelSGF, CleanupLocation(td));
1976-
1977-
for (auto &ESD : td->getBody()->getElements()) {
1978-
if (!TopLevelSGF->B.hasValidInsertionPoint()) {
1979-
if (auto *S = ESD.dyn_cast<Stmt*>()) {
1980-
if (S->isImplicit())
1981-
continue;
1982-
} else if (auto *E = ESD.dyn_cast<Expr*>()) {
1983-
if (E->isImplicit())
1984-
continue;
1985-
}
1986-
1987-
diagnose(ESD.getStartLoc(), diag::unreachable_code);
1988-
// There's no point in trying to emit anything else.
1989-
return;
1990-
}
1991-
1992-
if (auto *S = ESD.dyn_cast<Stmt*>()) {
1993-
TopLevelSGF->emitStmt(S);
1994-
} else if (auto *E = ESD.dyn_cast<Expr*>()) {
1995-
TopLevelSGF->emitIgnoredExpr(E);
1996-
} else {
1997-
TopLevelSGF->visit(ESD.get<Decl*>());
1998-
}
1999-
}
2000-
}
2001-
20021929
namespace {
20031930

2004-
/// An RAII class to scope source file codegen.
2005-
class SourceFileScope {
2006-
SILGenModule &sgm;
2007-
SILDeclRef EntryRef;
2008-
llvm::Optional<Scope> scope;
2009-
bool isAsyncTopLevel = false;
2010-
public:
2011-
SourceFileScope(SILGenModule &sgm, SourceFile *sf) : sgm(sgm) {
2012-
// If this is the script-mode file for the module, create a toplevel.
2013-
// TODO: We need to unify emission of the entry point such that we walk
2014-
// all of the TopLevelCodeDecls in one shot. This will be needed in order
2015-
// to requestify entry point emission.
2016-
if (sf->isScriptMode()) {
2017-
assert(!sgm.TopLevelSGF && "already emitted toplevel?!");
2018-
assert(!sgm.M.lookUpFunction(
2019-
sgm.getASTContext().getEntryPointFunctionName()) &&
2020-
"already emitted toplevel?!");
2021-
2022-
auto mainEntryRef = SILDeclRef::getMainFileEntryPoint(sf);
2023-
SILFunction * toplevel = sgm.getFunction(mainEntryRef, ForDefinition);
2024-
toplevel->setBare(IsBare);
2025-
EntryRef = mainEntryRef;
2026-
2027-
if (sf->isAsyncContext()) {
2028-
isAsyncTopLevel = true;
2029-
auto asyncEntryRef = SILDeclRef::getAsyncMainFileEntryPoint(sf);
2030-
auto *asyncTopLevel = sgm.getFunction(asyncEntryRef, ForDefinition);
2031-
SILGenFunction(sgm, *toplevel, sf).emitAsyncMainThreadStart(asyncEntryRef);
2032-
toplevel = asyncTopLevel;
2033-
EntryRef = asyncEntryRef;
2034-
}
2035-
2036-
toplevel->createProfiler(EntryRef);
2037-
2038-
sgm.TopLevelSGF = new SILGenFunction(sgm, *toplevel, sf);
2039-
sgm.TopLevelSGF->MagicFunctionName = sgm.SwiftModule->getName();
2040-
auto moduleCleanupLoc = CleanupLocation::getModuleCleanupLocation();
2041-
2042-
sgm.TopLevelSGF->prepareEpilog(llvm::None, true, moduleCleanupLoc);
2043-
2044-
auto prologueLoc = RegularLocation::getModuleLocation();
2045-
prologueLoc.markAsPrologue();
2046-
if (sf->isAsyncContext()) {
2047-
// emitAsyncMainThreadStart will create argc and argv.
2048-
// Just set the main actor as the expected executor; we should
2049-
// already be running on it.
2050-
SILValue executor = sgm.TopLevelSGF->emitMainExecutor(prologueLoc);
2051-
sgm.TopLevelSGF->ExpectedExecutor =
2052-
sgm.TopLevelSGF->B.createOptionalSome(
2053-
prologueLoc, executor,
2054-
SILType::getOptionalType(executor->getType()));
2055-
} else {
2056-
// Create the argc and argv arguments.
2057-
auto entry = sgm.TopLevelSGF->B.getInsertionBB();
2058-
auto context = sgm.TopLevelSGF->getTypeExpansionContext();
2059-
auto paramTypeIter = sgm.TopLevelSGF->F.getConventions()
2060-
.getParameterSILTypes(context)
2061-
.begin();
2062-
2063-
entry->createFunctionArgument(*paramTypeIter);
2064-
entry->createFunctionArgument(*std::next(paramTypeIter));
2065-
}
2066-
scope.emplace(sgm.TopLevelSGF->Cleanups, moduleCleanupLoc);
2067-
}
2068-
}
2069-
2070-
~SourceFileScope() {
2071-
if (sgm.TopLevelSGF) {
2072-
scope.reset();
2073-
2074-
// Unregister the top-level function emitter.
2075-
auto &SGF = *sgm.TopLevelSGF;
2076-
sgm.TopLevelSGF = nullptr;
2077-
2078-
// Write out the epilog.
2079-
auto moduleLoc = RegularLocation::getModuleLocation();
2080-
moduleLoc.markAutoGenerated();
2081-
auto returnInfo = SGF.emitEpilogBB(moduleLoc);
2082-
auto returnLoc = returnInfo.second;
2083-
returnLoc.markAutoGenerated();
2084-
2085-
SILFunction *exitFunc = nullptr;
2086-
2087-
SILType returnType;
2088-
if (isAsyncTopLevel) {
2089-
FuncDecl *exitFuncDecl = sgm.getExit();
2090-
assert(exitFuncDecl && "Failed to find exit function declaration");
2091-
exitFunc = sgm.getFunction(
2092-
SILDeclRef(exitFuncDecl, SILDeclRef::Kind::Func, /*isForeign*/true),
2093-
NotForDefinition);
2094-
SILFunctionType & funcType = *exitFunc->getLoweredType().getAs<SILFunctionType>();
2095-
returnType = SILType::getPrimitiveObjectType(
2096-
funcType.getParameters().front().getInterfaceType());
2097-
} else {
2098-
returnType = SGF.F.getConventions().getSingleSILResultType(
2099-
SGF.getTypeExpansionContext());
2100-
}
2101-
2102-
auto emitTopLevelReturnValue = [&](unsigned value) -> SILValue {
2103-
// Create an integer literal for the value.
2104-
auto litType = SILType::getBuiltinIntegerType(32, sgm.getASTContext());
2105-
SILValue retValue =
2106-
SGF.B.createIntegerLiteral(moduleLoc, litType, value);
2107-
2108-
// Wrap that in a struct if necessary.
2109-
if (litType != returnType) {
2110-
retValue = SGF.B.createStruct(moduleLoc, returnType, retValue);
2111-
}
2112-
return retValue;
2113-
};
2114-
2115-
// Fallthrough should signal a normal exit by returning 0.
2116-
SILValue returnValue;
2117-
if (SGF.B.hasValidInsertionPoint())
2118-
returnValue = emitTopLevelReturnValue(0);
2119-
2120-
// Handle the implicit rethrow block.
2121-
auto rethrowBB = SGF.ThrowDest.getBlock();
2122-
SGF.ThrowDest = JumpDest::invalid();
2123-
2124-
// If the rethrow block wasn't actually used, just remove it.
2125-
if (rethrowBB->pred_empty()) {
2126-
SGF.eraseBasicBlock(rethrowBB);
2127-
2128-
// Otherwise, we need to produce a unified return block.
2129-
} else {
2130-
auto returnBB = SGF.createBasicBlock();
2131-
if (SGF.B.hasValidInsertionPoint())
2132-
SGF.B.createBranch(returnLoc, returnBB, returnValue);
2133-
returnValue =
2134-
returnBB->createPhiArgument(returnType, OwnershipKind::Owned);
2135-
SGF.B.emitBlock(returnBB);
2136-
2137-
// Emit the rethrow block.
2138-
SILGenSavedInsertionPoint savedIP(SGF, rethrowBB,
2139-
FunctionSection::Postmatter);
2140-
2141-
// Log the error.
2142-
SILValue error = rethrowBB->getArgument(0);
2143-
SGF.B.createBuiltin(moduleLoc,
2144-
sgm.getASTContext().getIdentifier("errorInMain"),
2145-
sgm.Types.getEmptyTupleType(), {}, {error});
2146-
2147-
// Then end the lifetime of the error.
2148-
//
2149-
// We do this to appease the ownership verifier. We do not care about
2150-
// actually destroying the value since we are going to immediately exit,
2151-
// so this saves us a slight bit of code-size since end_lifetime is
2152-
// stripped out after ownership is removed.
2153-
SGF.B.createEndLifetime(moduleLoc, error);
2154-
2155-
// Signal an abnormal exit by returning 1.
2156-
SGF.Cleanups.emitCleanupsForReturn(CleanupLocation(moduleLoc),
2157-
IsForUnwind);
2158-
SGF.B.createBranch(returnLoc, returnBB, emitTopLevelReturnValue(1));
2159-
}
2160-
2161-
// Return.
2162-
if (SGF.B.hasValidInsertionPoint()) {
2163-
2164-
if (isAsyncTopLevel) {
2165-
SILValue exitCall = SGF.B.createFunctionRef(moduleLoc, exitFunc);
2166-
SGF.B.createApply(moduleLoc, exitCall, {}, {returnValue});
2167-
SGF.B.createUnreachable(moduleLoc);
2168-
} else {
2169-
SGF.B.createReturn(returnLoc, returnValue);
2170-
}
2171-
}
2172-
2173-
// Okay, we're done emitting the top-level function; destroy the
2174-
// emitter and verify the result.
2175-
SILFunction *toplevel = &SGF.getFunction();
2176-
delete &SGF;
2177-
2178-
LLVM_DEBUG(llvm::dbgs() << "lowered toplevel sil:\n";
2179-
toplevel->print(llvm::dbgs()));
2180-
toplevel->verifyIncompleteOSSA();
2181-
sgm.emitLazyConformancesForFunction(toplevel);
2182-
}
2183-
}
2184-
};
2185-
21861931
// An RAII object that constructs a \c SILGenModule instance.
21871932
// On destruction, delayed definitions are automatically emitted.
21881933
class SILGenModuleRAII {
@@ -2193,7 +1938,10 @@ class SILGenModuleRAII {
21931938
// Type-check the file if we haven't already.
21941939
performTypeChecking(*sf);
21951940

2196-
SourceFileScope scope(SGM, sf);
1941+
if (sf->isScriptMode()) {
1942+
SGM.emitEntryPoint(sf);
1943+
}
1944+
21971945
for (auto *D : sf->getTopLevelDecls()) {
21981946
// Emit auxiliary decls.
21991947
D->visitAuxiliaryDecls([&](Decl *auxiliaryDecl) {

0 commit comments

Comments
 (0)