| //===--- 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 "ManagedValue.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->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->getResult().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, ErrorType) |
| GET_BRIDGING_FN(Foundation, REQUIRED, ErrorType, 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->hasStorage()) |
| addGlobalVariable(vd); |
| } |
| |
| 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() == 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 _didEnterMain intrinsic, call it first |
| // thing. |
| if (auto didEnterMain = C.getDidEnterMain(nullptr)) { |
| ManagedValue params[] = { |
| ManagedValue::forUnmanaged(argc), |
| ManagedValue::forUnmanaged(argv), |
| }; |
| 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()->getResult().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); |
| } |