mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1262 lines
46 KiB
C++
1262 lines
46 KiB
C++
//===--- SILGen.cpp - Implements Lowering of ASTs -> SIL ------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "silgen"
|
|
#include "SILGenFunction.h"
|
|
#include "Scope.h"
|
|
#include "swift/Strings.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/AST/DiagnosticsSIL.h"
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/PrettyStackTrace.h"
|
|
#include "swift/AST/ResilienceExpansion.h"
|
|
#include "swift/Basic/Timer.h"
|
|
#include "swift/ClangImporter/ClangModule.h"
|
|
#include "swift/Serialization/SerializedModuleLoader.h"
|
|
#include "swift/Serialization/SerializedSILLoader.h"
|
|
#include "swift/SIL/PrettyStackTrace.h"
|
|
#include "swift/SIL/SILArgument.h"
|
|
#include "swift/SIL/SILDebugScope.h"
|
|
#include "swift/Subsystems.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "RValue.h"
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILGenModule Class implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SILGenModule::SILGenModule(SILModule &M, Module *SM, bool makeModuleFragile)
|
|
: M(M), Types(M.Types), SwiftModule(SM), TopLevelSGF(nullptr),
|
|
Profiler(nullptr), makeModuleFragile(makeModuleFragile) {
|
|
}
|
|
|
|
SILGenModule::~SILGenModule() {
|
|
assert(!TopLevelSGF && "active source file lowering!?");
|
|
M.verify();
|
|
}
|
|
|
|
static SILDeclRef
|
|
getBridgingFn(Optional<SILDeclRef> &cacheSlot,
|
|
SILGenModule &SGM,
|
|
Identifier moduleName,
|
|
StringRef functionName,
|
|
Optional<std::initializer_list<Type>> inputTypes,
|
|
Optional<Type> outputType) {
|
|
// FIXME: the optionality of outputType and the presence of trustInputTypes
|
|
// are hacks for cases where coming up with those types is complicated, i.e.,
|
|
// when dealing with generic bridging functions.
|
|
|
|
if (!cacheSlot) {
|
|
ASTContext &ctx = SGM.M.getASTContext();
|
|
Module *mod = ctx.getLoadedModule(moduleName);
|
|
if (!mod) {
|
|
SGM.diagnose(SourceLoc(), diag::bridging_module_missing,
|
|
moduleName.str(), functionName);
|
|
llvm::report_fatal_error("unable to set up the ObjC bridge!");
|
|
}
|
|
|
|
SmallVector<ValueDecl *, 2> decls;
|
|
mod->lookupValue(/*accessPath=*/{}, ctx.getIdentifier(functionName),
|
|
NLKind::QualifiedLookup, decls);
|
|
if (decls.empty()) {
|
|
SGM.diagnose(SourceLoc(), diag::bridging_function_missing,
|
|
moduleName.str(), functionName);
|
|
llvm::report_fatal_error("unable to set up the ObjC bridge!");
|
|
}
|
|
if (decls.size() != 1) {
|
|
SGM.diagnose(SourceLoc(), diag::bridging_function_overloaded,
|
|
moduleName.str(), functionName);
|
|
llvm::report_fatal_error("unable to set up the ObjC bridge!");
|
|
}
|
|
|
|
auto *fd = dyn_cast<FuncDecl>(decls.front());
|
|
if (!fd) {
|
|
SGM.diagnose(SourceLoc(), diag::bridging_function_not_function,
|
|
moduleName.str(), functionName);
|
|
llvm::report_fatal_error("unable to set up the ObjC bridge!");
|
|
}
|
|
|
|
assert(fd->hasType() && "bridging functions must be type-checked");
|
|
|
|
// Check that the function takes the expected arguments and returns the
|
|
// expected result type.
|
|
SILDeclRef c(fd);
|
|
auto funcInfo = SGM.getConstantType(c).castTo<SILFunctionType>();
|
|
|
|
if (inputTypes) {
|
|
auto toSILType = [&SGM](Type ty) { return SGM.getLoweredType(ty); };
|
|
if (funcInfo->hasIndirectResults()
|
|
|| funcInfo->getParameters().size() != inputTypes->size()
|
|
|| !std::equal(funcInfo->getParameterSILTypes().begin(),
|
|
funcInfo->getParameterSILTypes().end(),
|
|
makeTransformIterator(inputTypes->begin(),
|
|
toSILType))) {
|
|
SGM.diagnose(fd->getLoc(), diag::bridging_function_not_correct_type,
|
|
moduleName.str(), functionName);
|
|
llvm::report_fatal_error("unable to set up the ObjC bridge!");
|
|
}
|
|
}
|
|
|
|
if (outputType &&
|
|
funcInfo->getSingleResult().getSILType()
|
|
!= SGM.getLoweredType(*outputType)) {
|
|
SGM.diagnose(fd->getLoc(), diag::bridging_function_not_correct_type,
|
|
moduleName.str(), functionName);
|
|
llvm::report_fatal_error("unable to set up the ObjC bridge!");
|
|
}
|
|
|
|
cacheSlot = c;
|
|
}
|
|
|
|
DEBUG(llvm::dbgs() << "bridging function "
|
|
<< moduleName << '.' << functionName
|
|
<< " mapped to ";
|
|
cacheSlot->print(llvm::dbgs()));
|
|
|
|
return *cacheSlot;
|
|
}
|
|
|
|
#define REQUIRED(X) { Types.get##X##Type() }
|
|
#define OPTIONAL(X) { OptionalType::get(Types.get##X##Type()) }
|
|
#define GENERIC(X) None
|
|
|
|
#define GET_BRIDGING_FN(Module, FromKind, FromTy, ToKind, ToTy) \
|
|
SILDeclRef SILGenModule::get##FromTy##To##ToTy##Fn() { \
|
|
return getBridgingFn(FromTy##To##ToTy##Fn, *this, \
|
|
getASTContext().Id_##Module, \
|
|
"_convert" #FromTy "To" #ToTy, \
|
|
FromKind(FromTy), \
|
|
ToKind(ToTy)); \
|
|
}
|
|
|
|
GET_BRIDGING_FN(Darwin, REQUIRED, Bool, REQUIRED, DarwinBoolean)
|
|
GET_BRIDGING_FN(Darwin, REQUIRED, DarwinBoolean, REQUIRED, Bool)
|
|
GET_BRIDGING_FN(ObjectiveC, REQUIRED, Bool, REQUIRED, ObjCBool)
|
|
GET_BRIDGING_FN(ObjectiveC, REQUIRED, ObjCBool, REQUIRED, Bool)
|
|
GET_BRIDGING_FN(Foundation, OPTIONAL, NSError, REQUIRED, ErrorProtocol)
|
|
GET_BRIDGING_FN(Foundation, REQUIRED, ErrorProtocol, REQUIRED, NSError)
|
|
GET_BRIDGING_FN(Foundation, REQUIRED, String, REQUIRED, NSString)
|
|
GET_BRIDGING_FN(Foundation, OPTIONAL, NSString, REQUIRED, String)
|
|
GET_BRIDGING_FN(Foundation, GENERIC, Array, REQUIRED, NSArray)
|
|
GET_BRIDGING_FN(Foundation, OPTIONAL, NSArray, GENERIC, Array)
|
|
GET_BRIDGING_FN(Foundation, GENERIC, Set, REQUIRED, NSSet)
|
|
GET_BRIDGING_FN(Foundation, OPTIONAL, NSSet, GENERIC, Set)
|
|
GET_BRIDGING_FN(Foundation, GENERIC, Dictionary, REQUIRED, NSDictionary)
|
|
GET_BRIDGING_FN(Foundation, OPTIONAL, NSDictionary, GENERIC, Dictionary)
|
|
|
|
#undef GET_BRIDGING_FN
|
|
#undef REQURIED
|
|
#undef OPTIONAL
|
|
#undef GENERIC
|
|
|
|
SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) {
|
|
ASTContext &C = M.getASTContext();
|
|
auto extInfo = SILFunctionType::ExtInfo()
|
|
.withRepresentation(SILFunctionType::Representation::CFunctionPointer);
|
|
|
|
auto findStdlibDecl = [&](StringRef name) -> ValueDecl* {
|
|
if (!getASTContext().getStdlibModule())
|
|
return nullptr;
|
|
SmallVector<ValueDecl*, 1> lookupBuffer;
|
|
getASTContext().getStdlibModule()->lookupValue({},
|
|
getASTContext().getIdentifier(name),
|
|
NLKind::QualifiedLookup,
|
|
lookupBuffer);
|
|
if (lookupBuffer.size() == 1)
|
|
return lookupBuffer[0];
|
|
return nullptr;
|
|
};
|
|
|
|
// Use standard library types if we have them; otherwise, fall back to
|
|
// builtins.
|
|
CanType Int32Ty;
|
|
if (auto Int32Decl = dyn_cast_or_null<TypeDecl>(findStdlibDecl("Int32"))) {
|
|
Int32Ty = Int32Decl->getDeclaredType()->getCanonicalType();
|
|
} else {
|
|
Int32Ty = CanType(BuiltinIntegerType::get(32, C));
|
|
}
|
|
|
|
CanType PtrPtrInt8Ty = C.TheRawPointerType;
|
|
if (auto PointerDecl = C.getUnsafeMutablePointerDecl()) {
|
|
if (auto Int8Decl = cast<TypeDecl>(findStdlibDecl("Int8"))) {
|
|
Type PointerInt8Ty = BoundGenericType::get(PointerDecl,
|
|
nullptr,
|
|
Int8Decl->getDeclaredType());
|
|
PtrPtrInt8Ty = BoundGenericType::get(PointerDecl,
|
|
nullptr,
|
|
PointerInt8Ty)
|
|
->getCanonicalType();
|
|
}
|
|
}
|
|
|
|
SILParameterInfo params[] = {
|
|
SILParameterInfo(Int32Ty, ParameterConvention::Direct_Unowned),
|
|
SILParameterInfo(PtrPtrInt8Ty, ParameterConvention::Direct_Unowned),
|
|
};
|
|
|
|
CanSILFunctionType topLevelType = SILFunctionType::get(nullptr, extInfo,
|
|
ParameterConvention::Direct_Unowned,
|
|
params,
|
|
SILResultInfo(Int32Ty,
|
|
ResultConvention::Unowned),
|
|
None,
|
|
C);
|
|
|
|
return M.getOrCreateFunction(SILLinkage::Public, SWIFT_ENTRY_POINT_FUNCTION,
|
|
topLevelType, nullptr, Loc, IsBare,
|
|
IsNotTransparent, IsNotFragile, IsNotThunk,
|
|
SILFunction::NotRelevant);
|
|
}
|
|
|
|
SILType SILGenModule::getConstantType(SILDeclRef constant) {
|
|
return Types.getConstantType(constant);
|
|
}
|
|
|
|
SILFunction *SILGenModule::getEmittedFunction(SILDeclRef constant,
|
|
ForDefinition_t forDefinition) {
|
|
auto found = emittedFunctions.find(constant);
|
|
if (found != emittedFunctions.end()) {
|
|
SILFunction *F = found->second;
|
|
if (forDefinition) {
|
|
// In all the cases where getConstantLinkage returns something
|
|
// different for ForDefinition, it returns an available-externally
|
|
// linkage.
|
|
if (isAvailableExternally(F->getLinkage())) {
|
|
F->setLinkage(constant.getLinkage(ForDefinition));
|
|
}
|
|
if (makeModuleFragile) {
|
|
F->setFragile(IsFragile);
|
|
}
|
|
}
|
|
return F;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static SILFunction *getFunctionToInsertAfter(SILGenModule &SGM,
|
|
SILDeclRef insertAfter) {
|
|
// If the decl ref was emitted, emit after its function.
|
|
while (insertAfter) {
|
|
auto found = SGM.emittedFunctions.find(insertAfter);
|
|
if (found != SGM.emittedFunctions.end()) {
|
|
return found->second;
|
|
}
|
|
|
|
// Otherwise, try to insert after the function we would be transitively
|
|
// be inserted after.
|
|
auto foundDelayed = SGM.delayedFunctions.find(insertAfter);
|
|
if (foundDelayed != SGM.delayedFunctions.end()) {
|
|
insertAfter = foundDelayed->second.insertAfter;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If the decl ref is nil, just insert at the beginning.
|
|
return nullptr;
|
|
}
|
|
|
|
SILFunction *SILGenModule::getFunction(SILDeclRef constant,
|
|
ForDefinition_t forDefinition) {
|
|
// If we already emitted the function, return it (potentially preparing it
|
|
// for definition).
|
|
if (auto emitted = getEmittedFunction(constant, forDefinition))
|
|
return emitted;
|
|
|
|
// Note: Do not provide any SILLocation. You can set it afterwards.
|
|
auto *F = M.getOrCreateFunction((Decl*)nullptr, constant, forDefinition);
|
|
|
|
assert(F && "SILFunction should have been defined");
|
|
|
|
if (makeModuleFragile) {
|
|
SILLinkage linkage = constant.getLinkage(forDefinition);
|
|
if (linkage != SILLinkage::PublicExternal) {
|
|
F->setFragile(IsFragile);
|
|
}
|
|
}
|
|
|
|
emittedFunctions[constant] = F;
|
|
|
|
// If we delayed emitting this function previously, we need it now.
|
|
auto foundDelayed = delayedFunctions.find(constant);
|
|
if (foundDelayed != delayedFunctions.end()) {
|
|
// Move the function to its proper place within the module.
|
|
M.functions.remove(F);
|
|
SILFunction *insertAfter = getFunctionToInsertAfter(*this,
|
|
foundDelayed->second.insertAfter);
|
|
if (!insertAfter) {
|
|
M.functions.push_front(F);
|
|
} else {
|
|
M.functions.insertAfter(insertAfter->getIterator(), F);
|
|
}
|
|
|
|
forcedFunctions.push_back(*foundDelayed);
|
|
delayedFunctions.erase(foundDelayed);
|
|
} else {
|
|
// We would have registered a delayed function as "last emitted" when we
|
|
// enqueued. If the function wasn't delayed, then we're emitting it now.
|
|
lastEmittedFunction = constant;
|
|
}
|
|
|
|
return F;
|
|
}
|
|
|
|
bool SILGenModule::hasFunction(SILDeclRef constant) {
|
|
return emittedFunctions.count(constant);
|
|
}
|
|
|
|
void SILGenModule::visitFuncDecl(FuncDecl *fd) {
|
|
ProfilerRAII Profiler(*this, fd);
|
|
emitFunction(fd);
|
|
}
|
|
|
|
/// Emit a function now, if it's externally usable or has been referenced in
|
|
/// the current TU, or remember how to emit it later if not.
|
|
template<typename /*void (SILFunction*)*/ Fn>
|
|
void emitOrDelayFunction(SILGenModule &SGM,
|
|
SILDeclRef constant,
|
|
Fn &&emitter) {
|
|
auto emitAfter = SGM.lastEmittedFunction;
|
|
|
|
SILFunction *f = nullptr;
|
|
|
|
// If the function is explicit or may be externally referenced, we must emit
|
|
// it.
|
|
bool mayDelay;
|
|
// Shared thunks and Clang-imported definitions can always be delayed.
|
|
if (constant.isThunk() || constant.isClangImported()) {
|
|
mayDelay = true;
|
|
// Implicit decls may be delayed if they can't be used externally.
|
|
} else {
|
|
auto linkage = constant.getLinkage(ForDefinition);
|
|
mayDelay = constant.isImplicit()
|
|
&& !isPossiblyUsedExternally(linkage, SGM.M.isWholeModule());
|
|
}
|
|
|
|
// Avoid emitting a delayable definition if it hasn't already been referenced.
|
|
if (mayDelay)
|
|
f = SGM.getEmittedFunction(constant, ForDefinition);
|
|
else
|
|
f = SGM.getFunction(constant, ForDefinition);
|
|
|
|
// If we don't want to emit now, remember how for later.
|
|
if (!f) {
|
|
SGM.delayedFunctions.insert({constant, {emitAfter,
|
|
std::forward<Fn>(emitter)}});
|
|
// Even though we didn't emit the function now, update the
|
|
// lastEmittedFunction so that we preserve the original ordering that
|
|
// the symbols would have been emitted in.
|
|
SGM.lastEmittedFunction = constant;
|
|
return;
|
|
}
|
|
|
|
emitter(f);
|
|
}
|
|
|
|
template<typename T>
|
|
void SILGenModule::preEmitFunction(SILDeclRef constant,
|
|
T *astNode,
|
|
SILFunction *F,
|
|
SILLocation Loc) {
|
|
// By default, use the astNode to create the location.
|
|
if (Loc.isNull())
|
|
Loc = RegularLocation(astNode);
|
|
|
|
assert(F->empty() && "already emitted function?!");
|
|
|
|
F->setContextGenericParams(
|
|
Types.getConstantInfo(constant).ContextGenericParams);
|
|
|
|
// Create a debug scope for the function using astNode as source location.
|
|
F->setDebugScope(new (M) SILDebugScope(RegularLocation(astNode), F));
|
|
|
|
F->setLocation(Loc);
|
|
|
|
F->setDeclContext(astNode);
|
|
|
|
DEBUG(llvm::dbgs() << "lowering ";
|
|
F->printName(llvm::dbgs());
|
|
llvm::dbgs() << " : $";
|
|
F->getLoweredType().print(llvm::dbgs());
|
|
llvm::dbgs() << '\n';
|
|
if (astNode) {
|
|
astNode->print(llvm::dbgs());
|
|
llvm::dbgs() << '\n';
|
|
});
|
|
}
|
|
|
|
void SILGenModule::postEmitFunction(SILDeclRef constant,
|
|
SILFunction *F) {
|
|
assert(!F->isExternalDeclaration() && "did not emit any function body?!");
|
|
DEBUG(llvm::dbgs() << "lowered sil:\n";
|
|
F->print(llvm::dbgs()));
|
|
F->verify();
|
|
}
|
|
|
|
void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) {
|
|
// Emit any default argument generators.
|
|
{
|
|
auto paramLists = AFD->getParameterLists();
|
|
if (AFD->getDeclContext()->isTypeContext())
|
|
paramLists = paramLists.slice(1);
|
|
emitDefaultArgGenerators(AFD, paramLists);
|
|
}
|
|
|
|
// If this is a function at global scope, it may close over a global variable.
|
|
// If we're emitting top-level code, then emit a "mark_function_escape" that
|
|
// lists the captured global variables so that definite initialization can
|
|
// reason about this escape point.
|
|
if (!AFD->getDeclContext()->isLocalContext() &&
|
|
TopLevelSGF && TopLevelSGF->B.hasValidInsertionPoint()) {
|
|
SmallVector<SILValue, 4> Captures;
|
|
|
|
for (auto capture : AFD->getCaptureInfo().getCaptures()) {
|
|
// Decls captured by value don't escape.
|
|
auto It = TopLevelSGF->VarLocs.find(capture.getDecl());
|
|
if (It == TopLevelSGF->VarLocs.end() ||
|
|
!It->getSecond().value->getType().isAddress())
|
|
continue;
|
|
|
|
Captures.push_back(It->second.value);
|
|
}
|
|
|
|
if (!Captures.empty())
|
|
TopLevelSGF->B.createMarkFunctionEscape(AFD, Captures);
|
|
}
|
|
}
|
|
|
|
static bool hasSILBody(FuncDecl *fd) {
|
|
if (fd->getAccessorKind() == AccessorKind::IsMaterializeForSet)
|
|
return !isa<ProtocolDecl>(fd->getDeclContext());
|
|
|
|
return fd->getBody(/*canSynthesize=*/false);
|
|
}
|
|
|
|
void SILGenModule::emitFunction(FuncDecl *fd) {
|
|
SILDeclRef::Loc decl = fd;
|
|
|
|
emitAbstractFuncDecl(fd);
|
|
|
|
if (hasSILBody(fd)) {
|
|
PrettyStackTraceDecl stackTrace("emitting SIL for", fd);
|
|
|
|
SILDeclRef constant(decl);
|
|
|
|
emitOrDelayFunction(*this, constant, [this,constant,fd](SILFunction *f){
|
|
preEmitFunction(constant, fd, f, fd);
|
|
if (fd->getAccessorKind() == AccessorKind::IsMaterializeForSet)
|
|
SILGenFunction(*this, *f).emitMaterializeForSet(fd);
|
|
else
|
|
SILGenFunction(*this, *f).emitFunction(fd);
|
|
postEmitFunction(constant, f);
|
|
});
|
|
}
|
|
}
|
|
|
|
void SILGenModule::emitCurryThunk(ValueDecl *fd,
|
|
SILDeclRef entryPoint,
|
|
SILDeclRef nextEntryPoint) {
|
|
// Thunks are always emitted by need, so don't need delayed emission.
|
|
SILFunction *f = getFunction(entryPoint, ForDefinition);
|
|
preEmitFunction(entryPoint, fd, f, fd);
|
|
PrettyStackTraceSILFunction X("silgen emitCurryThunk", f);
|
|
|
|
SILGenFunction(*this, *f)
|
|
.emitCurryThunk(fd, entryPoint, nextEntryPoint);
|
|
postEmitFunction(entryPoint, f);
|
|
}
|
|
|
|
void SILGenModule::emitForeignToNativeThunk(SILDeclRef thunk) {
|
|
// Thunks are always emitted by need, so don't need delayed emission.
|
|
assert(!thunk.isForeign && "foreign-to-native thunks only");
|
|
SILFunction *f = getFunction(thunk, ForDefinition);
|
|
preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl());
|
|
PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f);
|
|
SILGenFunction(*this, *f).emitForeignToNativeThunk(thunk);
|
|
postEmitFunction(thunk, f);
|
|
}
|
|
|
|
void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk) {
|
|
// Thunks are always emitted by need, so don't need delayed emission.
|
|
assert(thunk.isForeign && "native-to-foreign thunks only");
|
|
|
|
SILFunction *f = getFunction(thunk, ForDefinition);
|
|
if (thunk.hasDecl())
|
|
preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl());
|
|
else
|
|
preEmitFunction(thunk, thunk.getAbstractClosureExpr(), f,
|
|
thunk.getAbstractClosureExpr());
|
|
PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f);
|
|
f->setBare(IsBare);
|
|
SILGenFunction(*this, *f).emitNativeToForeignThunk(thunk);
|
|
postEmitFunction(thunk, f);
|
|
}
|
|
|
|
void SILGenModule::addGlobalVariable(VarDecl *global) {
|
|
// We create SILGlobalVariable here.
|
|
getSILGlobalVariable(global, ForDefinition);
|
|
}
|
|
|
|
void SILGenModule::emitConstructor(ConstructorDecl *decl) {
|
|
// FIXME: Handle 'self' like any other argument here.
|
|
// Emit any default argument getter functions.
|
|
emitAbstractFuncDecl(decl);
|
|
|
|
// We never emit constructors in protocols.
|
|
if (isa<ProtocolDecl>(decl->getDeclContext()))
|
|
return;
|
|
|
|
// Always-unavailable imported constructors are factory methods
|
|
// that have been imported as constructors and then hidden by an
|
|
// imported init method.
|
|
if (decl->hasClangNode() &&
|
|
decl->getAttrs().isUnavailable(decl->getASTContext()))
|
|
return;
|
|
|
|
SILDeclRef constant(decl);
|
|
|
|
if (decl->getImplicitSelfDecl()->getType()->getInOutObjectType()
|
|
->getClassOrBoundGenericClass()) {
|
|
// Class constructors have separate entry points for allocation and
|
|
// initialization.
|
|
emitOrDelayFunction(*this, constant, [this,constant,decl](SILFunction *f){
|
|
preEmitFunction(constant, decl, f, decl);
|
|
PrettyStackTraceSILFunction X("silgen emitConstructor", f);
|
|
SILGenFunction(*this, *f)
|
|
.emitClassConstructorAllocator(decl);
|
|
postEmitFunction(constant, f);
|
|
});
|
|
|
|
// If this constructor was imported, we don't need the initializing
|
|
// constructor to be emitted.
|
|
if (!decl->hasClangNode()) {
|
|
SILDeclRef initConstant(decl, SILDeclRef::Kind::Initializer);
|
|
emitOrDelayFunction(*this, initConstant,
|
|
[this,initConstant,decl](SILFunction *initF){
|
|
preEmitFunction(initConstant, decl, initF, decl);
|
|
PrettyStackTraceSILFunction X("silgen constructor initializer", initF);
|
|
SILGenFunction(*this, *initF).emitClassConstructorInitializer(decl);
|
|
postEmitFunction(initConstant, initF);
|
|
});
|
|
}
|
|
} else {
|
|
// Struct and enum constructors do everything in a single function.
|
|
emitOrDelayFunction(*this, constant, [this,constant,decl](SILFunction *f) {
|
|
preEmitFunction(constant, decl, f, decl);
|
|
PrettyStackTraceSILFunction X("silgen emitConstructor", f);
|
|
SILGenFunction(*this, *f).emitValueConstructor(decl);
|
|
postEmitFunction(constant, f);
|
|
});
|
|
}
|
|
}
|
|
|
|
void SILGenModule::emitEnumConstructor(EnumElementDecl *decl) {
|
|
// Enum element constructors are always emitted by need, so don't need
|
|
// delayed emission.
|
|
SILDeclRef constant(decl);
|
|
SILFunction *f = getFunction(constant, ForDefinition);
|
|
preEmitFunction(constant, decl, f, decl);
|
|
PrettyStackTraceSILFunction X("silgen enum constructor", f);
|
|
SILGenFunction(*this, *f).emitEnumConstructor(decl);
|
|
postEmitFunction(constant, f);
|
|
}
|
|
|
|
SILFunction *SILGenModule::emitClosure(AbstractClosureExpr *ce) {
|
|
// Closures are emitted by need, so don't required delayed emission.
|
|
SILDeclRef constant(ce);
|
|
SILFunction *f = getFunction(constant, ForDefinition);
|
|
preEmitFunction(constant, ce, f, ce);
|
|
PrettyStackTraceSILFunction X("silgen closureexpr", f);
|
|
SILGenFunction(*this, *f).emitClosure(ce);
|
|
postEmitFunction(constant, f);
|
|
return f;
|
|
}
|
|
|
|
/// Determine whether the given class requires a separate instance
|
|
/// variable initialization method.
|
|
static bool requiresIVarInitialization(SILGenModule &SGM, ClassDecl *cd) {
|
|
if (!cd->requiresStoredPropertyInits())
|
|
return false;
|
|
|
|
for (Decl *member : cd->getMembers()) {
|
|
auto pbd = dyn_cast<PatternBindingDecl>(member);
|
|
if (!pbd) continue;
|
|
|
|
for (auto entry : pbd->getPatternList())
|
|
if (entry.getInit())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SILGenModule::hasNonTrivialIVars(ClassDecl *cd) {
|
|
for (Decl *member : cd->getMembers()) {
|
|
VarDecl *vd = dyn_cast<VarDecl>(member);
|
|
if (!vd || !vd->hasStorage()) continue;
|
|
|
|
const TypeLowering &ti = Types.getTypeLowering(vd->getType());
|
|
if (!ti.isTrivial())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SILGenModule::requiresIVarDestroyer(ClassDecl *cd) {
|
|
// Only needed if we have non-trivial ivars, we're not a root class, and
|
|
// the superclass is not @objc.
|
|
return (hasNonTrivialIVars(cd) &&
|
|
cd->getSuperclass() &&
|
|
!cd->getSuperclass()->getClassOrBoundGenericClass()->hasClangNode());
|
|
}
|
|
|
|
/// TODO: This needs a better name.
|
|
void SILGenModule::emitObjCAllocatorDestructor(ClassDecl *cd,
|
|
DestructorDecl *dd) {
|
|
// Emit the native deallocating destructor for -dealloc.
|
|
// Destructors are a necessary part of class metadata, so can't be delayed.
|
|
{
|
|
SILDeclRef dealloc(dd, SILDeclRef::Kind::Deallocator);
|
|
SILFunction *f = getFunction(dealloc, ForDefinition);
|
|
preEmitFunction(dealloc, dd, f, dd);
|
|
PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f);
|
|
SILGenFunction(*this, *f).emitObjCDestructor(dealloc);
|
|
postEmitFunction(dealloc, f);
|
|
}
|
|
|
|
// Emit the Objective-C -dealloc entry point if it has
|
|
// something to do beyond messaging the superclass's -dealloc.
|
|
if (dd->getBody()->getNumElements() != 0)
|
|
emitObjCDestructorThunk(dd);
|
|
|
|
// Emit the ivar initializer, if needed.
|
|
if (requiresIVarInitialization(*this, cd)) {
|
|
SILDeclRef ivarInitializer(cd, SILDeclRef::Kind::IVarInitializer,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isForeign=*/true);
|
|
SILFunction *f = getFunction(ivarInitializer, ForDefinition);
|
|
preEmitFunction(ivarInitializer, dd, f, dd);
|
|
PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f);
|
|
SILGenFunction(*this, *f).emitIVarInitializer(ivarInitializer);
|
|
postEmitFunction(ivarInitializer, f);
|
|
}
|
|
|
|
// Emit the ivar destroyer, if needed.
|
|
if (hasNonTrivialIVars(cd)) {
|
|
SILDeclRef ivarDestroyer(cd, SILDeclRef::Kind::IVarDestroyer,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isForeign=*/true);
|
|
SILFunction *f = getFunction(ivarDestroyer, ForDefinition);
|
|
preEmitFunction(ivarDestroyer, dd, f, dd);
|
|
PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f);
|
|
SILGenFunction(*this, *f).emitIVarDestroyer(ivarDestroyer);
|
|
postEmitFunction(ivarDestroyer, f);
|
|
}
|
|
}
|
|
|
|
void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) {
|
|
emitAbstractFuncDecl(dd);
|
|
|
|
// Emit the ivar destroyer, if needed.
|
|
if (requiresIVarDestroyer(cd)) {
|
|
SILDeclRef ivarDestroyer(cd, SILDeclRef::Kind::IVarDestroyer,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isForeign=*/false);
|
|
SILFunction *f = getFunction(ivarDestroyer, ForDefinition);
|
|
preEmitFunction(ivarDestroyer, dd, f, dd);
|
|
PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f);
|
|
SILGenFunction(*this, *f).emitIVarDestroyer(ivarDestroyer);
|
|
postEmitFunction(ivarDestroyer, f);
|
|
}
|
|
|
|
// If the class would use the Objective-C allocator, only emit -dealloc.
|
|
if (usesObjCAllocator(cd)) {
|
|
emitObjCAllocatorDestructor(cd, dd);
|
|
return;
|
|
}
|
|
|
|
// Emit the destroying destructor.
|
|
// Destructors are a necessary part of class metadata, so can't be delayed.
|
|
{
|
|
SILDeclRef destroyer(dd, SILDeclRef::Kind::Destroyer);
|
|
SILFunction *f = getFunction(destroyer, ForDefinition);
|
|
preEmitFunction(destroyer, dd, f, dd);
|
|
PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f);
|
|
SILGenFunction(*this, *f).emitDestroyingDestructor(dd);
|
|
f->setDebugScope(new (M) SILDebugScope(dd, f));
|
|
postEmitFunction(destroyer, f);
|
|
}
|
|
|
|
// Emit the deallocating destructor.
|
|
{
|
|
SILDeclRef deallocator(dd, SILDeclRef::Kind::Deallocator);
|
|
SILFunction *f = getFunction(deallocator, ForDefinition);
|
|
preEmitFunction(deallocator, dd, f, dd);
|
|
PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f);
|
|
SILGenFunction(*this, *f).emitDeallocatingDestructor(dd);
|
|
f->setDebugScope(new (M) SILDebugScope(dd, f));
|
|
postEmitFunction(deallocator, f);
|
|
}
|
|
}
|
|
|
|
void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, Expr *arg) {
|
|
emitOrDelayFunction(*this, constant, [this,constant,arg](SILFunction *f) {
|
|
preEmitFunction(constant, arg, f, arg);
|
|
PrettyStackTraceSILFunction X("silgen emitDefaultArgGenerator ", f);
|
|
SILGenFunction(*this, *f).emitGeneratorFunction(constant, arg);
|
|
postEmitFunction(constant, f);
|
|
});
|
|
}
|
|
|
|
SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName,
|
|
PatternBindingDecl *binding,
|
|
unsigned pbdEntry) {
|
|
ASTContext &C = M.getASTContext();
|
|
Type initType = FunctionType::get(
|
|
TupleType::getEmpty(C), TupleType::getEmpty(C),
|
|
FunctionType::ExtInfo()
|
|
.withRepresentation(FunctionType::Representation::Thin));
|
|
auto initSILType = getLoweredType(initType).castTo<SILFunctionType>();
|
|
|
|
auto *f =
|
|
M.getOrCreateFunction(SILLinkage::Private, funcName, initSILType, nullptr,
|
|
SILLocation(binding), IsNotBare, IsNotTransparent,
|
|
makeModuleFragile ? IsFragile : IsNotFragile);
|
|
f->setDebugScope(
|
|
new (M) SILDebugScope(RegularLocation(binding->getInit(pbdEntry)), f));
|
|
f->setLocation(binding);
|
|
|
|
SILGenFunction(*this, *f).emitLazyGlobalInitializer(binding, pbdEntry);
|
|
|
|
f->verify();
|
|
|
|
return f;
|
|
}
|
|
|
|
void SILGenModule::emitGlobalAccessor(VarDecl *global,
|
|
SILGlobalVariable *onceToken,
|
|
SILFunction *onceFunc) {
|
|
SILDeclRef accessor(global, SILDeclRef::Kind::GlobalAccessor);
|
|
emitOrDelayFunction(*this, accessor,
|
|
[this,accessor,global,onceToken,onceFunc](SILFunction *f){
|
|
preEmitFunction(accessor, global, f, global);
|
|
PrettyStackTraceSILFunction X("silgen emitGlobalAccessor", f);
|
|
SILGenFunction(*this, *f)
|
|
.emitGlobalAccessor(global, onceToken, onceFunc);
|
|
postEmitFunction(accessor, f);
|
|
});
|
|
}
|
|
|
|
void SILGenModule::emitGlobalGetter(VarDecl *global,
|
|
SILGlobalVariable *onceToken,
|
|
SILFunction *onceFunc) {
|
|
SILDeclRef accessor(global, SILDeclRef::Kind::GlobalGetter);
|
|
emitOrDelayFunction(*this, accessor,
|
|
[this,accessor,global,onceToken,onceFunc](SILFunction *f){
|
|
preEmitFunction(accessor, global, f, global);
|
|
PrettyStackTraceSILFunction X("silgen emitGlobalGetter", f);
|
|
SILGenFunction(*this, *f)
|
|
.emitGlobalGetter(global, onceToken, onceFunc);
|
|
postEmitFunction(accessor, f);
|
|
});
|
|
}
|
|
|
|
void SILGenModule::emitDefaultArgGenerators(SILDeclRef::Loc decl,
|
|
ArrayRef<ParameterList*> paramLists) {
|
|
unsigned index = 0;
|
|
for (auto paramList : paramLists) {
|
|
for (auto param : *paramList) {
|
|
if (auto handle = param->getDefaultValue())
|
|
emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl, index),
|
|
handle->getExpr());
|
|
++index;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SILGenModule::emitObjCMethodThunk(FuncDecl *method) {
|
|
SILDeclRef thunk(method,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isObjC*/ true);
|
|
|
|
// Don't emit the thunk if it already exists.
|
|
if (hasFunction(thunk))
|
|
return;
|
|
|
|
// ObjC entry points are always externally usable, so can't be delay-emitted.
|
|
|
|
SILFunction *f = getFunction(thunk, ForDefinition);
|
|
preEmitFunction(thunk, method, f, method);
|
|
PrettyStackTraceSILFunction X("silgen emitObjCMethodThunk", f);
|
|
f->setBare(IsBare);
|
|
f->setThunk(IsThunk);
|
|
SILGenFunction(*this, *f).emitNativeToForeignThunk(thunk);
|
|
postEmitFunction(thunk, f);
|
|
}
|
|
|
|
void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) {
|
|
// If we don't actually need an entry point for the getter, do nothing.
|
|
if (!prop->getGetter() || !requiresObjCMethodEntryPoint(prop->getGetter()))
|
|
return;
|
|
|
|
SILDeclRef getter(prop->getGetter(), SILDeclRef::Kind::Func,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isObjC*/ true);
|
|
|
|
// Don't emit the thunks if they already exist.
|
|
if (hasFunction(getter))
|
|
return;
|
|
|
|
RegularLocation ThunkBodyLoc(prop);
|
|
ThunkBodyLoc.markAutoGenerated();
|
|
// ObjC entry points are always externally usable, so emitting can't be
|
|
// delayed.
|
|
{
|
|
SILFunction *f = getFunction(getter, ForDefinition);
|
|
preEmitFunction(getter, prop, f, ThunkBodyLoc);
|
|
PrettyStackTraceSILFunction X("silgen objc property getter thunk", f);
|
|
f->setBare(IsBare);
|
|
f->setThunk(IsThunk);
|
|
SILGenFunction(*this, *f).emitNativeToForeignThunk(getter);
|
|
postEmitFunction(getter, f);
|
|
}
|
|
|
|
if (!prop->isSettable(prop->getDeclContext()))
|
|
return;
|
|
|
|
// FIXME: Add proper location.
|
|
SILDeclRef setter(prop->getSetter(), SILDeclRef::Kind::Func,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isObjC*/ true);
|
|
|
|
SILFunction *f = getFunction(setter, ForDefinition);
|
|
preEmitFunction(setter, prop, f, ThunkBodyLoc);
|
|
PrettyStackTraceSILFunction X("silgen objc property setter thunk", f);
|
|
f->setBare(IsBare);
|
|
f->setThunk(IsThunk);
|
|
SILGenFunction(*this, *f).emitNativeToForeignThunk(setter);
|
|
postEmitFunction(setter, f);
|
|
}
|
|
|
|
void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) {
|
|
SILDeclRef thunk(constructor,
|
|
SILDeclRef::Kind::Initializer,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isObjC*/ true);
|
|
|
|
// Don't emit the thunk if it already exists.
|
|
if (hasFunction(thunk))
|
|
return;
|
|
// ObjC entry points are always externally usable, so emitting can't be
|
|
// delayed.
|
|
|
|
SILFunction *f = getFunction(thunk, ForDefinition);
|
|
preEmitFunction(thunk, constructor, f, constructor);
|
|
PrettyStackTraceSILFunction X("silgen objc constructor thunk", f);
|
|
f->setBare(IsBare);
|
|
f->setThunk(IsThunk);
|
|
SILGenFunction(*this, *f).emitNativeToForeignThunk(thunk);
|
|
postEmitFunction(thunk, f);
|
|
}
|
|
|
|
void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) {
|
|
SILDeclRef thunk(destructor,
|
|
SILDeclRef::Kind::Deallocator,
|
|
SILDeclRef::ConstructAtBestResilienceExpansion,
|
|
SILDeclRef::ConstructAtNaturalUncurryLevel,
|
|
/*isObjC*/ true);
|
|
|
|
// Don't emit the thunk if it already exists.
|
|
if (hasFunction(thunk))
|
|
return;
|
|
SILFunction *f = getFunction(thunk, ForDefinition);
|
|
preEmitFunction(thunk, destructor, f, destructor);
|
|
PrettyStackTraceSILFunction X("silgen objc destructor thunk", f);
|
|
f->setBare(IsBare);
|
|
f->setThunk(IsThunk);
|
|
SILGenFunction(*this, *f).emitNativeToForeignThunk(thunk);
|
|
postEmitFunction(thunk, f);
|
|
}
|
|
|
|
void SILGenModule::visitPatternBindingDecl(PatternBindingDecl *pd) {
|
|
assert(!TopLevelSGF && "script mode PBDs should be in TopLevelCodeDecls");
|
|
for (unsigned i = 0, e = pd->getNumPatternEntries(); i != e; ++i)
|
|
if (pd->getInit(i))
|
|
emitGlobalInitialization(pd, i);
|
|
}
|
|
|
|
void SILGenModule::visitVarDecl(VarDecl *vd) {
|
|
if (vd->hasBehavior())
|
|
emitPropertyBehavior(vd);
|
|
|
|
if (vd->hasStorage())
|
|
addGlobalVariable(vd);
|
|
|
|
if (vd->getStorageKind() == AbstractStorageDecl::StoredWithTrivialAccessors) {
|
|
// If the global variable has storage, it might also have synthesized
|
|
// accessors. Emit them here, since they won't appear anywhere else.
|
|
if (auto getter = vd->getGetter())
|
|
emitFunction(getter);
|
|
if (auto setter = vd->getSetter())
|
|
emitFunction(setter);
|
|
}
|
|
}
|
|
|
|
void SILGenModule::emitPropertyBehavior(VarDecl *vd) {
|
|
assert(vd->hasBehavior());
|
|
// Emit the protocol conformance to the behavior.
|
|
getWitnessTable(*vd->getBehavior()->Conformance);
|
|
}
|
|
|
|
void SILGenModule::visitIfConfigDecl(IfConfigDecl *ICD) {
|
|
// Nothing to do for these kinds of decls - anything active has been added
|
|
// to the enclosing declaration.
|
|
}
|
|
|
|
void SILGenModule::visitTopLevelCodeDecl(TopLevelCodeDecl *td) {
|
|
assert(TopLevelSGF && "top-level code in a non-main source file!");
|
|
|
|
if (!TopLevelSGF->B.hasValidInsertionPoint())
|
|
return;
|
|
|
|
for (auto &ESD : td->getBody()->getElements()) {
|
|
if (!TopLevelSGF->B.hasValidInsertionPoint()) {
|
|
if (Stmt *S = ESD.dyn_cast<Stmt*>()) {
|
|
if (S->isImplicit())
|
|
continue;
|
|
} else if (Expr *E = ESD.dyn_cast<Expr*>()) {
|
|
if (E->isImplicit())
|
|
continue;
|
|
}
|
|
|
|
diagnose(ESD.getStartLoc(), diag::unreachable_code);
|
|
// There's no point in trying to emit anything else.
|
|
return;
|
|
}
|
|
|
|
if (Stmt *S = ESD.dyn_cast<Stmt*>()) {
|
|
TopLevelSGF->emitStmt(S);
|
|
} else if (Expr *E = ESD.dyn_cast<Expr*>()) {
|
|
TopLevelSGF->emitIgnoredExpr(E);
|
|
} else {
|
|
TopLevelSGF->visit(ESD.get<Decl*>());
|
|
}
|
|
}
|
|
}
|
|
|
|
static void emitTopLevelProlog(SILGenFunction &gen, SILLocation loc) {
|
|
assert(gen.B.getInsertionBB()->getIterator() == gen.F.begin()
|
|
&& "not at entry point?!");
|
|
|
|
SILBasicBlock *entry = gen.B.getInsertionBB();
|
|
// Create the argc and argv arguments.
|
|
auto &C = gen.getASTContext();
|
|
auto FnTy = gen.F.getLoweredFunctionType();
|
|
auto argc = new (gen.F.getModule()) SILArgument(
|
|
entry, FnTy->getParameters()[0].getSILType());
|
|
auto argv = new (gen.F.getModule()) SILArgument(
|
|
entry, FnTy->getParameters()[1].getSILType());
|
|
|
|
// If the standard library provides a _stdlib_didEnterMain intrinsic, call it
|
|
// first thing.
|
|
if (auto didEnterMain = C.getDidEnterMain(nullptr)) {
|
|
ManagedValue params[] = {
|
|
ManagedValue::forUnmanaged(argc),
|
|
ManagedValue::forUnmanaged(argv),
|
|
};
|
|
(void) gen.emitApplyOfLibraryIntrinsic(loc, didEnterMain, {}, params,
|
|
SGFContext());
|
|
}
|
|
}
|
|
|
|
void SILGenModule::useConformance(ProtocolConformanceRef conformanceRef) {
|
|
// We don't need to emit dependent conformances.
|
|
if (conformanceRef.isAbstract())
|
|
return;
|
|
|
|
auto conformance = conformanceRef.getConcrete();
|
|
auto root = conformance->getRootNormalConformance();
|
|
// If we already emitted this witness table, we don't need to track the fact
|
|
// we need it.
|
|
if (emittedWitnessTables.count(root))
|
|
return;
|
|
|
|
// If we delayed emitting this witness table, force it.
|
|
auto foundDelayed = delayedConformances.find(root);
|
|
if (foundDelayed != delayedConformances.end()) {
|
|
forcedConformances.push_back(*foundDelayed);
|
|
delayedConformances.erase(foundDelayed);
|
|
return;
|
|
}
|
|
|
|
// Otherwise, just remember the fact we used this conformance.
|
|
usedConformances.insert(root);
|
|
}
|
|
|
|
void
|
|
SILGenModule::useConformancesFromSubstitutions(ArrayRef<Substitution> subs) {
|
|
for (auto &sub : subs) {
|
|
for (auto conformance : sub.getConformances())
|
|
useConformance(conformance);
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// An RAII class to scope source file codegen.
|
|
class SourceFileScope {
|
|
SILGenModule &sgm;
|
|
SourceFile *sf;
|
|
Optional<Scope> scope;
|
|
public:
|
|
SourceFileScope(SILGenModule &sgm, SourceFile *sf) : sgm(sgm), sf(sf) {
|
|
// If this is the script-mode file for the module, create a toplevel.
|
|
if (sf->isScriptMode()) {
|
|
assert(!sgm.TopLevelSGF && "already emitted toplevel?!");
|
|
assert(!sgm.M.lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION)
|
|
&& "already emitted toplevel?!");
|
|
|
|
RegularLocation TopLevelLoc = RegularLocation::getModuleLocation();
|
|
SILFunction *toplevel = sgm.emitTopLevelFunction(TopLevelLoc);
|
|
|
|
// Assign a debug scope pointing into the void to the top level function.
|
|
toplevel->setDebugScope(new (sgm.M) SILDebugScope(TopLevelLoc, toplevel));
|
|
|
|
sgm.TopLevelSGF = new SILGenFunction(sgm, *toplevel);
|
|
sgm.TopLevelSGF->MagicFunctionName = sgm.SwiftModule->getName();
|
|
sgm.TopLevelSGF->prepareEpilog(Type(), false,
|
|
CleanupLocation::getModuleCleanupLocation());
|
|
|
|
sgm.TopLevelSGF->prepareRethrowEpilog(
|
|
CleanupLocation::getModuleCleanupLocation());
|
|
|
|
auto PrologueLoc = RegularLocation::getModuleLocation();
|
|
PrologueLoc.markAsPrologue();
|
|
emitTopLevelProlog(*sgm.TopLevelSGF, PrologueLoc);
|
|
|
|
scope.emplace(sgm.TopLevelSGF->Cleanups,
|
|
CleanupLocation::getModuleCleanupLocation());
|
|
}
|
|
}
|
|
|
|
~SourceFileScope() {
|
|
if (sgm.TopLevelSGF) {
|
|
scope.reset();
|
|
|
|
// Unregister the top-level function emitter.
|
|
auto &gen = *sgm.TopLevelSGF;
|
|
sgm.TopLevelSGF = nullptr;
|
|
|
|
// Write out the epilog.
|
|
auto moduleLoc = RegularLocation::getModuleLocation();
|
|
moduleLoc.markAutoGenerated();
|
|
auto returnInfo = gen.emitEpilogBB(moduleLoc);
|
|
auto returnLoc = returnInfo.second;
|
|
returnLoc.markAutoGenerated();
|
|
|
|
SILType returnType =
|
|
gen.F.getLoweredFunctionType()->getSingleResult().getSILType();
|
|
auto emitTopLevelReturnValue = [&](unsigned value) -> SILValue {
|
|
// Create an integer literal for the value.
|
|
auto litType = SILType::getBuiltinIntegerType(32, sgm.getASTContext());
|
|
SILValue retValue =
|
|
gen.B.createIntegerLiteral(moduleLoc, litType, value);
|
|
|
|
// Wrap that in a struct if necessary.
|
|
if (litType != returnType) {
|
|
retValue = gen.B.createStruct(moduleLoc, returnType, retValue);
|
|
}
|
|
return retValue;
|
|
};
|
|
|
|
// Fallthrough should signal a normal exit by returning 0.
|
|
SILValue returnValue;
|
|
if (gen.B.hasValidInsertionPoint())
|
|
returnValue = emitTopLevelReturnValue(0);
|
|
|
|
// Handle the implicit rethrow block.
|
|
auto rethrowBB = gen.ThrowDest.getBlock();
|
|
gen.ThrowDest = JumpDest::invalid();
|
|
|
|
// If the rethrow block wasn't actually used, just remove it.
|
|
if (rethrowBB->pred_empty()) {
|
|
gen.eraseBasicBlock(rethrowBB);
|
|
|
|
// Otherwise, we need to produce a unified return block.
|
|
} else {
|
|
auto returnBB = gen.createBasicBlock();
|
|
if (gen.B.hasValidInsertionPoint())
|
|
gen.B.createBranch(returnLoc, returnBB, returnValue);
|
|
returnValue = returnBB->createBBArg(returnType);
|
|
gen.B.emitBlock(returnBB);
|
|
|
|
// Emit the rethrow block.
|
|
SavedInsertionPoint savedIP(gen, rethrowBB,
|
|
FunctionSection::Postmatter);
|
|
|
|
// Log the error.
|
|
SILValue error = rethrowBB->getBBArg(0);
|
|
gen.B.createBuiltin(moduleLoc,
|
|
sgm.getASTContext().getIdentifier("errorInMain"),
|
|
sgm.Types.getEmptyTupleType(), {}, {error});
|
|
|
|
// Signal an abnormal exit by returning 1.
|
|
gen.Cleanups.emitCleanupsForReturn(CleanupLocation::get(moduleLoc));
|
|
gen.B.createBranch(returnLoc, returnBB, emitTopLevelReturnValue(1));
|
|
}
|
|
|
|
// Return.
|
|
if (gen.B.hasValidInsertionPoint())
|
|
gen.B.createReturn(returnLoc, returnValue);
|
|
|
|
// Okay, we're done emitting the top-level function; destroy the
|
|
// emitter and verify the result.
|
|
SILFunction *toplevel = &gen.getFunction();
|
|
delete &gen;
|
|
|
|
DEBUG(llvm::dbgs() << "lowered toplevel sil:\n";
|
|
toplevel->print(llvm::dbgs()));
|
|
toplevel->verify();
|
|
}
|
|
|
|
// If the source file contains an artificial main, emit the implicit
|
|
// toplevel code.
|
|
if (auto mainClass = sf->getMainClass()) {
|
|
assert(!sgm.M.lookUpFunction(SWIFT_ENTRY_POINT_FUNCTION)
|
|
&& "already emitted toplevel before main class?!");
|
|
|
|
RegularLocation TopLevelLoc = RegularLocation::getModuleLocation();
|
|
SILFunction *toplevel = sgm.emitTopLevelFunction(TopLevelLoc);
|
|
|
|
// Assign a debug scope pointing into the void to the top level function.
|
|
toplevel->setDebugScope(new (sgm.M) SILDebugScope(TopLevelLoc, toplevel));
|
|
|
|
SILGenFunction gen(sgm, *toplevel);
|
|
emitTopLevelProlog(gen, mainClass);
|
|
gen.emitArtificialTopLevel(mainClass);
|
|
}
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
void SILGenModule::emitSourceFile(SourceFile *sf, unsigned startElem) {
|
|
SourceFileScope scope(*this, sf);
|
|
for (Decl *D : llvm::makeArrayRef(sf->Decls).slice(startElem))
|
|
visit(D);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILModule::constructSIL method implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
std::unique_ptr<SILModule>
|
|
SILModule::constructSIL(Module *mod, SILOptions &options, FileUnit *SF,
|
|
Optional<unsigned> startElem, bool makeModuleFragile,
|
|
bool isWholeModule) {
|
|
SharedTimer timer("SILGen");
|
|
const DeclContext *DC;
|
|
if (startElem) {
|
|
assert(SF && "cannot have a start element without a source file");
|
|
// Because more decls may be added to the SourceFile, we can't assume
|
|
// anything about the compilation context.
|
|
DC = nullptr;
|
|
} else if (SF) {
|
|
DC = SF;
|
|
} else {
|
|
DC = mod;
|
|
}
|
|
|
|
std::unique_ptr<SILModule> M(new SILModule(mod, options, DC, isWholeModule));
|
|
SILGenModule SGM(*M, mod, makeModuleFragile);
|
|
|
|
if (SF) {
|
|
if (auto *file = dyn_cast<SourceFile>(SF)) {
|
|
SGM.emitSourceFile(file, startElem.getValueOr(0));
|
|
} else if (auto *file = dyn_cast<SerializedASTFile>(SF)) {
|
|
if (file->isSIB())
|
|
M->getSILLoader()->getAllForModule(mod->getName(), file);
|
|
}
|
|
} else {
|
|
for (auto file : mod->getFiles()) {
|
|
auto nextSF = dyn_cast<SourceFile>(file);
|
|
if (!nextSF || nextSF->ASTStage != SourceFile::TypeChecked)
|
|
continue;
|
|
SGM.emitSourceFile(nextSF, 0);
|
|
}
|
|
|
|
// Also make sure to process any intermediate files that may contain SIL
|
|
bool hasSIB = std::any_of(mod->getFiles().begin(),
|
|
mod->getFiles().end(),
|
|
[](const FileUnit *File) -> bool {
|
|
auto *SASTF = dyn_cast<SerializedASTFile>(File);
|
|
return SASTF && SASTF->isSIB();
|
|
});
|
|
if (hasSIB)
|
|
M->getSILLoader()->getAllForModule(mod->getName(), nullptr);
|
|
}
|
|
|
|
// Emit external definitions used by this module.
|
|
for (size_t i = 0, e = mod->getASTContext().LastCheckedExternalDefinition;
|
|
i != e; ++i) {
|
|
auto def = mod->getASTContext().ExternalDefinitions[i];
|
|
SGM.emitExternalDefinition(def);
|
|
}
|
|
|
|
// Emit any delayed definitions that were forced.
|
|
// Emitting these may in turn force more definitions, so we have to take care
|
|
// to keep pumping the queues.
|
|
while (!SGM.forcedFunctions.empty()
|
|
|| !SGM.forcedConformances.empty()) {
|
|
while (!SGM.forcedFunctions.empty()) {
|
|
auto &front = SGM.forcedFunctions.front();
|
|
front.second.emitter(SGM.getFunction(front.first, ForDefinition));
|
|
SGM.forcedFunctions.pop_front();
|
|
}
|
|
while (!SGM.forcedConformances.empty()) {
|
|
auto &front = SGM.forcedConformances.front();
|
|
SGM.getWitnessTable(front.first);
|
|
SGM.forcedConformances.pop_front();
|
|
}
|
|
}
|
|
|
|
return M;
|
|
}
|
|
|
|
std::unique_ptr<SILModule>
|
|
swift::performSILGeneration(Module *mod,
|
|
SILOptions &options,
|
|
bool makeModuleFragile,
|
|
bool wholeModuleCompilation) {
|
|
return SILModule::constructSIL(mod, options, nullptr, None, makeModuleFragile,
|
|
wholeModuleCompilation);
|
|
}
|
|
|
|
std::unique_ptr<SILModule>
|
|
swift::performSILGeneration(FileUnit &sf, SILOptions &options,
|
|
Optional<unsigned> startElem,
|
|
bool makeModuleFragile) {
|
|
return SILModule::constructSIL(sf.getParentModule(), options, &sf, startElem,
|
|
makeModuleFragile, false);
|
|
}
|