mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
1575 lines
62 KiB
C++
1575 lines
62 KiB
C++
//===--- SILGenFunction.cpp - Top-level lowering for functions ------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the primary routines for creating and emitting
|
|
// functions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SILGenFunction.h"
|
|
#include "Cleanup.h"
|
|
#include "RValue.h"
|
|
#include "SILGenFunctionBuilder.h"
|
|
#include "Scope.h"
|
|
#include "swift/ABI/MetadataValues.h"
|
|
#include "swift/AST/ASTMangler.h"
|
|
#include "swift/AST/ASTScope.h"
|
|
#include "swift/AST/ClangModuleLoader.h"
|
|
#include "swift/AST/DiagnosticsSIL.h"
|
|
#include "swift/AST/FileUnit.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/PropertyWrappers.h"
|
|
#include "swift/AST/SourceFile.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/SIL/SILArgument.h"
|
|
#include "swift/SIL/SILProfiler.h"
|
|
#include "swift/SIL/SILUndef.h"
|
|
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
#define DEBUG_TYPE "silscopes"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILGenFunction Class implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SILGenFunction::SILGenFunction(SILGenModule &SGM, SILFunction &F,
|
|
DeclContext *DC)
|
|
: SGM(SGM), F(F), silConv(SGM.M), FunctionDC(DC),
|
|
StartOfPostmatter(F.end()), B(*this),
|
|
SF(DC ? DC->getParentSourceFile() : nullptr), Cleanups(*this),
|
|
StatsTracer(SGM.M.getASTContext().Stats, "SILGen-function", &F) {
|
|
assert(DC && "creating SGF without a DeclContext?");
|
|
B.setInsertionPoint(createBasicBlock());
|
|
B.setCurrentDebugScope(F.getDebugScope());
|
|
SourceLoc SLoc = F.getLocation().getSourceLoc();
|
|
if (SF && SLoc) {
|
|
FnASTScope = ast_scope::ASTScopeImpl::findStartingScopeForLookup(SF, SLoc);
|
|
ScopeMap.insert({FnASTScope, F.getDebugScope()});
|
|
}
|
|
}
|
|
|
|
/// SILGenFunction destructor - called after the entire function's AST has been
|
|
/// visited. This handles "falling off the end of the function" logic.
|
|
SILGenFunction::~SILGenFunction() {
|
|
// If the end of the function isn't terminated, we screwed up somewhere.
|
|
assert(!B.hasValidInsertionPoint() &&
|
|
"SILGenFunction did not terminate function?!");
|
|
|
|
// If we didn't clean up the rethrow destination, we screwed up somewhere.
|
|
assert(!ThrowDest.isValid() &&
|
|
"SILGenFunction did not emit throw destination");
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Function emission
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Get the #function name for a declaration.
|
|
DeclName SILGenModule::getMagicFunctionName(DeclContext *dc) {
|
|
// For closures, use the parent name.
|
|
if (auto closure = dyn_cast<AbstractClosureExpr>(dc)) {
|
|
return getMagicFunctionName(closure->getParent());
|
|
}
|
|
if (auto absFunc = dyn_cast<AbstractFunctionDecl>(dc)) {
|
|
// If this is an accessor, use the name of the storage.
|
|
if (auto accessor = dyn_cast<AccessorDecl>(absFunc))
|
|
return accessor->getStorage()->getName();
|
|
if (auto func = dyn_cast<FuncDecl>(absFunc)) {
|
|
// If this is a defer body, use the parent name.
|
|
if (func->isDeferBody()) {
|
|
return getMagicFunctionName(func->getParent());
|
|
}
|
|
}
|
|
|
|
return absFunc->getName();
|
|
}
|
|
if (auto init = dyn_cast<Initializer>(dc)) {
|
|
return getMagicFunctionName(init->getParent());
|
|
}
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(dc)) {
|
|
return nominal->getName();
|
|
}
|
|
if (auto tl = dyn_cast<TopLevelCodeDecl>(dc)) {
|
|
return tl->getModuleContext()->getName();
|
|
}
|
|
if (auto fu = dyn_cast<FileUnit>(dc)) {
|
|
return fu->getParentModule()->getName();
|
|
}
|
|
if (auto m = dyn_cast<ModuleDecl>(dc)) {
|
|
return m->getName();
|
|
}
|
|
if (auto e = dyn_cast<ExtensionDecl>(dc)) {
|
|
assert(e->getExtendedNominal() && "extension for nonnominal");
|
|
return e->getExtendedNominal()->getName();
|
|
}
|
|
if (auto EED = dyn_cast<EnumElementDecl>(dc)) {
|
|
return EED->getName();
|
|
}
|
|
if (auto SD = dyn_cast<SubscriptDecl>(dc)) {
|
|
return SD->getName();
|
|
}
|
|
llvm_unreachable("unexpected #function context");
|
|
}
|
|
|
|
DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
|
|
switch (ref.kind) {
|
|
case SILDeclRef::Kind::Func:
|
|
if (auto closure = ref.getAbstractClosureExpr())
|
|
return getMagicFunctionName(closure);
|
|
return getMagicFunctionName(cast<FuncDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::Initializer:
|
|
case SILDeclRef::Kind::Allocator:
|
|
return getMagicFunctionName(cast<ConstructorDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::Deallocator:
|
|
case SILDeclRef::Kind::Destroyer:
|
|
return getMagicFunctionName(cast<DestructorDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::GlobalAccessor:
|
|
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
|
|
case SILDeclRef::Kind::DefaultArgGenerator:
|
|
return getMagicFunctionName(cast<DeclContext>(ref.getDecl()));
|
|
case SILDeclRef::Kind::StoredPropertyInitializer:
|
|
case SILDeclRef::Kind::PropertyWrapperBackingInitializer:
|
|
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
|
|
case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue:
|
|
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
|
|
case SILDeclRef::Kind::IVarInitializer:
|
|
return getMagicFunctionName(cast<ClassDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::IVarDestroyer:
|
|
return getMagicFunctionName(cast<ClassDecl>(ref.getDecl()));
|
|
case SILDeclRef::Kind::EnumElement:
|
|
return getMagicFunctionName(cast<EnumElementDecl>(ref.getDecl())
|
|
->getDeclContext());
|
|
case SILDeclRef::Kind::AsyncEntryPoint:
|
|
case SILDeclRef::Kind::EntryPoint: {
|
|
auto *file = ref.getDecl()->getDeclContext()->getParentSourceFile();
|
|
return getMagicFunctionName(file);
|
|
}
|
|
case SILDeclRef::Kind::RuntimeAttributeGenerator: {
|
|
if (auto *var = dyn_cast<VarDecl>(ref.getDecl()))
|
|
return var->getName();
|
|
|
|
auto *DC = dyn_cast<DeclContext>(ref.getDecl());
|
|
return getMagicFunctionName(DC ? DC : ref.getDecl()->getDeclContext());
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Unhandled SILDeclRefKind in switch.");
|
|
}
|
|
|
|
SILDebugLocation
|
|
SILGenFunction::getSILDebugLocation(SILBuilder &B, SILLocation Loc,
|
|
Optional<SILLocation> CurDebugLocOverride,
|
|
bool ForMetaInstruction) {
|
|
const SILDebugScope *Scope = B.getCurrentDebugScope();
|
|
if (!Scope)
|
|
Scope = F.getDebugScope();
|
|
if (auto *SILScope = getScopeOrNull(Loc, ForMetaInstruction)) {
|
|
Scope = SILScope;
|
|
// Metainstructions such as a debug_value may break the flow of scopes and
|
|
// should not change the state of the builder.
|
|
if (!ForMetaInstruction)
|
|
B.setCurrentDebugScope(Scope);
|
|
}
|
|
auto overriddenLoc = CurDebugLocOverride ? *CurDebugLocOverride : Loc;
|
|
return SILDebugLocation(overriddenLoc, Scope);
|
|
}
|
|
|
|
const SILDebugScope *SILGenFunction::getScopeOrNull(SILLocation Loc,
|
|
bool ForMetaInstruction) {
|
|
if (!ForMetaInstruction) {
|
|
if (Loc.getKind() == SILLocation::CleanupKind ||
|
|
Loc.getKind() == SILLocation::ImplicitReturnKind ||
|
|
// The source locations produced by the ResultBuilder transformation are
|
|
// all over the place.
|
|
Loc.isImplicit() || Loc.isAutoGenerated())
|
|
return nullptr;
|
|
}
|
|
|
|
SourceLoc SLoc = Loc.getSourceLoc();//ForDebugging();
|
|
if (!SF || LastSourceLoc == SLoc)
|
|
return nullptr;
|
|
return getOrCreateScope(SLoc);
|
|
}
|
|
|
|
const SILDebugScope *SILGenFunction::getOrCreateScope(SourceLoc SLoc) {
|
|
if (const SILDebugScope *macroScope = getMacroScope(SLoc))
|
|
return macroScope;
|
|
auto *astScope =
|
|
ast_scope::ASTScopeImpl::findStartingScopeForLookup(SF, SLoc);
|
|
|
|
// At the call site of a closure, the ASTScope created for the ClosureExpr
|
|
// has no parents, so filter it out here.
|
|
if (!astScope->getParent())
|
|
return nullptr;
|
|
|
|
const SILDebugScope *Scope = getOrCreateScope(astScope);
|
|
assert(Scope && "failed to construct SILDebugScope from ASTScope");
|
|
return Scope;
|
|
}
|
|
|
|
static std::pair<SILLocation, std::string>
|
|
getMacroName(GeneratedSourceInfo &Info) {
|
|
SourceLoc MacroSLoc = Info.generatedSourceRange.getStart();
|
|
RegularLocation Loc(MacroSLoc);
|
|
Mangle::ASTMangler mangler;
|
|
std::string Name = "__unknown_macro__";
|
|
if (!Info.astNode)
|
|
return {Loc, Name};
|
|
|
|
// Keep this in sync with ASTMangler::appendMacroExpansionContext().
|
|
switch (Info.kind) {
|
|
case GeneratedSourceInfo::ExpressionMacroExpansion: {
|
|
auto parent = ASTNode::getFromOpaqueValue(Info.astNode);
|
|
if (auto expr =
|
|
cast_or_null<MacroExpansionExpr>(parent.dyn_cast<Expr *>())) {
|
|
Loc = RegularLocation(expr);
|
|
Name = mangler.mangleMacroExpansion(expr);
|
|
} else {
|
|
auto decl = cast<MacroExpansionDecl>(parent.get<Decl *>());
|
|
Loc = RegularLocation(decl);
|
|
Name = mangler.mangleMacroExpansion(decl);
|
|
}
|
|
break;
|
|
}
|
|
case GeneratedSourceInfo::FreestandingDeclMacroExpansion: {
|
|
auto expansion = cast<MacroExpansionDecl>(
|
|
ASTNode::getFromOpaqueValue(Info.astNode).get<Decl *>());
|
|
Loc = RegularLocation(expansion);
|
|
Name = mangler.mangleMacroExpansion(expansion);
|
|
break;
|
|
}
|
|
case GeneratedSourceInfo::AccessorMacroExpansion:
|
|
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
|
|
case GeneratedSourceInfo::MemberMacroExpansion:
|
|
case GeneratedSourceInfo::PeerMacroExpansion:
|
|
case GeneratedSourceInfo::ConformanceMacroExpansion: {
|
|
auto decl = ASTNode::getFromOpaqueValue(Info.astNode).get<Decl *>();
|
|
auto attr = Info.attachedMacroCustomAttr;
|
|
if (auto *macroDecl = decl->getResolvedMacro(attr)) {
|
|
Loc = RegularLocation(macroDecl);
|
|
Name = macroDecl->getBaseName().userFacingName();
|
|
}
|
|
break;
|
|
}
|
|
case GeneratedSourceInfo::PrettyPrinted:
|
|
case GeneratedSourceInfo::ReplacedFunctionBody:
|
|
break;
|
|
}
|
|
return {Loc, Name};
|
|
}
|
|
|
|
const SILDebugScope *SILGenFunction::getMacroScope(SourceLoc SLoc) {
|
|
auto &SM = getSourceManager();
|
|
unsigned BufferID = SM.findBufferContainingLoc(SLoc);
|
|
auto GeneratedSourceInfo = SM.getGeneratedSourceInfo(BufferID);
|
|
if (!GeneratedSourceInfo)
|
|
return nullptr;
|
|
|
|
SourceLoc OrigSLoc = GeneratedSourceInfo->originalSourceRange.getStart();
|
|
if (!OrigSLoc)
|
|
return nullptr;
|
|
|
|
auto It = InlinedScopeMap.find(BufferID);
|
|
if (It != InlinedScopeMap.end())
|
|
return It->second;
|
|
|
|
// Recursively create one inlined function + scope per layer of generated
|
|
// sources. Chains of Macro expansions are representad as flat function-level
|
|
// scopes.
|
|
SILGenFunctionBuilder B(SGM);
|
|
auto &ASTContext = SGM.M.getASTContext();
|
|
auto ExtInfo = SILFunctionType::ExtInfo::getThin();
|
|
auto FunctionType = SILFunctionType::get(
|
|
nullptr, ExtInfo, SILCoroutineKind::None,
|
|
ParameterConvention::Direct_Unowned, /*Params*/ {},
|
|
/*yields*/
|
|
{},
|
|
/*Results*/ {}, None, SubstitutionMap(), SubstitutionMap(), ASTContext);
|
|
auto LocName = getMacroName(*GeneratedSourceInfo);
|
|
RegularLocation MacroLoc(LocName.first);
|
|
StringRef MacroName = ASTContext.getIdentifier(LocName.second).str();
|
|
SILFunction *MacroFn = B.getOrCreateFunction(
|
|
MacroLoc, MacroName, SILLinkage::DefaultForDeclaration, FunctionType,
|
|
IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic,
|
|
IsNotDistributed, IsNotRuntimeAccessible);
|
|
// At the end of the chain OrigSLoc should be a macro expansion node.
|
|
const SILDebugScope *InlinedAt = getOrCreateScope(OrigSLoc);
|
|
// Inject an extra scope to hold the inlined call site.
|
|
if (InlinedAt)
|
|
InlinedAt =
|
|
new (SGM.M) SILDebugScope(RegularLocation(OrigSLoc), nullptr, InlinedAt,
|
|
InlinedAt->InlinedCallSite);
|
|
const SILDebugScope *Scope =
|
|
new (SGM.M) SILDebugScope(MacroLoc, MacroFn, nullptr, InlinedAt);
|
|
|
|
InlinedScopeMap.insert({BufferID, Scope});
|
|
return Scope;
|
|
}
|
|
|
|
const SILDebugScope *
|
|
SILGenFunction::getOrCreateScope(const ast_scope::ASTScopeImpl *ASTScope) {
|
|
const SILDebugScope *FnScope = F.getDebugScope();
|
|
|
|
if (!ASTScope)
|
|
return FnScope;
|
|
|
|
// Top-level function scope?
|
|
if (ASTScope == FnASTScope)
|
|
return FnScope;
|
|
|
|
auto It = ScopeMap.find(ASTScope);
|
|
if (It != ScopeMap.end())
|
|
return It->second;
|
|
|
|
LLVM_DEBUG( ASTScope->print(llvm::errs(), 0, false, false) );
|
|
|
|
SILDebugScope *SILScope = nullptr;
|
|
|
|
// Decide whether to pick a parent scope instead.
|
|
if (ASTScope->ignoreInDebugInfo()) {
|
|
LLVM_DEBUG(llvm::dbgs() << "ignored\n");
|
|
// FIXME: it would be more deterministic to use
|
|
// getOrCreateScope(ASTScope->getParent().getPtrOrNull());
|
|
// here. Unfortunately property wrappers rearrange AST
|
|
// nodes without marking them as implicit, e.g.:
|
|
//
|
|
// @Wrapper(a) var v = b
|
|
// ->
|
|
// let _tmp = Constructor(a, b); var v = _tmp
|
|
//
|
|
// Since the arguments to Constructor aren't marked as implicit,
|
|
// argument b is in the scope of v, but the call to Constructor
|
|
// isn't, which correctly triggers the scope hole verifier.
|
|
return B.getCurrentDebugScope();
|
|
}
|
|
|
|
// Collapse BraceStmtScopes whose parent is a .*BodyScope.
|
|
if (auto Parent = ASTScope->getParent().getPtrOrNull())
|
|
if (Parent->getSourceRangeOfThisASTNode() ==
|
|
ASTScope->getSourceRangeOfThisASTNode())
|
|
return getOrCreateScope(Parent);
|
|
|
|
// The calls to defer closures have cleanup source locations pointing to the
|
|
// defer. Reparent them into the current debug scope.
|
|
auto *AncestorScope = ASTScope->getParent().getPtrOrNull();
|
|
while (AncestorScope && AncestorScope != FnASTScope &&
|
|
!ScopeMap.count(AncestorScope)) {
|
|
if (auto *FD = dyn_cast_or_null<FuncDecl>(
|
|
AncestorScope->getDeclIfAny().getPtrOrNull())) {
|
|
if (cast<DeclContext>(FD) != FunctionDC)
|
|
return B.getCurrentDebugScope();
|
|
|
|
// This is this function's own scope.
|
|
// If this is the outermost BraceStmt scope, ignore it.
|
|
if (AncestorScope == ASTScope->getParent().getPtrOrNull())
|
|
return FnScope;
|
|
break;
|
|
}
|
|
|
|
AncestorScope = AncestorScope->getParent().getPtrOrNull();
|
|
};
|
|
|
|
const SILDebugScope *Parent =
|
|
getOrCreateScope(ASTScope->getParent().getPtrOrNull());
|
|
RegularLocation Loc(ASTScope->getSourceRangeOfThisASTNode().Start);
|
|
SILScope = new (SGM.M) SILDebugScope(Loc, &F, Parent);
|
|
ScopeMap.insert({ASTScope, SILScope});
|
|
return SILScope;
|
|
}
|
|
|
|
void SILGenFunction::enterDebugScope(SILLocation Loc, bool isBindingScope) {
|
|
// Initialize the builder with a default SILDebugScope for this scope.
|
|
if (const SILDebugScope *Scope = getScopeOrNull(Loc))
|
|
B.setCurrentDebugScope(Scope);
|
|
}
|
|
|
|
/// Return to the previous debug scope.
|
|
void SILGenFunction::leaveDebugScope() {}
|
|
|
|
std::tuple<ManagedValue, SILType>
|
|
SILGenFunction::emitSiblingMethodRef(SILLocation loc,
|
|
SILValue selfValue,
|
|
SILDeclRef methodConstant,
|
|
SubstitutionMap subMap) {
|
|
SILValue methodValue;
|
|
|
|
// If the method is dynamic, access it through runtime-hookable virtual
|
|
// dispatch (viz. objc_msgSend for now).
|
|
if (methodConstant.hasDecl()
|
|
&& methodConstant.getDecl()->shouldUseObjCDispatch()) {
|
|
methodValue =
|
|
emitDynamicMethodRef(
|
|
loc, methodConstant,
|
|
SGM.Types.getConstantInfo(getTypeExpansionContext(), methodConstant)
|
|
.SILFnType)
|
|
.getValue();
|
|
} else {
|
|
methodValue = emitGlobalFunctionRef(loc, methodConstant);
|
|
}
|
|
|
|
SILType methodTy = methodValue->getType();
|
|
|
|
// Specialize the generic method.
|
|
methodTy =
|
|
methodTy.substGenericArgs(SGM.M, subMap, getTypeExpansionContext());
|
|
|
|
return std::make_tuple(ManagedValue::forUnmanaged(methodValue),
|
|
methodTy);
|
|
}
|
|
|
|
void SILGenFunction::emitCaptures(SILLocation loc,
|
|
SILDeclRef closure,
|
|
CaptureEmission purpose,
|
|
SmallVectorImpl<ManagedValue> &capturedArgs) {
|
|
loc.markAutoGenerated();
|
|
auto captureInfo = SGM.Types.getLoweredLocalCaptures(closure);
|
|
// For boxed captures, we need to mark the contained variables as having
|
|
// escaped for DI diagnostics.
|
|
SmallVector<SILValue, 2> escapesToMark;
|
|
|
|
// Partial applications take ownership of the context parameters, so we'll
|
|
// need to pass ownership rather than merely guaranteeing parameters.
|
|
bool canGuarantee;
|
|
bool captureCanEscape = true;
|
|
switch (purpose) {
|
|
case CaptureEmission::PartialApplication:
|
|
canGuarantee = false;
|
|
break;
|
|
case CaptureEmission::ImmediateApplication:
|
|
canGuarantee = true;
|
|
break;
|
|
case CaptureEmission::AssignByWrapper:
|
|
canGuarantee = false;
|
|
captureCanEscape = false;
|
|
break;
|
|
}
|
|
|
|
auto expansion = getTypeExpansionContext();
|
|
|
|
for (auto capture : captureInfo.getCaptures()) {
|
|
if (capture.isDynamicSelfMetadata()) {
|
|
// The parameter type is the static Self type, but the value we
|
|
// want to pass is the dynamic Self type, so upcast it.
|
|
auto dynamicSelfMetatype = MetatypeType::get(
|
|
captureInfo.getDynamicSelfType());
|
|
SILType dynamicSILType = getLoweredType(dynamicSelfMetatype);
|
|
|
|
SILValue value = B.createMetatype(loc, dynamicSILType);
|
|
capturedArgs.push_back(ManagedValue::forUnmanaged(value));
|
|
continue;
|
|
}
|
|
|
|
if (capture.isOpaqueValue()) {
|
|
OpaqueValueExpr *opaqueValue = capture.getOpaqueValue();
|
|
capturedArgs.push_back(
|
|
emitRValueAsSingleValue(opaqueValue).ensurePlusOne(*this, loc));
|
|
continue;
|
|
}
|
|
|
|
auto *vd = cast<VarDecl>(capture.getDecl());
|
|
auto type = FunctionDC->mapTypeIntoContext(
|
|
vd->getInterfaceType());
|
|
auto valueType = FunctionDC->mapTypeIntoContext(
|
|
vd->getValueInterfaceType());
|
|
|
|
//
|
|
// If we haven't emitted the captured value yet, we're forming a closure
|
|
// to a local function before all of its captures have been emitted. Eg,
|
|
//
|
|
// func f() { g() } // transitive capture of 'x'
|
|
// f() // closure formed here
|
|
// var x = 123 // 'x' defined here
|
|
// func g() { print(x) } // 'x' captured here
|
|
//
|
|
auto found = VarLocs.find(vd);
|
|
if (found == VarLocs.end()) {
|
|
auto &Diags = getASTContext().Diags;
|
|
|
|
SourceLoc loc;
|
|
if (closure.kind == SILDeclRef::Kind::DefaultArgGenerator) {
|
|
auto *param = getParameterAt(closure.getDecl(),
|
|
closure.defaultArgIndex);
|
|
assert(param);
|
|
loc = param->getLoc();
|
|
} else {
|
|
auto f = *closure.getAnyFunctionRef();
|
|
loc = f.getLoc();
|
|
}
|
|
|
|
Diags.diagnose(loc, diag::capture_before_declaration,
|
|
vd->getBaseIdentifier());
|
|
Diags.diagnose(vd->getLoc(), diag::captured_value_declared_here);
|
|
Diags.diagnose(capture.getLoc(), diag::value_captured_here);
|
|
|
|
// Emit an 'undef' of the correct type.
|
|
auto captureKind = SGM.Types.getDeclCaptureKind(capture, expansion);
|
|
switch (captureKind) {
|
|
case CaptureKind::Constant:
|
|
capturedArgs.push_back(emitUndef(getLoweredType(type)));
|
|
break;
|
|
case CaptureKind::Immutable:
|
|
case CaptureKind::StorageAddress: {
|
|
auto ty = getLoweredType(type);
|
|
if (SGM.M.useLoweredAddresses())
|
|
ty = ty.getAddressType();
|
|
capturedArgs.push_back(emitUndef(ty));
|
|
break;
|
|
}
|
|
case CaptureKind::ImmutableBox:
|
|
case CaptureKind::Box: {
|
|
bool isMutable = captureKind == CaptureKind::Box;
|
|
auto boxTy = SGM.Types.getContextBoxTypeForCapture(
|
|
vd,
|
|
SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(),
|
|
type),
|
|
FunctionDC->getGenericEnvironmentOfContext(),
|
|
/*mutable*/ isMutable);
|
|
capturedArgs.push_back(emitUndef(boxTy));
|
|
break;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Get an address value for a SILValue if it is address only in an type
|
|
// expansion context without opaque archetype substitution.
|
|
auto getAddressValue = [&](VarLoc entryVarLoc) -> SILValue {
|
|
SILValue entryValue = entryVarLoc.value;
|
|
if (SGM.M.useLoweredAddresses()
|
|
&& SGM.Types
|
|
.getTypeLowering(
|
|
valueType,
|
|
TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(
|
|
expansion.getResilienceExpansion()))
|
|
.isAddressOnly()
|
|
&& !entryValue->getType().isAddress()) {
|
|
|
|
auto addr = emitTemporaryAllocation(vd, entryValue->getType(), false,
|
|
false, /*generateDebugInfo*/ false);
|
|
auto val = B.emitCopyValueOperation(loc, entryValue);
|
|
auto &lowering = getTypeLowering(entryValue->getType());
|
|
lowering.emitStore(B, loc, val, addr, StoreOwnershipQualifier::Init);
|
|
entryValue = addr;
|
|
enterDestroyCleanup(addr);
|
|
}
|
|
return entryValue;
|
|
};
|
|
|
|
auto Entry = found->second;
|
|
switch (SGM.Types.getDeclCaptureKind(capture, expansion)) {
|
|
case CaptureKind::Constant: {
|
|
// let declarations.
|
|
auto &tl = getTypeLowering(valueType);
|
|
SILValue Val = Entry.value;
|
|
bool eliminateMoveOnlyWrapper =
|
|
Val->getType().isMoveOnlyWrapped() &&
|
|
!vd->getInterfaceType()->is<SILMoveOnlyWrappedType>();
|
|
|
|
if (!Val->getType().isAddress()) {
|
|
// Our 'let' binding can guarantee the lifetime for the callee,
|
|
// if we don't need to do anything more to it.
|
|
if (canGuarantee && !vd->getInterfaceType()->is<ReferenceStorageType>()) {
|
|
auto guaranteed = ManagedValue::forUnmanaged(Val).borrow(*this, loc);
|
|
if (eliminateMoveOnlyWrapper)
|
|
guaranteed = B.createGuaranteedMoveOnlyWrapperToCopyableValue(
|
|
loc, guaranteed);
|
|
capturedArgs.push_back(guaranteed);
|
|
break;
|
|
}
|
|
|
|
// Just copy a by-val let.
|
|
Val = B.emitCopyValueOperation(loc, Val);
|
|
// If we need to unwrap a moveonlywrapped value, do so now but in an
|
|
// owned way to ensure that the partial apply is viewed as a semantic
|
|
// use of the value.
|
|
if (eliminateMoveOnlyWrapper)
|
|
Val = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, Val);
|
|
} else {
|
|
// If we have a mutable binding for a 'let', such as 'self' in an
|
|
// 'init' method, load it.
|
|
if (Val->getType().isMoveOnly()) {
|
|
Val = B.createMarkMustCheckInst(
|
|
loc, Val,
|
|
MarkMustCheckInst::CheckKind::AssignableButNotConsumable);
|
|
}
|
|
Val = emitLoad(loc, Val, tl, SGFContext(), IsNotTake).forward(*this);
|
|
}
|
|
|
|
// If we're capturing an unowned pointer by value, we will have just
|
|
// loaded it into a normal retained class pointer, but we capture it as
|
|
// an unowned pointer. Convert back now.
|
|
if (vd->getInterfaceType()->is<ReferenceStorageType>())
|
|
Val = emitConversionFromSemanticValue(loc, Val, getLoweredType(type));
|
|
|
|
capturedArgs.push_back(emitManagedRValueWithCleanup(Val));
|
|
break;
|
|
}
|
|
case CaptureKind::Immutable: {
|
|
if (canGuarantee) {
|
|
// No-escaping stored declarations are captured as the
|
|
// address of the value.
|
|
auto entryValue = getAddressValue(Entry);
|
|
capturedArgs.push_back(ManagedValue::forBorrowedRValue(entryValue));
|
|
}
|
|
else if (!silConv.useLoweredAddresses()) {
|
|
capturedArgs.push_back(
|
|
B.createCopyValue(loc, ManagedValue::forUnmanaged(Entry.value)));
|
|
} else {
|
|
auto entryValue = getAddressValue(Entry);
|
|
// We cannot pass a valid SILDebugVariable while creating the temp here
|
|
// See rdar://60425582
|
|
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
|
|
enterDeallocStackCleanup(addr);
|
|
B.createCopyAddr(loc, entryValue, addr, IsNotTake, IsInitialization);
|
|
capturedArgs.push_back(ManagedValue::forLValue(addr));
|
|
}
|
|
break;
|
|
}
|
|
case CaptureKind::StorageAddress: {
|
|
auto entryValue = getAddressValue(Entry);
|
|
// No-escaping stored declarations are captured as the
|
|
// address of the value.
|
|
assert(entryValue->getType().isAddress() && "no address for captured var!");
|
|
capturedArgs.push_back(ManagedValue::forLValue(entryValue));
|
|
break;
|
|
}
|
|
|
|
case CaptureKind::Box: {
|
|
auto entryValue = getAddressValue(Entry);
|
|
// LValues are captured as both the box owning the value and the
|
|
// address of the value.
|
|
assert(entryValue->getType().isAddress() && "no address for captured var!");
|
|
// Boxes of opaque return values stay opaque.
|
|
auto minimalLoweredType = SGM.Types.getLoweredRValueType(
|
|
TypeExpansionContext::minimal(), type->getCanonicalType());
|
|
// If this is a boxed variable, we can use it directly.
|
|
if (Entry.box &&
|
|
entryValue->getType().getASTType() == minimalLoweredType) {
|
|
// We can guarantee our own box to the callee.
|
|
if (canGuarantee) {
|
|
capturedArgs.push_back(
|
|
ManagedValue::forUnmanaged(Entry.box).borrow(*this, loc));
|
|
} else {
|
|
capturedArgs.push_back(emitManagedRetain(loc, Entry.box));
|
|
}
|
|
if (captureCanEscape)
|
|
escapesToMark.push_back(entryValue);
|
|
} else {
|
|
// Address only 'let' values are passed by box. This isn't great, in
|
|
// that a variable captured by multiple closures will be boxed for each
|
|
// one. This could be improved by doing an "isCaptured" analysis when
|
|
// emitting address-only let constants, and emit them into an alloc_box
|
|
// like a variable instead of into an alloc_stack.
|
|
//
|
|
// TODO: This might not be profitable anymore with guaranteed captures,
|
|
// since we could conceivably forward the copied value into the
|
|
// closure context and pass it down to the partially applied function
|
|
// in-place.
|
|
// TODO: Use immutable box for immutable captures.
|
|
auto boxTy = SGM.Types.getContextBoxTypeForCapture(
|
|
vd, minimalLoweredType, FunctionDC->getGenericEnvironmentOfContext(),
|
|
/*mutable*/ true);
|
|
|
|
AllocBoxInst *allocBox = B.createAllocBox(loc, boxTy);
|
|
ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox, 0);
|
|
B.createCopyAddr(loc, entryValue, boxAddress, IsNotTake,
|
|
IsInitialization);
|
|
if (canGuarantee)
|
|
capturedArgs.push_back(
|
|
emitManagedRValueWithCleanup(allocBox).borrow(*this, loc));
|
|
else
|
|
capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox));
|
|
}
|
|
|
|
break;
|
|
}
|
|
case CaptureKind::ImmutableBox: {
|
|
auto entryValue = getAddressValue(Entry);
|
|
// LValues are captured as both the box owning the value and the
|
|
// address of the value.
|
|
assert(entryValue->getType().isAddress() &&
|
|
"no address for captured var!");
|
|
// Boxes of opaque return values stay opaque.
|
|
auto minimalLoweredType = SGM.Types.getLoweredRValueType(
|
|
TypeExpansionContext::minimal(), type->getCanonicalType());
|
|
// If this is a boxed variable, we can use it directly.
|
|
if (Entry.box &&
|
|
entryValue->getType().getASTType() == minimalLoweredType) {
|
|
// We can guarantee our own box to the callee.
|
|
if (canGuarantee) {
|
|
capturedArgs.push_back(
|
|
ManagedValue::forUnmanaged(Entry.box).borrow(*this, loc));
|
|
} else {
|
|
capturedArgs.push_back(emitManagedRetain(loc, Entry.box));
|
|
}
|
|
if (captureCanEscape)
|
|
escapesToMark.push_back(entryValue);
|
|
} else {
|
|
// Address only 'let' values are passed by box. This isn't great, in
|
|
// that a variable captured by multiple closures will be boxed for each
|
|
// one. This could be improved by doing an "isCaptured" analysis when
|
|
// emitting address-only let constants, and emit them into an alloc_box
|
|
// like a variable instead of into an alloc_stack.
|
|
//
|
|
// TODO: This might not be profitable anymore with guaranteed captures,
|
|
// since we could conceivably forward the copied value into the
|
|
// closure context and pass it down to the partially applied function
|
|
// in-place.
|
|
// TODO: Use immutable box for immutable captures.
|
|
auto boxTy = SGM.Types.getContextBoxTypeForCapture(
|
|
vd, minimalLoweredType,
|
|
FunctionDC->getGenericEnvironmentOfContext(),
|
|
/*mutable*/ false);
|
|
|
|
AllocBoxInst *allocBox = B.createAllocBox(loc, boxTy);
|
|
ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox, 0);
|
|
B.createCopyAddr(loc, entryValue, boxAddress, IsNotTake,
|
|
IsInitialization);
|
|
if (canGuarantee)
|
|
capturedArgs.push_back(
|
|
emitManagedRValueWithCleanup(allocBox).borrow(*this, loc));
|
|
else
|
|
capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox));
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mark box addresses as captured for DI purposes. The values must have
|
|
// been fully initialized before we close over them.
|
|
if (!escapesToMark.empty()) {
|
|
B.createMarkFunctionEscape(loc, escapesToMark);
|
|
}
|
|
}
|
|
|
|
ManagedValue
|
|
SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
|
|
CanType expectedType,
|
|
SubstitutionMap subs,
|
|
bool alreadyConverted) {
|
|
auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(constant);
|
|
SGM.Types.setCaptureTypeExpansionContext(constant, SGM.M);
|
|
|
|
auto constantInfo = getConstantInfo(getTypeExpansionContext(), constant);
|
|
SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo);
|
|
SILType functionTy = functionRef->getType();
|
|
|
|
// Apply substitutions.
|
|
auto pft = constantInfo.SILFnType;
|
|
|
|
auto closure = *constant.getAnyFunctionRef();
|
|
auto *dc = closure.getAsDeclContext()->getParent();
|
|
if (dc->isLocalContext() && !loweredCaptureInfo.hasGenericParamCaptures()) {
|
|
// If the lowered function type is not polymorphic but we were given
|
|
// substitutions, we have a closure in a generic context which does not
|
|
// capture generic parameters. Just drop the substitutions.
|
|
subs = { };
|
|
} else if (closure.getAbstractClosureExpr()) {
|
|
// If we have a closure expression in generic context, Sema won't give
|
|
// us substitutions, so we just use the forwarding substitutions from
|
|
// context.
|
|
subs = getForwardingSubstitutionMap();
|
|
}
|
|
|
|
bool wasSpecialized = false;
|
|
if (!subs.empty()) {
|
|
auto specialized =
|
|
pft->substGenericArgs(F.getModule(), subs, getTypeExpansionContext());
|
|
functionTy = SILType::getPrimitiveObjectType(specialized);
|
|
wasSpecialized = true;
|
|
}
|
|
|
|
// If we're in top-level code, we don't need to physically capture script
|
|
// globals, but we still need to mark them as escaping so that DI can flag
|
|
// uninitialized uses.
|
|
if (this == SGM.TopLevelSGF) {
|
|
auto captureInfo = closure.getCaptureInfo();
|
|
SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(
|
|
loc, captureInfo);
|
|
}
|
|
|
|
if (loweredCaptureInfo.getCaptures().empty() && !wasSpecialized) {
|
|
auto result = ManagedValue::forUnmanaged(functionRef);
|
|
if (!alreadyConverted)
|
|
result = emitOrigToSubstValue(loc, result,
|
|
AbstractionPattern(expectedType),
|
|
expectedType);
|
|
return result;
|
|
}
|
|
|
|
SmallVector<ManagedValue, 4> capturedArgs;
|
|
emitCaptures(loc, constant, CaptureEmission::PartialApplication,
|
|
capturedArgs);
|
|
|
|
// The partial application takes ownership of the context parameters.
|
|
SmallVector<SILValue, 4> forwardedArgs;
|
|
for (auto capture : capturedArgs)
|
|
forwardedArgs.push_back(capture.forward(*this));
|
|
|
|
auto calleeConvention = ParameterConvention::Direct_Guaranteed;
|
|
|
|
auto toClosure =
|
|
B.createPartialApply(loc, functionRef, subs, forwardedArgs,
|
|
calleeConvention);
|
|
auto result = emitManagedRValueWithCleanup(toClosure);
|
|
|
|
// Get the lowered AST types:
|
|
// - the original type
|
|
auto origFormalType = AbstractionPattern(constantInfo.LoweredType);
|
|
|
|
// - the substituted type
|
|
auto substFormalType = expectedType;
|
|
|
|
// Generalize if necessary.
|
|
if (!alreadyConverted)
|
|
result = emitOrigToSubstValue(loc, result, origFormalType,
|
|
substFormalType);
|
|
|
|
return result;
|
|
}
|
|
|
|
void SILGenFunction::emitFunction(FuncDecl *fd) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(fd);
|
|
|
|
auto captureInfo = SGM.M.Types.getLoweredLocalCaptures(SILDeclRef(fd));
|
|
emitProlog(captureInfo, fd->getParameters(), fd->getImplicitSelfDecl(), fd,
|
|
fd->getResultInterfaceType(), fd->hasThrows(), fd->getThrowsLoc());
|
|
|
|
if (fd->isDistributedActorFactory()) {
|
|
// Synthesize the factory function body
|
|
emitDistributedActorFactory(fd);
|
|
} else {
|
|
prepareEpilog(fd->getResultInterfaceType(),
|
|
fd->hasThrows(), CleanupLocation(fd));
|
|
|
|
emitProfilerIncrement(fd->getTypecheckedBody());
|
|
|
|
// Emit the actual function body as usual
|
|
emitStmt(fd->getTypecheckedBody());
|
|
|
|
emitEpilog(fd);
|
|
}
|
|
|
|
mergeCleanupBlocks();
|
|
}
|
|
|
|
void SILGenFunction::emitClosure(AbstractClosureExpr *ace) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(ace);
|
|
OrigFnType = SGM.M.Types.getConstantAbstractionPattern(SILDeclRef(ace));
|
|
|
|
auto resultIfaceTy = ace->getResultType()->mapTypeOutOfContext();
|
|
auto captureInfo = SGM.M.Types.getLoweredLocalCaptures(
|
|
SILDeclRef(ace));
|
|
emitProlog(captureInfo, ace->getParameters(), /*selfParam=*/nullptr,
|
|
ace, resultIfaceTy, ace->isBodyThrowing(), ace->getLoc(),
|
|
OrigFnType);
|
|
prepareEpilog(resultIfaceTy, ace->isBodyThrowing(), CleanupLocation(ace));
|
|
|
|
emitProfilerIncrement(ace);
|
|
if (auto *ce = dyn_cast<ClosureExpr>(ace)) {
|
|
emitStmt(ce->getBody());
|
|
} else {
|
|
auto *autoclosure = cast<AutoClosureExpr>(ace);
|
|
// Closure expressions implicitly return the result of their body
|
|
// expression.
|
|
if (B.hasValidInsertionPoint()) {
|
|
emitReturnExpr(ImplicitReturnLocation(ace),
|
|
autoclosure->getSingleExpressionBody());
|
|
}
|
|
}
|
|
emitEpilog(ace);
|
|
}
|
|
|
|
ManagedValue emitBuiltinCreateAsyncTask(SILGenFunction &SGF, SILLocation loc,
|
|
SubstitutionMap subs,
|
|
ArrayRef<ManagedValue> args,
|
|
SGFContext C);
|
|
|
|
void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) {
|
|
// Create the argc and argv arguments.
|
|
auto entry = B.getInsertionBB();
|
|
auto paramTypeIter = F.getConventions()
|
|
.getParameterSILTypes(getTypeExpansionContext())
|
|
.begin();
|
|
|
|
SILValue argc;
|
|
SILValue argv;
|
|
const bool isAsyncFunc =
|
|
isa<FuncDecl>(mainDecl) && static_cast<FuncDecl *>(mainDecl)->hasAsync();
|
|
if (!isAsyncFunc) {
|
|
argc = entry->createFunctionArgument(*paramTypeIter);
|
|
argv = entry->createFunctionArgument(*std::next(paramTypeIter));
|
|
}
|
|
|
|
switch (mainDecl->getArtificialMainKind()) {
|
|
case ArtificialMainKind::UIApplicationMain: {
|
|
// Emit a UIKit main.
|
|
// return UIApplicationMain(C_ARGC, C_ARGV, nil, ClassName);
|
|
|
|
auto *mainClass = cast<NominalTypeDecl>(mainDecl);
|
|
|
|
CanType NSStringTy = SGM.Types.getNSStringType();
|
|
CanType OptNSStringTy
|
|
= OptionalType::get(NSStringTy)->getCanonicalType();
|
|
|
|
// Look up UIApplicationMain.
|
|
// FIXME: Doing an AST lookup here is gross and not entirely sound;
|
|
// we're getting away with it because the types are guaranteed to already
|
|
// be imported.
|
|
ASTContext &ctx = getASTContext();
|
|
|
|
ImportPath::Element UIKitName =
|
|
{ctx.getIdentifier("UIKit"), SourceLoc()};
|
|
|
|
ModuleDecl *UIKit = ctx
|
|
.getClangModuleLoader()
|
|
->loadModule(SourceLoc(),
|
|
ImportPath::Module(llvm::makeArrayRef(UIKitName)));
|
|
assert(UIKit && "couldn't find UIKit objc module?!");
|
|
SmallVector<ValueDecl *, 2> results;
|
|
UIKit->lookupQualified(UIKit,
|
|
DeclNameRef(ctx.getIdentifier("UIApplicationMain")),
|
|
NL_QualifiedDefault,
|
|
results);
|
|
|
|
// As the comment above alludes, using a qualified lookup into UIKit is
|
|
// *not* sound. In particular, it's possible for the lookup to find the
|
|
// (deprecated) Swift copy of UIApplicationMain in UIKit and try to call
|
|
// that instead of the C entrypoint. Let's try to force this to happen.
|
|
auto FoundUIApplicationMain = llvm::find_if(results, [](const ValueDecl *VD) {
|
|
return !VD->getClangNode().isNull();
|
|
});
|
|
assert(FoundUIApplicationMain != results.end() &&
|
|
"Could not find a UIApplicationMain to call!");
|
|
ValueDecl *UIApplicationMainDecl = *FoundUIApplicationMain;
|
|
|
|
auto mainRef = SILDeclRef(UIApplicationMainDecl).asForeign();
|
|
SILGenFunctionBuilder builder(SGM);
|
|
auto UIApplicationMainFn =
|
|
builder.getOrCreateFunction(mainClass, mainRef, NotForDefinition);
|
|
auto fnTy = UIApplicationMainFn->getLoweredFunctionType();
|
|
SILFunctionConventions fnConv(fnTy, SGM.M);
|
|
|
|
// Get the class name as a string using NSStringFromClass.
|
|
CanType mainClassTy = mainClass->getDeclaredInterfaceType()
|
|
->getCanonicalType();
|
|
CanType mainClassMetaty = CanMetatypeType::get(mainClassTy,
|
|
MetatypeRepresentation::ObjC);
|
|
CanType anyObjectTy = ctx.getAnyObjectType();
|
|
CanType anyObjectMetaTy = CanExistentialMetatypeType::get(anyObjectTy,
|
|
MetatypeRepresentation::ObjC);
|
|
|
|
auto paramConvention = ParameterConvention::Direct_Unowned;
|
|
auto params = {SILParameterInfo(anyObjectMetaTy, paramConvention)};
|
|
std::array<SILResultInfo, 1> resultInfos = {
|
|
SILResultInfo(OptNSStringTy, ResultConvention::Autoreleased)};
|
|
auto repr = SILFunctionType::Representation::CFunctionPointer;
|
|
auto *clangFnType =
|
|
ctx.getCanonicalClangFunctionType(params, resultInfos[0], repr);
|
|
auto extInfo = SILFunctionType::ExtInfoBuilder()
|
|
.withRepresentation(repr)
|
|
.withClangFunctionType(clangFnType)
|
|
.build();
|
|
|
|
auto NSStringFromClassType = SILFunctionType::get(
|
|
nullptr, extInfo, SILCoroutineKind::None, paramConvention, params,
|
|
/*yields*/ {}, resultInfos, /*error result*/ None, SubstitutionMap(),
|
|
SubstitutionMap(), ctx);
|
|
|
|
auto NSStringFromClassFn = builder.getOrCreateFunction(
|
|
mainClass, "NSStringFromClass", SILLinkage::PublicExternal,
|
|
NSStringFromClassType, IsBare, IsTransparent, IsNotSerialized,
|
|
IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible);
|
|
auto NSStringFromClass = B.createFunctionRef(mainClass, NSStringFromClassFn);
|
|
SILValue metaTy = B.createMetatype(mainClass,
|
|
SILType::getPrimitiveObjectType(mainClassMetaty));
|
|
metaTy = B.createInitExistentialMetatype(mainClass, metaTy,
|
|
SILType::getPrimitiveObjectType(anyObjectMetaTy),
|
|
{});
|
|
SILValue optNameValue = B.createApply(
|
|
mainClass, NSStringFromClass, {}, metaTy);
|
|
ManagedValue optName = emitManagedRValueWithCleanup(optNameValue);
|
|
|
|
// Fix up the string parameters to have the right type.
|
|
SILType nameArgTy =
|
|
fnConv.getSILArgumentType(3, B.getTypeExpansionContext());
|
|
assert(nameArgTy ==
|
|
fnConv.getSILArgumentType(2, B.getTypeExpansionContext()));
|
|
(void)nameArgTy;
|
|
assert(optName.getType() == nameArgTy);
|
|
SILValue nilValue =
|
|
getOptionalNoneValue(mainClass, getTypeLowering(OptNSStringTy));
|
|
|
|
// Fix up argv to have the right type.
|
|
auto argvTy = fnConv.getSILArgumentType(1, B.getTypeExpansionContext());
|
|
|
|
SILType unwrappedTy = argvTy;
|
|
if (Type innerTy = argvTy.getASTType()->getOptionalObjectType()) {
|
|
auto canInnerTy = innerTy->getCanonicalType();
|
|
unwrappedTy = SILType::getPrimitiveObjectType(canInnerTy);
|
|
}
|
|
|
|
auto managedArgv = ManagedValue::forUnmanaged(argv);
|
|
|
|
if (unwrappedTy != argv->getType()) {
|
|
auto converted =
|
|
emitPointerToPointer(mainClass, managedArgv,
|
|
argv->getType().getASTType(),
|
|
unwrappedTy.getASTType());
|
|
managedArgv = std::move(converted).getAsSingleValue(*this, mainClass);
|
|
}
|
|
|
|
if (unwrappedTy != argvTy) {
|
|
managedArgv = getOptionalSomeValue(mainClass, managedArgv,
|
|
getTypeLowering(argvTy));
|
|
}
|
|
|
|
auto UIApplicationMain = B.createFunctionRef(mainClass, UIApplicationMainFn);
|
|
|
|
SILValue args[] = {argc, managedArgv.getValue(), nilValue,
|
|
optName.getValue()};
|
|
|
|
B.createApply(mainClass, UIApplicationMain, SubstitutionMap(), args);
|
|
SILValue r = B.createIntegerLiteral(mainClass,
|
|
SILType::getBuiltinIntegerType(32, ctx), 0);
|
|
auto rType =
|
|
F.getConventions().getSingleSILResultType(B.getTypeExpansionContext());
|
|
if (r->getType() != rType)
|
|
r = B.createStruct(mainClass, rType, r);
|
|
|
|
Cleanups.emitCleanupsForReturn(mainClass, NotForUnwind);
|
|
B.createReturn(mainClass, r);
|
|
return;
|
|
}
|
|
|
|
case ArtificialMainKind::NSApplicationMain: {
|
|
// Emit an AppKit main.
|
|
// return NSApplicationMain(C_ARGC, C_ARGV);
|
|
|
|
auto *mainClass = cast<NominalTypeDecl>(mainDecl);
|
|
|
|
SILParameterInfo argTypes[] = {
|
|
SILParameterInfo(argc->getType().getASTType(),
|
|
ParameterConvention::Direct_Unowned),
|
|
SILParameterInfo(argv->getType().getASTType(),
|
|
ParameterConvention::Direct_Unowned),
|
|
};
|
|
auto NSApplicationMainType = SILFunctionType::get(
|
|
nullptr,
|
|
// Should be C calling convention, but NSApplicationMain
|
|
// has an overlay to fix the type of argv.
|
|
SILFunctionType::ExtInfo::getThin(), SILCoroutineKind::None,
|
|
ParameterConvention::Direct_Unowned, argTypes,
|
|
/*yields*/ {},
|
|
SILResultInfo(argc->getType().getASTType(), ResultConvention::Unowned),
|
|
/*error result*/ None, SubstitutionMap(), SubstitutionMap(),
|
|
getASTContext());
|
|
|
|
SILGenFunctionBuilder builder(SGM);
|
|
auto NSApplicationMainFn = builder.getOrCreateFunction(
|
|
mainClass, "NSApplicationMain", SILLinkage::PublicExternal,
|
|
NSApplicationMainType, IsBare, IsTransparent, IsNotSerialized,
|
|
IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible);
|
|
|
|
auto NSApplicationMain = B.createFunctionRef(mainClass, NSApplicationMainFn);
|
|
SILValue args[] = { argc, argv };
|
|
|
|
B.createApply(mainClass, NSApplicationMain, SubstitutionMap(), args);
|
|
SILValue r = B.createIntegerLiteral(mainClass,
|
|
SILType::getBuiltinIntegerType(32, getASTContext()), 0);
|
|
auto rType =
|
|
F.getConventions().getSingleSILResultType(B.getTypeExpansionContext());
|
|
if (r->getType() != rType)
|
|
r = B.createStruct(mainClass, rType, r);
|
|
B.createReturn(mainClass, r);
|
|
return;
|
|
}
|
|
|
|
case ArtificialMainKind::TypeMain: {
|
|
// Emit a call to the main static function.
|
|
// return Module.$main();
|
|
auto *mainFunc = cast<FuncDecl>(mainDecl);
|
|
auto moduleLoc = SILLocation(mainDecl);
|
|
auto *entryBlock = B.getInsertionBB();
|
|
|
|
SILDeclRef mainFunctionDeclRef(mainFunc, SILDeclRef::Kind::Func);
|
|
SILFunction *mainFunction =
|
|
SGM.getFunction(mainFunctionDeclRef, NotForDefinition);
|
|
|
|
ExtensionDecl *mainExtension =
|
|
dyn_cast<ExtensionDecl>(mainFunc->getDeclContext());
|
|
|
|
NominalTypeDecl *mainType;
|
|
if (mainExtension) {
|
|
mainType = mainExtension->getExtendedNominal();
|
|
} else {
|
|
mainType = cast<NominalTypeDecl>(mainFunc->getDeclContext());
|
|
}
|
|
auto metatype = B.createMetatype(mainType, getLoweredType(mainType->getInterfaceType()));
|
|
|
|
auto mainFunctionRef = B.createFunctionRef(moduleLoc, mainFunction);
|
|
|
|
auto builtinInt32Type = SILType::getBuiltinIntegerType(32, getASTContext());
|
|
|
|
auto *exitBlock = createBasicBlock();
|
|
SILValue exitCode =
|
|
exitBlock->createPhiArgument(builtinInt32Type, OwnershipKind::None);
|
|
B.setInsertionPoint(exitBlock);
|
|
|
|
if (!mainFunc->hasAsync()) {
|
|
auto returnType = F.getConventions().getSingleSILResultType(
|
|
B.getTypeExpansionContext());
|
|
if (exitCode->getType() != returnType)
|
|
exitCode = B.createStruct(moduleLoc, returnType, exitCode);
|
|
B.createReturn(moduleLoc, exitCode);
|
|
} else {
|
|
FuncDecl *exitFuncDecl = SGM.getExit();
|
|
assert(exitFuncDecl && "Failed to find exit function declaration");
|
|
SILFunction *exitSILFunc = SGM.getFunction(
|
|
SILDeclRef(exitFuncDecl, SILDeclRef::Kind::Func, /*isForeign*/ true),
|
|
NotForDefinition);
|
|
|
|
SILFunctionType &funcType =
|
|
*exitSILFunc->getLoweredType().getAs<SILFunctionType>();
|
|
SILType retType = SILType::getPrimitiveObjectType(
|
|
funcType.getParameters().front().getInterfaceType());
|
|
exitCode = B.createStruct(moduleLoc, retType, exitCode);
|
|
SILValue exitCall = B.createFunctionRef(moduleLoc, exitSILFunc);
|
|
B.createApply(moduleLoc, exitCall, {}, {exitCode});
|
|
B.createUnreachable(moduleLoc);
|
|
}
|
|
|
|
if (mainFunc->hasThrows()) {
|
|
auto *successBlock = createBasicBlock();
|
|
B.setInsertionPoint(successBlock);
|
|
successBlock->createPhiArgument(SGM.Types.getEmptyTupleType(),
|
|
OwnershipKind::None);
|
|
SILValue zeroReturnValue =
|
|
B.createIntegerLiteral(moduleLoc, builtinInt32Type, 0);
|
|
B.createBranch(moduleLoc, exitBlock, {zeroReturnValue});
|
|
|
|
auto *failureBlock = createBasicBlock();
|
|
B.setInsertionPoint(failureBlock);
|
|
SILValue error = failureBlock->createPhiArgument(
|
|
SILType::getExceptionType(getASTContext()), OwnershipKind::Owned);
|
|
// Log the error.
|
|
B.createBuiltin(moduleLoc, getASTContext().getIdentifier("errorInMain"),
|
|
SGM.Types.getEmptyTupleType(), {}, {error});
|
|
B.createEndLifetime(moduleLoc, error);
|
|
SILValue oneReturnValue =
|
|
B.createIntegerLiteral(moduleLoc, builtinInt32Type, 1);
|
|
B.createBranch(moduleLoc, exitBlock, {oneReturnValue});
|
|
|
|
B.setInsertionPoint(entryBlock);
|
|
B.createTryApply(moduleLoc, mainFunctionRef, SubstitutionMap(),
|
|
{metatype}, successBlock, failureBlock);
|
|
} else {
|
|
B.setInsertionPoint(entryBlock);
|
|
B.createApply(moduleLoc, mainFunctionRef, SubstitutionMap(), {metatype});
|
|
SILValue returnValue =
|
|
B.createIntegerLiteral(moduleLoc, builtinInt32Type, 0);
|
|
B.createBranch(moduleLoc, exitBlock, {returnValue});
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SILGenFunction::emitAsyncMainThreadStart(SILDeclRef entryPoint) {
|
|
auto moduleLoc = entryPoint.getAsRegularLocation();
|
|
auto *entryBlock = B.getInsertionBB();
|
|
auto paramTypeIter = F.getConventions()
|
|
.getParameterSILTypes(getTypeExpansionContext())
|
|
.begin();
|
|
|
|
entryBlock->createFunctionArgument(*paramTypeIter); // argc
|
|
entryBlock->createFunctionArgument(*std::next(paramTypeIter)); // argv
|
|
|
|
// Lookup necessary functions
|
|
swift::ASTContext &ctx = entryPoint.getASTContext();
|
|
|
|
B.setInsertionPoint(entryBlock);
|
|
|
|
auto wrapCallArgs = [this, &moduleLoc](SILValue originalValue, FuncDecl *fd,
|
|
uint32_t paramIndex) -> SILValue {
|
|
Type parameterType = fd->getParameters()->get(paramIndex)->getType();
|
|
SILType paramSILType = SILType::getPrimitiveObjectType(parameterType->getCanonicalType());
|
|
// If the types are the same, we don't need to do anything!
|
|
if (paramSILType == originalValue->getType())
|
|
return originalValue;
|
|
return this->B.createStruct(moduleLoc, paramSILType, originalValue);
|
|
};
|
|
|
|
// Call CreateAsyncTask
|
|
FuncDecl *builtinDecl = cast<FuncDecl>(getBuiltinValueDecl(
|
|
ctx,
|
|
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::CreateAsyncTask))));
|
|
auto subs = SubstitutionMap::get(builtinDecl->getGenericSignature(),
|
|
{TupleType::getEmpty(ctx)},
|
|
ArrayRef<ProtocolConformanceRef>{});
|
|
|
|
SILValue mainFunctionRef = emitGlobalFunctionRef(moduleLoc, entryPoint);
|
|
|
|
// Emit the CreateAsyncTask builtin
|
|
TaskCreateFlags taskCreationFlagMask(0);
|
|
taskCreationFlagMask.setInheritContext(true);
|
|
SILValue taskFlags =
|
|
emitWrapIntegerLiteral(moduleLoc, getLoweredType(ctx.getIntType()),
|
|
taskCreationFlagMask.getOpaqueValue());
|
|
|
|
SILValue task =
|
|
emitBuiltinCreateAsyncTask(*this, moduleLoc, subs,
|
|
{ManagedValue::forUnmanaged(taskFlags),
|
|
ManagedValue::forUnmanaged(mainFunctionRef)},
|
|
{})
|
|
.forward(*this);
|
|
DestructureTupleInst *structure = B.createDestructureTuple(moduleLoc, task);
|
|
task = structure->getResult(0);
|
|
|
|
// Get swiftJobRun
|
|
FuncDecl *swiftJobRunFuncDecl = SGM.getSwiftJobRun();
|
|
assert(swiftJobRunFuncDecl && "Failed to find swift_job_run function decl");
|
|
SILFunction *swiftJobRunSILFunc =
|
|
SGM.getFunction(SILDeclRef(swiftJobRunFuncDecl, SILDeclRef::Kind::Func),
|
|
NotForDefinition);
|
|
SILValue swiftJobRunFunc =
|
|
B.createFunctionRefFor(moduleLoc, swiftJobRunSILFunc);
|
|
|
|
// Convert task to job
|
|
SILType JobType = SILType::getPrimitiveObjectType(
|
|
getBuiltinType(ctx, "Job")->getCanonicalType());
|
|
SILValue jobResult = B.createBuiltin(
|
|
moduleLoc,
|
|
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::ConvertTaskToJob)),
|
|
JobType, {}, {task});
|
|
jobResult = wrapCallArgs(jobResult, swiftJobRunFuncDecl, 0);
|
|
|
|
ModuleDecl * moduleDecl = entryPoint.getModuleContext();
|
|
|
|
SILValue mainExecutor = emitMainExecutor(moduleLoc);
|
|
mainExecutor = wrapCallArgs(mainExecutor, swiftJobRunFuncDecl, 1);
|
|
|
|
// Run first part synchronously
|
|
B.createApply(moduleLoc, swiftJobRunFunc, {}, {jobResult, mainExecutor});
|
|
|
|
// Start Main loop!
|
|
FuncDecl *drainQueueFuncDecl = SGM.getAsyncMainDrainQueue();
|
|
if (!drainQueueFuncDecl) {
|
|
// If it doesn't exist, we can conjure one up instead of crashing
|
|
// @available(SwiftStdlib 5.5, *)
|
|
// @_silgen_name("swift_task_asyncMainDrainQueue")
|
|
// internal func _asyncMainDrainQueue() -> Never
|
|
ParameterList *emptyParams = ParameterList::createEmpty(getASTContext());
|
|
drainQueueFuncDecl = FuncDecl::createImplicit(
|
|
getASTContext(), StaticSpellingKind::None,
|
|
DeclName(
|
|
getASTContext(),
|
|
DeclBaseName(getASTContext().getIdentifier("_asyncMainDrainQueue")),
|
|
/*Arguments*/ emptyParams),
|
|
{}, /*async*/ false, /*throws*/ false, {}, emptyParams,
|
|
getASTContext().getNeverType(), moduleDecl);
|
|
drainQueueFuncDecl->getAttrs().add(new (getASTContext()) SILGenNameAttr(
|
|
"swift_task_asyncMainDrainQueue", /*implicit*/ true));
|
|
}
|
|
|
|
SILFunction *drainQueueSILFunc = SGM.getFunction(
|
|
SILDeclRef(drainQueueFuncDecl, SILDeclRef::Kind::Func), NotForDefinition);
|
|
SILValue drainQueueFunc =
|
|
B.createFunctionRefFor(moduleLoc, drainQueueSILFunc);
|
|
B.createApply(moduleLoc, drainQueueFunc, {}, {});
|
|
B.createUnreachable(moduleLoc);
|
|
return;
|
|
}
|
|
|
|
void SILGenFunction::emitGeneratorFunction(SILDeclRef function, Expr *value,
|
|
bool EmitProfilerIncrement) {
|
|
auto *const topLevelValue = value;
|
|
auto *dc = function.getDecl()->getInnermostDeclContext();
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(function);
|
|
|
|
RegularLocation Loc(value);
|
|
Loc.markAutoGenerated();
|
|
|
|
// If a default argument or stored property initializer value is a noescape
|
|
// function type, strip the escape to noescape function conversion.
|
|
if (function.kind == SILDeclRef::Kind::DefaultArgGenerator ||
|
|
function.kind == SILDeclRef::Kind::StoredPropertyInitializer) {
|
|
if (auto funType = value->getType()->getAs<AnyFunctionType>()) {
|
|
if (funType->getExtInfo().isNoEscape()) {
|
|
auto conv = cast<FunctionConversionExpr>(value);
|
|
value = conv->getSubExpr();
|
|
assert(funType->withExtInfo(funType->getExtInfo().withNoEscape(false))
|
|
->isEqual(value->getType()));
|
|
}
|
|
}
|
|
}
|
|
|
|
// For a property wrapper backing initializer, form a parameter list
|
|
// containing the wrapped or projected value.
|
|
ParameterList *params = nullptr;
|
|
if (function.kind == SILDeclRef::Kind::PropertyWrapperBackingInitializer ||
|
|
function.kind == SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue) {
|
|
auto &ctx = getASTContext();
|
|
auto param = new (ctx) ParamDecl(SourceLoc(), SourceLoc(),
|
|
ctx.getIdentifier("$input_value"),
|
|
SourceLoc(),
|
|
ctx.getIdentifier("$input_value"),
|
|
dc);
|
|
param->setSpecifier(ParamSpecifier::LegacyOwned);
|
|
param->setImplicit();
|
|
auto vd = cast<VarDecl>(function.getDecl());
|
|
if (function.kind == SILDeclRef::Kind::PropertyWrapperBackingInitializer) {
|
|
param->setInterfaceType(vd->getPropertyWrapperInitValueInterfaceType());
|
|
} else {
|
|
auto *placeholder =
|
|
vd->getPropertyWrapperInitializerInfo().getProjectedValuePlaceholder();
|
|
auto interfaceType = placeholder->getType();
|
|
if (interfaceType->hasArchetype())
|
|
interfaceType = interfaceType->mapTypeOutOfContext();
|
|
|
|
param->setInterfaceType(interfaceType);
|
|
}
|
|
|
|
params = ParameterList::create(ctx, SourceLoc(), {param}, SourceLoc());
|
|
} else if (function.kind == SILDeclRef::Kind::RuntimeAttributeGenerator) {
|
|
params = ParameterList::createEmpty(getASTContext());
|
|
}
|
|
|
|
auto captureInfo = SGM.M.Types.getLoweredLocalCaptures(function);
|
|
auto interfaceType = value->getType()->mapTypeOutOfContext();
|
|
emitProlog(captureInfo, params, /*selfParam=*/nullptr,
|
|
dc, interfaceType, /*throws=*/false, SourceLoc());
|
|
if (EmitProfilerIncrement) {
|
|
// Emit a profiler increment for the top-level value, not looking through
|
|
// any function conversions. This is necessary as the counter would have
|
|
// been recorded for this expression, not the sub-expression.
|
|
emitProfilerIncrement(topLevelValue);
|
|
}
|
|
prepareEpilog(interfaceType, false, CleanupLocation(Loc));
|
|
|
|
{
|
|
llvm::Optional<SILGenFunction::OpaqueValueRAII> opaqueValue;
|
|
|
|
// For a property wrapper backing initializer, bind the opaque value used
|
|
// in the initializer expression to the given parameter.
|
|
if (function.kind == SILDeclRef::Kind::PropertyWrapperBackingInitializer) {
|
|
auto var = cast<VarDecl>(function.getDecl());
|
|
auto initInfo = var->getPropertyWrapperInitializerInfo();
|
|
auto param = params->get(0);
|
|
auto *placeholder = initInfo.getWrappedValuePlaceholder();
|
|
opaqueValue.emplace(
|
|
*this, placeholder->getOpaqueValuePlaceholder(),
|
|
maybeEmitValueOfLocalVarDecl(param, AccessKind::Read));
|
|
|
|
assert(value == initInfo.getInitFromWrappedValue());
|
|
} else if (function.kind == SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue) {
|
|
auto var = cast<VarDecl>(function.getDecl());
|
|
auto initInfo = var->getPropertyWrapperInitializerInfo();
|
|
auto param = params->get(0);
|
|
auto *placeholder = initInfo.getProjectedValuePlaceholder();
|
|
opaqueValue.emplace(
|
|
*this, placeholder->getOpaqueValuePlaceholder(),
|
|
maybeEmitValueOfLocalVarDecl(param, AccessKind::Read));
|
|
|
|
assert(value == initInfo.getInitFromProjectedValue());
|
|
}
|
|
|
|
emitReturnExpr(Loc, value);
|
|
}
|
|
|
|
emitEpilog(Loc);
|
|
mergeCleanupBlocks();
|
|
}
|
|
|
|
void SILGenFunction::emitGeneratorFunction(SILDeclRef function, VarDecl *var) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(function);
|
|
|
|
RegularLocation loc(var);
|
|
loc.markAutoGenerated();
|
|
|
|
auto decl = function.getAbstractFunctionDecl();
|
|
auto *dc = decl->getInnermostDeclContext();
|
|
auto interfaceType = var->getValueInterfaceType();
|
|
|
|
// If this is the backing storage for a property with an attached
|
|
// wrapper that was initialized with '=', the stored property initializer
|
|
// will be in terms of the original property's type.
|
|
if (auto originalProperty = var->getOriginalWrappedProperty()) {
|
|
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType()) {
|
|
interfaceType = originalProperty->getPropertyWrapperInitValueInterfaceType();
|
|
|
|
if (auto fnType = interfaceType->getAs<AnyFunctionType>()) {
|
|
auto newExtInfo = fnType->getExtInfo().withNoEscape(false);
|
|
interfaceType = fnType->withExtInfo(newExtInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
emitBasicProlog(/*paramList*/ nullptr, /*selfParam*/ nullptr,
|
|
interfaceType, dc, /*throws=*/ false,SourceLoc(),
|
|
/*ignored parameters*/ 0);
|
|
prepareEpilog(interfaceType, false, CleanupLocation(loc));
|
|
|
|
auto pbd = var->getParentPatternBinding();
|
|
const auto i = pbd->getPatternEntryIndexForVarDecl(var);
|
|
auto *anchorVar = pbd->getAnchoringVarDecl(i);
|
|
auto subs = getForwardingSubstitutionMap();
|
|
auto contextualType = dc->mapTypeIntoContext(interfaceType);
|
|
auto resultType = contextualType->getCanonicalType();
|
|
auto origResultType = AbstractionPattern(resultType);
|
|
|
|
SmallVector<SILValue, 4> directResults;
|
|
|
|
if (F.getConventions().hasIndirectSILResults()) {
|
|
Scope scope(Cleanups, CleanupLocation(var));
|
|
|
|
SmallVector<CleanupHandle, 4> cleanups;
|
|
auto init = prepareIndirectResultInit(loc, AbstractionPattern(resultType),
|
|
resultType, directResults, cleanups);
|
|
|
|
emitApplyOfStoredPropertyInitializer(loc, anchorVar, subs, resultType,
|
|
origResultType,
|
|
SGFContext(init.get()));
|
|
|
|
for (auto cleanup : cleanups) {
|
|
Cleanups.forwardCleanup(cleanup);
|
|
}
|
|
} else {
|
|
Scope scope(Cleanups, CleanupLocation(var));
|
|
|
|
// If we have no indirect results, just return the result.
|
|
auto result = emitApplyOfStoredPropertyInitializer(loc, anchorVar, subs,
|
|
resultType,
|
|
origResultType,
|
|
SGFContext())
|
|
.ensurePlusOne(*this, loc);
|
|
std::move(result).forwardAll(*this, directResults);
|
|
}
|
|
|
|
Cleanups.emitBranchAndCleanups(ReturnDest, loc, directResults);
|
|
emitEpilog(loc);
|
|
}
|
|
|
|
void SILGenFunction::emitGeneratorFunction(
|
|
SILDeclRef function, Type resultInterfaceType, BraceStmt *body,
|
|
Optional<AbstractionPattern> pattern) {
|
|
MagicFunctionName = SILGenModule::getMagicFunctionName(function);
|
|
|
|
RegularLocation loc(function.getDecl());
|
|
loc.markAutoGenerated();
|
|
|
|
auto *dc = function.getDecl()->getInnermostDeclContext();
|
|
auto captureInfo = SGM.M.Types.getLoweredLocalCaptures(function);
|
|
emitProlog(captureInfo, ParameterList::createEmpty(getASTContext()),
|
|
/*selfParam=*/nullptr, dc, resultInterfaceType, /*throws=*/false,
|
|
SourceLoc(), pattern);
|
|
|
|
prepareEpilog(resultInterfaceType, /*hasThrows=*/false, CleanupLocation(loc));
|
|
|
|
emitStmt(body);
|
|
|
|
emitEpilog(loc);
|
|
mergeCleanupBlocks();
|
|
}
|
|
|
|
Initialization *SILGenFunction::getSingleValueStmtInit(Expr *E) {
|
|
if (SingleValueStmtInitStack.empty())
|
|
return nullptr;
|
|
|
|
// Check to see if this is an expression branch of an active
|
|
// SingleValueStmtExpr initialization.
|
|
if (!SingleValueStmtInitStack.back().Exprs.contains(E))
|
|
return nullptr;
|
|
|
|
return SingleValueStmtInitStack.back().Init;
|
|
}
|
|
|
|
void SILGenFunction::emitProfilerIncrement(ASTNode Node) {
|
|
emitProfilerIncrement(ProfileCounterRef::node(Node));
|
|
}
|
|
|
|
void SILGenFunction::emitProfilerIncrement(ProfileCounterRef Ref) {
|
|
// Ignore functions which aren't set up for instrumentation.
|
|
SILProfiler *SP = F.getProfiler();
|
|
if (!SP)
|
|
return;
|
|
if (!SP->hasRegionCounters() || !getModule().getOptions().UseProfile.empty())
|
|
return;
|
|
|
|
const auto &RegionCounterMap = SP->getRegionCounterMap();
|
|
auto CounterIt = RegionCounterMap.find(Ref);
|
|
|
|
assert(CounterIt != RegionCounterMap.end() &&
|
|
"cannot increment non-existent counter");
|
|
|
|
// If we're at an unreachable point, the increment can be elided as the
|
|
// counter cannot be incremented.
|
|
if (!B.hasValidInsertionPoint())
|
|
return;
|
|
|
|
B.createIncrementProfilerCounter(
|
|
Ref.getLocation(), CounterIt->second, SP->getPGOFuncName(),
|
|
SP->getNumRegionCounters(), SP->getPGOFuncHash());
|
|
}
|
|
|
|
ProfileCounter SILGenFunction::loadProfilerCount(ASTNode Node) const {
|
|
if (SILProfiler *SP = F.getProfiler())
|
|
return SP->getExecutionCount(Node);
|
|
return ProfileCounter();
|
|
}
|
|
|
|
Optional<ASTNode> SILGenFunction::getPGOParent(ASTNode Node) const {
|
|
if (SILProfiler *SP = F.getProfiler())
|
|
return SP->getPGOParent(Node);
|
|
return None;
|
|
}
|
|
|
|
SILValue SILGenFunction::emitUnwrapIntegerResult(SILLocation loc,
|
|
SILValue value) {
|
|
// This is a loop because we want to handle types that wrap integer types,
|
|
// like ObjCBool (which may be Bool or Int8).
|
|
while (!value->getType().is<BuiltinIntegerType>()) {
|
|
auto structDecl = value->getType().getStructOrBoundGenericStruct();
|
|
assert(structDecl && "value for error result wasn't of struct type!");
|
|
assert(structDecl->getStoredProperties().size() == 1);
|
|
auto property = structDecl->getStoredProperties()[0];
|
|
value = B.createStructExtract(loc, value, property);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
SILValue SILGenFunction::emitWrapIntegerLiteral(SILLocation loc,
|
|
SILType ty,
|
|
unsigned value) {
|
|
// Create a builtin integer literal value.
|
|
if (auto intTy = ty.getAs<BuiltinIntegerType>()) {
|
|
return B.createIntegerLiteral(loc, ty, value);
|
|
}
|
|
|
|
// Or wrap a value in a struct, potentially multiple times to handle types
|
|
// that wrap integer types like ObjCBool (which may be Bool or Int8).
|
|
auto structDecl = ty.getStructOrBoundGenericStruct();
|
|
assert(structDecl && "value for error result wasn't of struct type!");
|
|
assert(structDecl->getStoredProperties().size() == 1);
|
|
auto property = structDecl->getStoredProperties()[0];
|
|
auto propertyTy = ty.getFieldType(property, SGM.Types, getTypeExpansionContext());
|
|
auto propertyValue = emitWrapIntegerLiteral(loc, propertyTy, value);
|
|
return B.createStruct(loc, ty, propertyValue);
|
|
}
|