Files
swift-mirror/lib/SILGen/SILGen.cpp
Anthony Latsis bda6edb85c AST: Rename GenericContext::isGeneric to hasGenericParamList
`isGeneric` is a misleading name because this method checks for the
existence of a `GenericParamList`, which is not implied by genericity.
2025-11-11 15:55:16 +00:00

2403 lines
85 KiB
C++

//===--- SILGen.cpp - Implements Lowering of ASTs -> SIL ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "silgen"
#include "ManagedValue.h"
#include "RValue.h"
#include "SILGenFunction.h"
#include "SILGenFunctionBuilder.h"
#include "SILGenTopLevel.h"
#include "Scope.h"
#include "swift/AST/ConformanceLookup.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSIL.h"
#include "swift/AST/Evaluator.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/ResilienceExpansion.h"
#include "swift/AST/SILGenRequests.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Statistic.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/Frontend/Frontend.h"
#include "swift/SIL/PrettyStackTrace.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILDebugScope.h"
#include "swift/SIL/SILProfiler.h"
#include "swift/Serialization/SerializedModuleLoader.h"
#include "swift/Serialization/SerializedSILLoader.h"
#include "swift/Strings.h"
#include "swift/Subsystems.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/Debug.h"
using namespace swift;
using namespace Lowering;
llvm::cl::list<std::string> PrintFunctionAST(
"print-function-ast", llvm::cl::CommaSeparated,
llvm::cl::desc("Only print out the ast for this function"));
//===----------------------------------------------------------------------===//
// SILGenModule Class implementation
//===----------------------------------------------------------------------===//
SILGenModule::SILGenModule(SILModule &M, ModuleDecl *SM)
: M(M), Types(M.Types), SwiftModule(SM),
FileIDsByFilePath(SM->computeFileIDMap(/*shouldDiagnose=*/true)) {
const SILOptions &Opts = M.getOptions();
if (!Opts.UseProfile.empty()) {
// FIXME: Create file system to read the profile. In the future, the vfs
// needs to come from CompilerInstance.
auto FS = llvm::vfs::getRealFileSystem();
auto ReaderOrErr =
llvm::IndexedInstrProfReader::create(Opts.UseProfile, *FS);
if (auto E = ReaderOrErr.takeError()) {
diagnose(SourceLoc(), diag::profile_read_error, Opts.UseProfile,
llvm::toString(std::move(E)));
} else {
M.setPGOReader(std::move(ReaderOrErr.get()));
}
}
}
SILGenModule::~SILGenModule() {
// Update the linkage of external private functions to public_external,
// because there is no private_external linkage. External private functions
// can occur in the following cases:
//
// * private class methods which are referenced from the vtable of a derived
// class in a different file/module. Such private methods are always
// generated with public linkage in the other file/module.
//
// * in lldb: lldb can access private declarations in other files/modules
//
// * private functions with a @_silgen_name attribute but without a body
//
// * when compiling with -disable-access-control
//
for (SILFunction &f : M.getFunctionList()) {
if (f.getLinkage() == SILLinkage::Private && f.isExternalDeclaration())
f.setLinkage(SILLinkage::PublicExternal);
}
// Skip verification if a lazy typechecking error occurred.
auto &ctx = getASTContext();
if (ctx.TypeCheckerOpts.EnableLazyTypecheck && ctx.hadError())
return;
M.verifyIncompleteOSSA();
}
static SILDeclRef getBridgingFn(std::optional<SILDeclRef> &cacheSlot,
SILGenModule &SGM, Identifier moduleName,
StringRef functionName,
std::initializer_list<Type> inputTypes,
Type outputType) {
if (!cacheSlot) {
ASTContext &ctx = SGM.M.getASTContext();
ModuleDecl *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(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!");
}
// Check that the function takes the expected arguments and returns the
// expected result type.
SILDeclRef c(fd);
auto funcTy =
SGM.Types.getConstantFunctionType(TypeExpansionContext::minimal(), c);
SILFunctionConventions fnConv(funcTy, SGM.M);
auto toSILType = [&SGM](Type ty) {
return SGM.Types.getLoweredType(ty, TypeExpansionContext::minimal());
};
if (fnConv.hasIndirectSILResults() ||
funcTy->getNumParameters() != inputTypes.size() ||
!std::equal(
fnConv.getParameterSILTypes(TypeExpansionContext::minimal())
.begin(),
fnConv.getParameterSILTypes(TypeExpansionContext::minimal()).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 (fnConv.getSingleSILResultType(TypeExpansionContext::minimal()) !=
toSILType(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;
}
LLVM_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 EXISTENTIAL(X) getASTContext().get##X##ExistentialType()
#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, EXISTENTIAL, Error)
GET_BRIDGING_FN(Foundation, EXISTENTIAL, Error, REQUIRED, NSError)
GET_BRIDGING_FN(WinSDK, REQUIRED, Bool, REQUIRED, WindowsBool)
GET_BRIDGING_FN(WinSDK, REQUIRED, WindowsBool, REQUIRED, Bool)
#undef GET_BRIDGING_FN
#undef REQUIRED
#undef OPTIONAL
static FuncDecl *diagnoseMissingIntrinsic(SILGenModule &sgm,
SILLocation loc,
const char *name) {
sgm.diagnose(loc, diag::bridging_function_missing,
sgm.getASTContext().StdlibModuleName.str(), name);
return nullptr;
}
#define FUNC_DECL(NAME, ID) \
FuncDecl *SILGenModule::get##NAME(SILLocation loc) { \
if (auto fn = getASTContext().get##NAME()) \
return fn; \
return diagnoseMissingIntrinsic(*this, loc, ID); \
}
#include "swift/AST/KnownDecls.def"
#define KNOWN_SDK_FUNC_DECL(MODULE, NAME, ID) \
FuncDecl *SILGenModule::get##NAME(SILLocation loc) { \
if (getASTContext().getLoadedModule(getASTContext().Id_##MODULE)) { \
if (auto fn = getASTContext().get##NAME()) \
return fn; \
} \
return diagnoseMissingIntrinsic(*this, loc, ID); \
}
#include "swift/AST/KnownSDKDecls.def"
ProtocolDecl *SILGenModule::getObjectiveCBridgeable(SILLocation loc) {
if (ObjectiveCBridgeable)
return *ObjectiveCBridgeable;
// Find the _ObjectiveCBridgeable protocol.
auto &ctx = getASTContext();
auto proto = ctx.getProtocol(KnownProtocolKind::ObjectiveCBridgeable);
if (!proto)
diagnose(loc, diag::bridging_objcbridgeable_missing);
ObjectiveCBridgeable = proto;
return proto;
}
FuncDecl *SILGenModule::getBridgeToObjectiveCRequirement(SILLocation loc) {
if (BridgeToObjectiveCRequirement)
return *BridgeToObjectiveCRequirement;
// Find the _ObjectiveCBridgeable protocol.
auto proto = getObjectiveCBridgeable(loc);
if (!proto) {
BridgeToObjectiveCRequirement = nullptr;
return nullptr;
}
// Look for _bridgeToObjectiveC().
auto &ctx = getASTContext();
DeclName name(ctx, ctx.Id_bridgeToObjectiveC, llvm::ArrayRef<Identifier>());
auto *found = dyn_cast_or_null<FuncDecl>(
proto->getSingleRequirement(name));
if (!found)
diagnose(loc, diag::bridging_objcbridgeable_broken, name);
BridgeToObjectiveCRequirement = found;
return found;
}
FuncDecl *SILGenModule::getUnconditionallyBridgeFromObjectiveCRequirement(
SILLocation loc) {
if (UnconditionallyBridgeFromObjectiveCRequirement)
return *UnconditionallyBridgeFromObjectiveCRequirement;
// Find the _ObjectiveCBridgeable protocol.
auto proto = getObjectiveCBridgeable(loc);
if (!proto) {
UnconditionallyBridgeFromObjectiveCRequirement = nullptr;
return nullptr;
}
// Look for _bridgeToObjectiveC().
auto &ctx = getASTContext();
DeclName name(ctx, ctx.getIdentifier("_unconditionallyBridgeFromObjectiveC"),
llvm::ArrayRef(Identifier()));
auto *found = dyn_cast_or_null<FuncDecl>(
proto->getSingleRequirement(name));
if (!found)
diagnose(loc, diag::bridging_objcbridgeable_broken, name);
UnconditionallyBridgeFromObjectiveCRequirement = found;
return found;
}
AssociatedTypeDecl *
SILGenModule::getBridgedObjectiveCTypeRequirement(SILLocation loc) {
if (BridgedObjectiveCType)
return *BridgedObjectiveCType;
// Find the _ObjectiveCBridgeable protocol.
auto proto = getObjectiveCBridgeable(loc);
if (!proto) {
BridgeToObjectiveCRequirement = nullptr;
return nullptr;
}
// Look for _bridgeToObjectiveC().
auto &ctx = getASTContext();
auto *found = proto->getAssociatedType(ctx.Id_ObjectiveCType);
if (!found)
diagnose(loc, diag::bridging_objcbridgeable_broken, ctx.Id_ObjectiveCType);
BridgedObjectiveCType = found;
return found;
}
ProtocolConformance *
SILGenModule::getConformanceToObjectiveCBridgeable(SILLocation loc, Type type) {
auto proto = getObjectiveCBridgeable(loc);
if (!proto) return nullptr;
// Find the conformance to _ObjectiveCBridgeable.
auto result = lookupConformance(type, proto);
if (result.isInvalid())
return nullptr;
return result.getConcrete();
}
ProtocolDecl *SILGenModule::getBridgedStoredNSError(SILLocation loc) {
if (BridgedStoredNSError)
return *BridgedStoredNSError;
// Find the _BridgedStoredNSError protocol.
auto &ctx = getASTContext();
auto proto = ctx.getProtocol(KnownProtocolKind::BridgedStoredNSError);
BridgedStoredNSError = proto;
return proto;
}
VarDecl *SILGenModule::getNSErrorRequirement(SILLocation loc) {
if (NSErrorRequirement)
return *NSErrorRequirement;
// Find the _BridgedStoredNSError protocol.
auto proto = getBridgedStoredNSError(loc);
if (!proto) {
NSErrorRequirement = nullptr;
return nullptr;
}
// Look for _nsError.
auto &ctx = getASTContext();
auto *found = dyn_cast_or_null<VarDecl>(
proto->getSingleRequirement(ctx.Id_nsError));
NSErrorRequirement = found;
return found;
}
ProtocolConformanceRef
SILGenModule::getConformanceToBridgedStoredNSError(SILLocation loc, Type type) {
auto proto = getBridgedStoredNSError(loc);
if (!proto)
return ProtocolConformanceRef::forInvalid();
// Find the conformance to _BridgedStoredNSError.
return lookupConformance(type, proto);
}
static FuncDecl *lookupConcurrencyIntrinsic(ASTContext &C, StringRef name) {
auto *module = C.getLoadedModule(C.Id_Concurrency);
if (!module)
return nullptr;
return evaluateOrDefault(
C.evaluator, LookupIntrinsicRequest{module, C.getIdentifier(name)},
/*default=*/nullptr);
}
FuncDecl *SILGenModule::getAsyncLetGet() {
return lookupConcurrencyIntrinsic(getASTContext(), "_asyncLet_get");
}
FuncDecl *SILGenModule::getAsyncLetGetThrowing() {
return lookupConcurrencyIntrinsic(getASTContext(), "_asyncLet_get_throwing");
}
FuncDecl *SILGenModule::getTaskFutureGet() {
return lookupConcurrencyIntrinsic(getASTContext(), "_taskFutureGet");
}
FuncDecl *SILGenModule::getTaskFutureGetThrowing() {
return lookupConcurrencyIntrinsic(getASTContext(), "_taskFutureGetThrowing");
}
FuncDecl *SILGenModule::getResumeUnsafeContinuation() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_resumeUnsafeContinuation");
}
FuncDecl *SILGenModule::getResumeUnsafeThrowingContinuation() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_resumeUnsafeThrowingContinuation");
}
FuncDecl *SILGenModule::getResumeUnsafeThrowingContinuationWithError() {
return lookupConcurrencyIntrinsic(
getASTContext(), "_resumeUnsafeThrowingContinuationWithError");
}
FuncDecl *SILGenModule::getRunTaskForBridgedAsyncMethod() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_runTaskForBridgedAsyncMethod");
}
FuncDecl *SILGenModule::getCheckExpectedExecutor() {
return lookupConcurrencyIntrinsic(getASTContext(), "_checkExpectedExecutor");
}
FuncDecl *SILGenModule::getCreateCheckedContinuation() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_createCheckedContinuation");
}
FuncDecl *SILGenModule::getCreateCheckedThrowingContinuation() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_createCheckedThrowingContinuation");
}
FuncDecl *SILGenModule::getResumeCheckedContinuation() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_resumeCheckedContinuation");
}
FuncDecl *SILGenModule::getResumeCheckedThrowingContinuation() {
return lookupConcurrencyIntrinsic(getASTContext(),
"_resumeCheckedThrowingContinuation");
}
FuncDecl *SILGenModule::getResumeCheckedThrowingContinuationWithError() {
return lookupConcurrencyIntrinsic(
getASTContext(), "_resumeCheckedThrowingContinuationWithError");
}
FuncDecl *SILGenModule::getAsyncMainDrainQueue() {
return lookupConcurrencyIntrinsic(getASTContext(), "_asyncMainDrainQueue");
}
FuncDecl *SILGenModule::getSwiftJobRun() {
return lookupConcurrencyIntrinsic(getASTContext(), "_swiftJobRun");
}
FuncDecl *SILGenModule::getDeinitOnExecutor() {
return lookupConcurrencyIntrinsic(getASTContext(), "_deinitOnExecutor");
}
FuncDecl *SILGenModule::getDeinitOnExecutorMainActorBackDeploy() {
auto found = lookupConcurrencyIntrinsic(getASTContext(),
"_deinitOnExecutorMainActorBackDeploy");
if (found)
return found;
return getDeinitOnExecutor();
}
FuncDecl *SILGenModule::getCreateExecutors() {
return lookupConcurrencyIntrinsic(getASTContext(), "_createExecutors");
}
FuncDecl *SILGenModule::getExit() {
ASTContext &C = getASTContext();
// Try the most likely modules.
Identifier mostLikelyIdentifier;
const llvm::Triple &triple = C.LangOpts.Target;
if (triple.isOSDarwin()) {
mostLikelyIdentifier = C.getIdentifier("Darwin");
} else if (triple.isOSWASI()) {
mostLikelyIdentifier = C.getIdentifier("SwiftWASILibc");
} else if (triple.isWindowsMSVCEnvironment()) {
mostLikelyIdentifier = C.getIdentifier("ucrt");
} else {
mostLikelyIdentifier = C.getIdentifier("SwiftGlibc");
}
ModuleDecl *exitModule = C.getModuleByIdentifier(mostLikelyIdentifier);
FuncDecl *exitFunction = nullptr;
if (exitModule) {
exitFunction = evaluateOrDefault(
C.evaluator,
LookupIntrinsicRequest{exitModule, C.getIdentifier("exit")},
/*default=*/nullptr);
}
if (!exitFunction) {
// No go, look for it in any loaded module. Several of the internal
// Swift modules or swift-corelibs modules may have absorbed <stdlib.h>
// when buliding without fully specified clang modules in the OS/SDK.
for (const auto &loadedModuleVector : C.getLoadedModules()) {
if (loadedModuleVector.first == mostLikelyIdentifier) {
continue;
}
ModuleDecl *loadedModule = loadedModuleVector.second;
if (loadedModule) {
exitFunction = evaluateOrDefault(
C.evaluator,
LookupIntrinsicRequest{loadedModule, C.getIdentifier("exit")},
/*default=*/nullptr);
}
if (exitFunction) {
break;
}
}
}
return exitFunction;
}
Type SILGenModule::getConfiguredExecutorFactory() {
auto &ctx = getASTContext();
// First look in the @main struct, if any
NominalTypeDecl *mainType = ctx.MainModule->getMainTypeDecl();
if (mainType) {
SmallVector<ValueDecl *, 1> decls;
auto identifier = ctx.getIdentifier("DefaultExecutorFactory");
mainType->lookupQualified(mainType,
DeclNameRef(identifier),
SourceLoc(),
NL_RemoveNonVisible | NL_RemoveOverridden
| NL_OnlyTypes | NL_ProtocolMembers,
decls);
for (auto decl : decls) {
TypeDecl *typeDecl = dyn_cast<TypeDecl>(decl);
if (typeDecl) {
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(typeDecl)) {
return nominalDecl->getDeclaredType();
}
if (isa<AssociatedTypeDecl>(typeDecl)) {
// We ignore associatedtype declarations; those with a default will
// turn into a `typealias` instead.
continue;
}
return typeDecl->getDeclaredInterfaceType();
}
}
}
// Failing that, look at the top level
Type factory = ctx.getNamedSwiftType(ctx.MainModule, "DefaultExecutorFactory");
// If we don't find it, fall back to _Concurrency.PlatformExecutorFactory
if (!factory)
factory = getDefaultExecutorFactory();
return factory;
}
Type SILGenModule::getDefaultExecutorFactory() {
auto &ctx = getASTContext();
ModuleDecl *module = ctx.getModuleByIdentifier(ctx.Id_Concurrency);
if (!module)
return Type();
return ctx.getNamedSwiftType(module, "DefaultExecutorFactory");
}
ProtocolConformance *SILGenModule::getNSErrorConformanceToError() {
if (NSErrorConformanceToError)
return *NSErrorConformanceToError;
auto &ctx = getASTContext();
auto nsErrorTy = ctx.getNSErrorType();
if (!nsErrorTy) {
NSErrorConformanceToError = nullptr;
return nullptr;
}
auto error = ctx.getErrorDecl();
if (!error) {
NSErrorConformanceToError = nullptr;
return nullptr;
}
auto conformance = lookupConformance(nsErrorTy, cast<ProtocolDecl>(error));
if (conformance.isConcrete())
NSErrorConformanceToError = conformance.getConcrete();
else
NSErrorConformanceToError = nullptr;
return *NSErrorConformanceToError;
}
SILFunction *
SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess,
KeyPathTypeKind typeKind) {
bool isBaseInout;
bool isResultInout;
StringRef functionName;
NominalTypeDecl *keyPathDecl;
if (isReadAccess) {
assert(typeKind == KPTK_KeyPath ||
typeKind == KPTK_WritableKeyPath ||
typeKind == KPTK_ReferenceWritableKeyPath);
functionName = "swift_readAtKeyPath";
isBaseInout = false;
isResultInout = false;
keyPathDecl = getASTContext().getKeyPathDecl();
} else if (typeKind == KPTK_WritableKeyPath) {
functionName = "swift_modifyAtWritableKeyPath";
isBaseInout = true;
isResultInout = true;
keyPathDecl = getASTContext().getWritableKeyPathDecl();
} else if (typeKind == KPTK_ReferenceWritableKeyPath) {
functionName = "swift_modifyAtReferenceWritableKeyPath";
isBaseInout = false;
isResultInout = true;
keyPathDecl = getASTContext().getReferenceWritableKeyPathDecl();
} else {
llvm_unreachable("bad combination");
}
auto fn = M.lookUpFunction(functionName);
if (fn) return fn;
auto sig = keyPathDecl->getGenericSignature().getCanonicalSignature();
auto rootType = sig.getGenericParams()[0]->getCanonicalType();
auto valueType = sig.getGenericParams()[1]->getCanonicalType();
auto keyPathTy = BoundGenericType::get(keyPathDecl, Type(),
{ rootType, valueType })
->getCanonicalType();
// (@in_guaranteed/@inout Root, @guaranteed KeyPath<Root, Value>)
SILParameterInfo params[] = {
{ rootType,
isBaseInout ? ParameterConvention::Indirect_Inout
: ParameterConvention::Indirect_In_Guaranteed },
{ keyPathTy, ParameterConvention::Direct_Guaranteed },
};
// -> @yields @in_guaranteed/@inout Value
SILYieldInfo yields[] = {
{ valueType,
isResultInout ? ParameterConvention::Indirect_Inout
: ParameterConvention::Indirect_In_Guaranteed },
};
auto extInfo = SILFunctionType::ExtInfo::getThin();
auto functionTy = SILFunctionType::get(sig, extInfo,
SILCoroutineKind::YieldOnce,
ParameterConvention::Direct_Unowned,
params,
yields,
/*results*/ {},
/*error result*/ {},
SubstitutionMap(),
SubstitutionMap(),
getASTContext());
auto env = sig.getGenericEnvironment();
SILGenFunctionBuilder builder(*this);
fn = builder.createFunction(
SILLinkage::PublicExternal, functionName, functionTy, env,
/*location*/ std::nullopt, IsNotBare, IsNotTransparent, IsNotSerialized,
IsNotDynamic, IsNotDistributed, IsNotRuntimeAccessible);
return fn;
}
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));
}
}
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;
} else {
break;
}
}
// If the decl ref is nil, just insert at the beginning.
return nullptr;
}
static bool shouldEmitFunctionBody(const AbstractFunctionDecl *AFD) {
if (!AFD->hasBody())
return false;
if (AFD->isBodySkipped())
return false;
auto &ctx = AFD->getASTContext();
if (ctx.TypeCheckerOpts.EnableLazyTypecheck || AFD->isInMacroExpansionFromClangHeader()) {
// Force the function body to be type-checked and then skip it if there
// have been any errors. Normally macro expansions are type checked in the module they
// expand in - this does not apply to swift macros applied to nodes imported from clang,
// so force type checking of them here if they haven't already, to prevent crashing.
(void)AFD->getTypecheckedBody();
// FIXME: Only skip bodies that contain type checking errors.
// It would be ideal to only skip the function body if it is specifically
// the source of an error. However, that information isn't available today
// so instead we avoid emitting all function bodies as soon as any error is
// encountered.
if (ctx.hadError())
return false;
}
return true;
}
static bool isEmittedOnDemand(SILModule &M, SILDeclRef constant) {
if (!constant.hasDecl())
return false;
if (constant.isForeign)
return false;
auto *d = constant.getDecl();
auto *dc = d->getDeclContext();
switch (constant.kind) {
case SILDeclRef::Kind::Func: {
auto *fd = cast<FuncDecl>(d);
if (!shouldEmitFunctionBody(fd))
return false;
if (isa<ClangModuleUnit>(dc->getModuleScopeContext()))
return true;
if (fd->hasForcedStaticDispatch())
return true;
break;
}
case SILDeclRef::Kind::Allocator: {
auto *cd = cast<ConstructorDecl>(d);
// For factories, we don't need to emit a special thunk; the normal
// foreign-to-native thunk is sufficient.
if (isa<ClangModuleUnit>(dc->getModuleScopeContext()) &&
!cd->isFactoryInit() &&
(dc->getSelfClassDecl() || shouldEmitFunctionBody(cd)))
return true;
break;
}
case SILDeclRef::Kind::EnumElement:
return true;
case SILDeclRef::Kind::DefaultArgGenerator: {
// Default arguments of C++ functions are only emitted if used.
if (isa<ClangModuleUnit>(dc->getModuleScopeContext()))
return true;
break;
}
default:
break;
}
return false;
}
SILFunction *SILGenModule::getFunction(SILDeclRef constant,
ForDefinition_t forDefinition) {
// If we already emitted the function, return it.
if (auto emitted = getEmittedFunction(constant, forDefinition))
return emitted;
auto getBestLocation = [](SILDeclRef ref) -> SILLocation {
if (ref.hasDecl())
return ref.getDecl();
if (ref.loc.isNull())
return {(Decl *)nullptr};
if (auto *ace = ref.getAbstractClosureExpr())
return {ace};
return {(Decl *)nullptr};
};
// Note: Do not provide any SILLocation. You can set it afterwards.
SILGenFunctionBuilder builder(*this);
auto &IGM = *this;
auto *F = builder.getOrCreateFunction(
getBestLocation(constant), constant, forDefinition,
[&IGM](SILLocation loc, SILDeclRef constant) -> SILFunction * {
return IGM.getFunction(constant, NotForDefinition);
});
F->setDeclRef(constant);
F->setActorIsolation(constant.getActorIsolation());
assert(F && "SILFunction should have been defined");
emittedFunctions[constant] = F;
auto foundDelayed = delayedFunctions.find(constant);
if (foundDelayed == delayedFunctions.end()) {
if (isEmittedOnDemand(M, constant)) {
if (forcedFunctions.insert(constant).second)
pendingForcedFunctions.push_back(constant);
return F;
}
}
// If we delayed emitting this function previously, we need it now.
if (foundDelayed != delayedFunctions.end()) {
// Move the function to its proper place within the module.
M.functions.remove(F);
SILFunction *insertAfter = getFunctionToInsertAfter(*this,
foundDelayed->second);
if (!insertAfter) {
M.functions.push_front(F);
} else {
M.functions.insertAfter(insertAfter->getIterator(), F);
}
if (forcedFunctions.insert(constant).second)
pendingForcedFunctions.push_back(constant);
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);
}
bool SILGenModule::shouldSkipDecl(Decl *D) {
if (!D->isAvailableDuringLowering())
return true;
if (!getASTContext().SILOpts.SkipNonExportableDecls)
return false;
// Declarations nested in functions should be emitted whenever the function
// containing them should also be emitted.
if (auto funcContext = D->getDeclContext()->getOutermostFunctionContext())
return shouldSkipDecl(funcContext->getAsDecl());
if (D->isExposedToClients())
return false;
return true;
}
void SILGenModule::visit(Decl *D) {
if (shouldSkipDecl(D))
return;
ASTVisitor::visit(D);
}
static bool isInPrintFunctionList(AbstractFunctionDecl *fd) {
if (PrintFunctionAST.empty()) {
return false;
}
auto fnName = SILDeclRef(fd).mangle();
for (const std::string &printFnName : PrintFunctionAST) {
if (printFnName == fnName)
return true;
if (!printFnName.empty() && printFnName[0] != '$' && !fnName.empty() &&
fnName[0] == '$' && printFnName == fnName.substr(1)) {
return true;
}
}
return false;
}
void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); }
void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {
if (!f->empty()) {
diagnose(constant.getAsRegularLocation(), diag::sil_function_redefinition,
f->getName());
if (f->hasLocation())
diagnose(f->getLocation(), diag::sil_function_redefinition_note);
return;
}
if (constant.isForeignToNativeThunk()) {
f->setThunk(IsThunk);
if (constant.asForeign().isClangGenerated())
f->setSerializedKind(IsSerialized);
auto loc = constant.getAsRegularLocation();
loc.markAutoGenerated();
auto *dc = loc.getAsDeclContext();
assert(dc);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitForeignToNativeThunk", f);
SILGenFunction(*this, *f, dc).emitForeignToNativeThunk(constant);
postEmitFunction(constant, f);
return;
}
if (constant.isNativeToForeignThunk()) {
auto loc = constant.getAsRegularLocation();
loc.markAutoGenerated();
auto *dc = loc.getAsDeclContext();
assert(dc);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f);
f->setBare(IsBare);
f->setThunk(IsThunk);
// If the native function is async, then the foreign entry point is not,
// so it needs to spawn a detached task in which to run the native
// implementation, so the actual thunk logic needs to go into a closure
// implementation function.
if (constant.hasAsync()) {
f = SILGenFunction(*this, *f, dc).emitNativeAsyncToForeignThunk(constant);
}
SILGenFunction(*this, *f, dc).emitNativeToForeignThunk(constant);
postEmitFunction(constant, f);
return;
}
if (constant.isDistributedThunk()) {
auto loc = constant.getAsRegularLocation();
loc.markAutoGenerated();
auto *dc = loc.getAsDeclContext();
assert(dc);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitDistributedThunk", f);
f->setBare(IsBare);
f->setThunk(IsThunk);
f->setIsDistributed();
assert(constant.isDistributedThunk());
SILGenFunction(*this, *f, constant.getFuncDecl())
.emitFunction(constant.getFuncDecl());
postEmitFunction(constant, f);
return;
}
if (constant.isBackDeploymentThunk()) {
auto loc = constant.getAsRegularLocation();
loc.markAutoGenerated();
auto *dc = loc.getAsDeclContext();
assert(dc);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitBackDeploymentThunk", f);
f->setBare(IsBare);
f->setThunk(IsBackDeployedThunk);
SILGenFunction(*this, *f, dc).emitBackDeploymentThunk(constant);
postEmitFunction(constant, f);
return;
}
switch (constant.kind) {
case SILDeclRef::Kind::Func: {
if (auto *ce = constant.getAbstractClosureExpr()) {
preEmitFunction(constant, f, ce);
PrettyStackTraceSILFunction X("silgen closureexpr", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, ce).emitClosure(ce);
postEmitFunction(constant, f);
break;
}
if (constant.isInitAccessor()) {
auto *accessor = cast<AccessorDecl>(constant.getDecl());
preEmitFunction(constant, f, accessor);
PrettyStackTraceSILFunction X("silgen init accessor", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, accessor).emitInitAccessor(accessor);
postEmitFunction(constant, f);
break;
}
auto *fd = cast<FuncDecl>(constant.getDecl());
preEmitFunction(constant, f, fd);
PrettyStackTraceSILFunction X("silgen emitFunction", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, fd).emitFunction(fd);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::Allocator: {
auto *decl = cast<ConstructorDecl>(constant.getDecl());
if (decl->getDeclContext()->getSelfClassDecl() &&
(decl->isDesignatedInit() ||
decl->isObjC())) {
preEmitFunction(constant, f, decl);
PrettyStackTraceSILFunction X("silgen emitClassConstructorAllocator", f);
SILGenFunction(*this, *f, decl).emitClassConstructorAllocator(decl);
postEmitFunction(constant, f);
} else {
preEmitFunction(constant, f, decl);
PrettyStackTraceSILFunction X("silgen emitValueConstructor", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, decl).emitValueConstructor(decl);
postEmitFunction(constant, f);
}
break;
}
case SILDeclRef::Kind::Initializer: {
auto *decl = cast<ConstructorDecl>(constant.getDecl());
assert(decl->getDeclContext()->getSelfClassDecl());
preEmitFunction(constant, f, decl);
PrettyStackTraceSILFunction X("silgen constructor initializer", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, decl).emitClassConstructorInitializer(decl);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::DefaultArgGenerator: {
auto *decl = constant.getDecl();
auto *param = getParameterAt(decl, constant.defaultArgIndex);
assert(param);
auto *initDC = param->getDefaultArgumentInitContext();
switch (param->getDefaultArgumentKind()) {
case DefaultArgumentKind::Normal: {
auto arg = param->getTypeCheckedDefaultExpr();
auto loc = RegularLocation::getAutoGeneratedLocation(arg);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen default arg initializer", f);
SILGenFunction SGF(*this, *f, initDC);
SGF.emitGeneratorFunction(constant, arg);
postEmitFunction(constant, f);
break;
}
case DefaultArgumentKind::StoredProperty: {
auto arg = param->getStoredProperty();
auto loc = RegularLocation::getAutoGeneratedLocation(arg);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen stored property initializer", f);
SILGenFunction SGF(*this, *f, initDC);
SGF.emitGeneratorFunction(constant, arg);
postEmitFunction(constant, f);
break;
}
default:
llvm_unreachable("Bad default argument kind");
}
break;
}
case SILDeclRef::Kind::StoredPropertyInitializer: {
auto *var = cast<VarDecl>(constant.getDecl());
auto *pbd = var->getParentPatternBinding();
unsigned idx = pbd->getPatternEntryIndexForVarDecl(var);
auto *initDC = pbd->getInitContext(idx);
auto *init = constant.getInitializationExpr();
assert(init);
auto *parentMod = f->getParentModule();
auto loc = RegularLocation::getAutoGeneratedLocation(init);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f);
f->createProfiler(constant);
SILGenFunction SGF(*this, *f, initDC);
SGF.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement=*/true);
postEmitFunction(constant, f);
// Ensure that the SIL function has a module associated with it. This
// ensures that SIL serializer serializes the module id for this function
// correctly. The parent module can be reset when the function's location is
// updated to the autogenerated location above.
if (!f->getParentModule())
f->setParentModule(parentMod);
break;
}
case SILDeclRef::Kind::PropertyWrapperBackingInitializer: {
auto *var = cast<VarDecl>(constant.getDecl());
auto loc = RegularLocation::getAutoGeneratedLocation(var);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X(
"silgen emitPropertyWrapperBackingInitializer", f);
auto *init = constant.getInitializationExpr();
assert(init);
f->createProfiler(constant);
auto varDC = var->getInnermostDeclContext();
SILGenFunction SGF(*this, *f, varDC);
SGF.emitGeneratorFunction(constant, init, /*EmitProfilerIncrement*/ true);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::PropertyWrappedFieldInitAccessor: {
auto *var = cast<VarDecl>(constant.getDecl());
auto loc = RegularLocation::getAutoGeneratedLocation(var);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen propertyWrappedFieldInitAccessor", f);
f->createProfiler(constant);
auto *init = constant.getInitializationExpr();
assert(init);
auto varDC = var->getInnermostDeclContext();
SILGenFunction SGF(*this, *f, varDC);
SGF.emitPropertyWrappedFieldInitAccessor(constant, init,
/*EmitProfilerIncrement*/ true);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue: {
auto *var = cast<VarDecl>(constant.getDecl());
auto loc = RegularLocation::getAutoGeneratedLocation(var);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X(
"silgen emitPropertyWrapperInitFromProjectedValue", f);
auto *init = constant.getInitializationExpr();
assert(init);
auto varDC = var->getInnermostDeclContext();
SILGenFunction SGF(*this, *f, varDC);
SGF.emitGeneratorFunction(constant, init);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::GlobalAccessor: {
auto *global = cast<VarDecl>(constant.getDecl());
auto found = delayedGlobals.find(global);
assert(found != delayedGlobals.end());
auto *onceToken = found->second.first;
auto *onceFunc = found->second.second;
auto loc = RegularLocation::getAutoGeneratedLocation(global);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitGlobalAccessor", f);
SILGenFunction(*this, *f, global->getDeclContext())
.emitGlobalAccessor(global, onceToken, onceFunc);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::EnumElement: {
auto *decl = cast<EnumElementDecl>(constant.getDecl());
auto loc = RegularLocation::getAutoGeneratedLocation(decl);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen enum constructor", f);
SILGenFunction(*this, *f, decl->getDeclContext()).emitEnumConstructor(decl);
postEmitFunction(constant, f);
break;
}
case SILDeclRef::Kind::Destroyer: {
auto *dd = cast<DestructorDecl>(constant.getDecl());
preEmitFunction(constant, f, dd);
PrettyStackTraceSILFunction X("silgen emitDestroyingDestructor", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, dd).emitDestroyingDestructor(dd);
postEmitFunction(constant, f);
return;
}
case SILDeclRef::Kind::IsolatedDeallocator: {
emitDeallocatorImpl(constant, f);
return;
}
case SILDeclRef::Kind::Deallocator: {
auto *dd = cast<DestructorDecl>(constant.getDecl());
if (needsIsolatingDestructor(dd)) {
auto loc = RegularLocation::getAutoGeneratedLocation(dd);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitIsolatingDestructor", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, dd).emitIsolatingDestructor(dd);
postEmitFunction(constant, f);
return;
}
emitDeallocatorImpl(constant, f);
return;
}
case SILDeclRef::Kind::IVarInitializer: {
auto *cd = cast<ClassDecl>(constant.getDecl());
auto loc = RegularLocation::getAutoGeneratedLocation(cd);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitDestructor ivar initializer", f);
SILGenFunction(*this, *f, cd).emitIVarInitializer(constant);
postEmitFunction(constant, f);
return;
}
case SILDeclRef::Kind::IVarDestroyer: {
auto *cd = cast<ClassDecl>(constant.getDecl());
auto loc = RegularLocation::getAutoGeneratedLocation(cd);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitDestructor ivar destroyer", f);
SILGenFunction(*this, *f, cd).emitIVarDestroyer(constant);
postEmitFunction(constant, f);
return;
}
case SILDeclRef::Kind::AsyncEntryPoint:
case SILDeclRef::Kind::EntryPoint: {
f->setBare(IsBare);
if (constant.hasFileUnit()) {
auto *File = constant.getFileUnit();
// In script mode
assert(isa<SourceFile>(File) && "Emitting entry-point of non source file?!");
auto *SF = cast<SourceFile>(File);
emitEntryPoint(SF, f);
return;
}
auto loc = constant.getAsRegularLocation();
preEmitFunction(constant, f, loc);
auto *decl = constant.getDecl();
auto *dc = decl->getDeclContext();
PrettyStackTraceSILFunction X("silgen emitArtificialTopLevel", f);
// In all cases, a constant.kind == EntryPoint indicates the main entrypoint
// to the program, @main.
// In the synchronous case, the decl is not async, so emitArtificialTopLevel
// emits the error unwrapping and call to MainType.$main() into @main.
//
// In the async case, emitAsyncMainThreadStart is responsible for generating
// the contents of @main. This wraps @async_main in a task, passes that task
// to swift_job_run to execute the first thunk, and starts the runloop to
// run any additional continuations. The kind is EntryPoint, and the decl is
// async.
// When the kind is 'AsyncMain', we are generating @async_main. In this
// case, emitArtificialTopLevel emits the code for calling MaintType.$main,
// unwrapping errors, and calling exit(0) into @async_main to run the
// user-specified main function.
if (constant.kind == SILDeclRef::Kind::EntryPoint && isa<FuncDecl>(decl) &&
static_cast<FuncDecl *>(decl)->hasAsync()) {
SILDeclRef mainEntryPoint = SILDeclRef::getAsyncMainDeclEntryPoint(decl);
SILGenFunction(*this, *f, dc).emitAsyncMainThreadStart(mainEntryPoint);
} else {
SILGenFunction(*this, *f, dc).emitArtificialTopLevel(decl);
}
postEmitFunction(constant, f);
return;
}
}
}
void SILGenModule::emitOrDelayFunction(SILDeclRef constant) {
assert(!constant.isThunk());
assert(!constant.isClangImported());
auto emitAfter = lastEmittedFunction;
// Implicit decls may be delayed if they can't be used externally.
auto linkage = constant.getLinkage(ForDefinition);;
bool mayDelay = !constant.shouldBeEmittedForDebugger() &&
!constant.hasUserWrittenCode() &&
!constant.isDynamicallyReplaceable() &&
!isPossiblyUsedExternally(linkage, M.isWholeModule());
if (!mayDelay) {
emitFunctionDefinition(constant, getFunction(constant, ForDefinition));
return;
}
// If the function is already forced then it was previously delayed and then
// referenced. We don't need to emit or delay it again.
if (forcedFunctions.contains(constant))
return;
if (auto *f = getEmittedFunction(constant, ForDefinition)) {
emitFunctionDefinition(constant, f);
return;
}
// This is a delayable function so remember how to emit it in case it gets
// referenced later.
delayedFunctions.insert({constant, emitAfter});
// 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.
lastEmittedFunction = constant;
}
void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
SILLocation Loc) {
assert(F->empty() && "already emitted function?!");
if (F->getLoweredFunctionType()->isPolymorphic()) {
auto [genericEnv, capturedEnvs, forwardingSubs]
= Types.getForwardingSubstitutionsForLowering(constant);
F->setGenericEnvironment(genericEnv, capturedEnvs, forwardingSubs);
}
// Create a debug scope for the function using astNode as source location.
F->setDebugScope(new (M) SILDebugScope(Loc, F));
// Initialize F with the constant we created for it.
F->setDeclRef(constant);
// Set our actor isolation.
F->setActorIsolation(constant.getActorIsolation());
// Closures automatically infer [manual_ownership] based on outermost func.
//
// We need to add this constraint _prior_ to emitting the closure's body,
// because the output from SILGen slightly differs because of this constraint
// when it comes to the CopyExpr and SILMoveOnlyWrappedType usage.
//
// If ManualOwnership ends up subsuming those prior mechanisms for an
// explicit-copy mode, we can move this somewhere else, like postEmitFunction.
//
// FIXME: maybe this should happen in SILFunctionBuilder::getOrCreateFunction
if (getASTContext().LangOpts.hasFeature(Feature::ManualOwnership))
if (auto *ace = constant.getAbstractClosureExpr())
if (auto *dc = ace->getOutermostFunctionContext())
if (auto *decl = dc->getAsDecl())
if (!decl->isImplicit() &&
!decl->getAttrs().hasAttribute<NoManualOwnershipAttr>())
F->setPerfConstraints(PerformanceConstraints::ManualOwnership);
LLVM_DEBUG(llvm::dbgs() << "lowering ";
F->printName(llvm::dbgs());
llvm::dbgs() << " : ";
F->getLoweredType().print(llvm::dbgs());
llvm::dbgs() << '\n';
if (auto *decl = Loc.getAsASTNode<ValueDecl>()) {
decl->dump(llvm::dbgs());
llvm::dbgs() << '\n';
} else if (auto *expr = Loc.getAsASTNode<Expr>()) {
expr->dump(llvm::dbgs());
llvm::dbgs() << "\n";
});
}
void SILGenModule::postEmitFunction(SILDeclRef constant,
SILFunction *F) {
emitLazyConformancesForFunction(F);
auto sig = Types.getGenericSignatureWithCapturedEnvironments(constant);
recontextualizeCapturedLocalArchetypes(F, sig);
assert(!F->isExternalDeclaration() && "did not emit any function body?!");
LLVM_DEBUG(llvm::dbgs() << "lowered sil:\n";
F->print(llvm::dbgs()));
F->verifyIncompleteOSSA();
emitDifferentiabilityWitnessesForFunction(constant, F);
}
void SILGenModule::emitDifferentiabilityWitnessesForFunction(
SILDeclRef constant, SILFunction *F) {
// Visit `@differentiable` attributes and generate SIL differentiability
// witnesses.
// Skip if the SILDeclRef is a:
// - Default argument generator function.
// - Thunk.
if (!constant.hasDecl() || !constant.getAbstractFunctionDecl())
return;
if (constant.kind == SILDeclRef::Kind::DefaultArgGenerator ||
constant.isThunk())
return;
auto *AFD = constant.getAbstractFunctionDecl();
auto emitWitnesses = [&](DeclAttributes &Attrs) {
for (auto *diffAttr : Attrs.getAttributes<DifferentiableAttr>()) {
assert((!F->getLoweredFunctionType()->getSubstGenericSignature() ||
diffAttr->getDerivativeGenericSignature()) &&
"Type-checking should resolve derivative generic signatures for "
"all original SIL functions with generic signatures");
auto *resultIndices =
autodiff::getFunctionSemanticResultIndices(AFD,
diffAttr->getParameterIndices());
auto witnessGenSig =
autodiff::getDifferentiabilityWitnessGenericSignature(
AFD->getGenericSignature(),
diffAttr->getDerivativeGenericSignature());
AutoDiffConfig config(diffAttr->getParameterIndices(), resultIndices,
witnessGenSig);
emitDifferentiabilityWitness(AFD, F, DifferentiabilityKind::Reverse,
config, /*jvp*/ nullptr,
/*vjp*/ nullptr, diffAttr);
}
};
if (auto *accessor = dyn_cast<AccessorDecl>(AFD))
if (accessor->isGetter())
emitWitnesses(accessor->getStorage()->getAttrs());
emitWitnesses(AFD->getAttrs());
}
void SILGenModule::emitDifferentiabilityWitness(
AbstractFunctionDecl *originalAFD, SILFunction *originalFunction,
DifferentiabilityKind diffKind, const AutoDiffConfig &config,
SILFunction *jvp, SILFunction *vjp, const DeclAttribute *attr) {
assert(isa<DifferentiableAttr>(attr) || isa<DerivativeAttr>(attr));
auto *origFnType = originalAFD->getInterfaceType()->castTo<AnyFunctionType>();
auto origSilFnType = originalFunction->getLoweredFunctionType();
auto *silParamIndices =
autodiff::getLoweredParameterIndices(config.parameterIndices, origFnType);
// NOTE(TF-893): Extending capacity is necessary when `origSilFnType` has
// parameters corresponding to captured variables. These parameters do not
// appear in the type of `origFnType`.
// TODO: If possible, change `autodiff::getLoweredParameterIndices` to
// take `CaptureInfo` into account.
if (origSilFnType->getNumParameters() > silParamIndices->getCapacity())
silParamIndices = silParamIndices->extendingCapacity(
getASTContext(), origSilFnType->getNumParameters());
// Get or create new SIL differentiability witness.
// Witness already exists when there are two `@derivative` attributes
// (registering JVP and VJP functions) for the same derivative function
// configuration.
// Witness JVP and VJP are set below.
AutoDiffConfig silConfig(silParamIndices, config.resultIndices,
config.derivativeGenericSignature);
SILDifferentiabilityWitnessKey key = {
originalFunction->getName(), diffKind, silConfig};
auto *diffWitness = M.lookUpDifferentiabilityWitness(key);
if (!diffWitness) {
// Differentiability witnesses have the same linkage as the original
// function, stripping external. For @_alwaysEmitIntoClient original
// functions, force PublicNonABI linkage of the differentiability witness so
// we can serialize it (the original function itself might be HiddenExternal
// in this case if we only have declaration without definition).
auto linkage =
originalFunction->markedAsAlwaysEmitIntoClient()
? SILLinkage::PublicNonABI
: stripExternalFromLinkage(originalFunction->getLinkage());
diffWitness = SILDifferentiabilityWitness::createDefinition(
M, linkage, originalFunction, diffKind, silConfig.parameterIndices,
silConfig.resultIndices, config.derivativeGenericSignature,
/*jvp*/ nullptr, /*vjp*/ nullptr,
/*isSerialized*/ hasPublicVisibility(linkage), attr);
}
// Set derivative function in differentiability witness.
auto setDerivativeInDifferentiabilityWitness =
[&](AutoDiffDerivativeFunctionKind kind, SILFunction *derivative) {
auto derivativeThunk = getOrCreateCustomDerivativeThunk(
originalAFD, originalFunction, derivative, silConfig, kind);
// Check for existing same derivative.
// TODO(TF-835): Remove condition below and simplify assertion to
// `!diffWitness->getDerivative(kind)` after `@derivative` attribute
// type-checking no longer generates implicit `@differentiable`
// attributes.
auto *existingDerivative = diffWitness->getDerivative(kind);
if (existingDerivative && existingDerivative == derivativeThunk)
return;
assert(!existingDerivative &&
"SIL differentiability witness already has a different existing "
"derivative");
diffWitness->setDerivative(kind, derivativeThunk);
};
if (jvp)
setDerivativeInDifferentiabilityWitness(AutoDiffDerivativeFunctionKind::JVP,
jvp);
if (vjp)
setDerivativeInDifferentiabilityWitness(AutoDiffDerivativeFunctionKind::VJP,
vjp);
}
void SILGenModule::emitAbstractFuncDecl(AbstractFunctionDecl *AFD) {
if (isInPrintFunctionList(AFD)) {
auto &out = llvm::errs();
AFD->dump(out);
}
// Emit default arguments and property wrapper initializers.
emitArgumentGenerators(AFD, AFD->getParameters());
ASSERT(ABIRoleInfo(AFD).providesAPI()
&& "emitAbstractFuncDecl() on ABI-only decl?");
// If the declaration is exported as a C function, emit its native-to-foreign
// thunk too, if it wasn't already forced.
if (auto cdeclAttr = AFD->getAttrs().getAttribute<CDeclAttr>()) {
if (cdeclAttr->Underscored) {
auto thunk = SILDeclRef(AFD).asForeign();
if (!hasFunction(thunk))
emitNativeToForeignThunk(thunk);
}
}
emitDistributedThunkForDecl(AFD);
if (AFD->isBackDeployed()) {
// Emit the fallback function that will be used when the original function
// is unavailable at runtime.
auto fallback = SILDeclRef(AFD).asBackDeploymentKind(
SILDeclRef::BackDeploymentKind::Fallback);
emitFunctionDefinition(fallback, getFunction(fallback, ForDefinition));
// Emit the thunk that either invokes the original function or the fallback
// function depending on the availability of the original.
auto thunk = SILDeclRef(AFD).asBackDeploymentKind(
SILDeclRef::BackDeploymentKind::Thunk);
emitBackDeploymentThunk(thunk);
}
// Emit differentiability witness for the function referenced in
// @derivative(of:) attribute registering current function as VJP / JVP.
// Differentiability witnesses for a function could originate either from its
// @differentiable attribute or from explicit @derivative(of:) attribute on
// the derivative. In the latter case the derivative itself might not be
// emitted, while original function is (e.g. original function is @inlineable,
// but derivative is @usableFromInline). Ensure the differentiability witness
// originating from @derivative(of:) is emitted even if we're not going to
// emit body of the derivative.
for (auto *derivAttr : AFD->getAttrs().getAttributes<DerivativeAttr>()) {
auto *f = getFunction(SILDeclRef(AFD), NotForDefinition);
SILFunction *jvp = nullptr, *vjp = nullptr;
switch (derivAttr->getDerivativeKind()) {
case AutoDiffDerivativeFunctionKind::JVP:
jvp = f;
break;
case AutoDiffDerivativeFunctionKind::VJP:
vjp = f;
break;
}
auto *origAFD = derivAttr->getOriginalFunction(getASTContext());
auto origDeclRef =
SILDeclRef(origAFD).asForeign(requiresForeignEntryPoint(origAFD));
auto *origFn = getFunction(origDeclRef, NotForDefinition);
auto witnessGenSig =
autodiff::getDifferentiabilityWitnessGenericSignature(
origAFD->getGenericSignature(), AFD->getGenericSignature());
auto *resultIndices =
autodiff::getFunctionSemanticResultIndices(origAFD,
derivAttr->getParameterIndices());
AutoDiffConfig config(derivAttr->getParameterIndices(), resultIndices,
witnessGenSig);
emitDifferentiabilityWitness(origAFD, origFn,
DifferentiabilityKind::Reverse, config, jvp,
vjp, derivAttr);
}
}
void SILGenModule::emitFunction(FuncDecl *fd) {
assert(!shouldSkipDecl(fd));
SILDeclRef::Loc decl = fd;
emitAbstractFuncDecl(fd);
if (shouldEmitFunctionBody(fd)) {
Types.setCaptureTypeExpansionContext(SILDeclRef(fd), M);
emitOrDelayFunction(SILDeclRef(decl, fd->hasOnlyCEntryPoint()));
}
}
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;
SILDeclRef constant(decl);
DeclContext *declCtx = decl->getDeclContext();
if (declCtx->getSelfClassDecl()) {
// Designated initializers for classes, as well as @objc convenience
// initializers, have separate entry points for allocation and
// initialization.
if (decl->isDesignatedInit() || decl->isObjC()) {
emitOrDelayFunction(constant);
if (shouldEmitFunctionBody(decl)) {
SILDeclRef initConstant(decl, SILDeclRef::Kind::Initializer);
emitOrDelayFunction(initConstant);
}
return;
}
}
// Struct and enum constructors do everything in a single function, as do
// non-@objc convenience initializers for classes.
if (shouldEmitFunctionBody(decl)) {
emitOrDelayFunction(constant);
}
}
SILFunction *SILGenModule::emitClosure(AbstractClosureExpr *e,
const FunctionTypeInfo &closureInfo) {
Types.setCaptureTypeExpansionContext(SILDeclRef(e), M);
SILFunction *f = nullptr;
Types.withClosureTypeInfo(e, closureInfo, [&] {
SILDeclRef constant(e);
f = getFunction(constant, ForDefinition);
// Generate the closure function, if we haven't already.
//
// We may visit the same closure expr multiple times in some cases,
// for instance, when closures appear as in-line initializers of stored
// properties. In these cases the closure will be emitted into every
// initializer of the containing type.
if (!f->isExternalDeclaration())
return;
// Emit property wrapper argument generators.
emitArgumentGenerators(e, e->getParameters());
emitFunctionDefinition(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->getImplementationContext()->getAllMembers()) {
auto pbd = dyn_cast<PatternBindingDecl>(member);
if (!pbd) continue;
for (auto i : range(pbd->getNumPatternEntries()))
if (pbd->getExecutableInit(i))
return true;
}
return false;
}
bool SILGenModule::hasNonTrivialIVars(ClassDecl *cd) {
for (Decl *member : cd->getImplementationContext()->getAllMembers()) {
auto *vd = dyn_cast<VarDecl>(member);
if (!vd || !vd->hasStorage()) continue;
auto props = Types.getTypeProperties(
vd->getTypeInContext(),
TypeExpansionContext::maximalResilienceExpansionOnly());
if (!props.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->getSuperclassDecl() &&
!cd->getSuperclassDecl()->hasClangNode());
}
/// TODO: This needs a better name.
void SILGenModule::emitObjCAllocatorDestructor(ClassDecl *cd,
DestructorDecl *dd) {
const bool isActorIsolated = needsIsolatingDestructor(dd);
// Emit the isolated deallocating destructor.
// If emitted, it implements actual deallocating and deallocating destructor
// only switches executor
if (dd->hasBody() && !dd->isBodySkipped() && isActorIsolated) {
SILDeclRef dealloc(dd, SILDeclRef::Kind::IsolatedDeallocator);
emitFunctionDefinition(dealloc, getFunction(dealloc, ForDefinition));
}
// Emit the native deallocating destructor for -dealloc.
// Destructors are a necessary part of class metadata, so can't be delayed.
if (shouldEmitFunctionBody(dd)) {
SILDeclRef dealloc(dd, SILDeclRef::Kind::Deallocator);
emitFunctionDefinition(dealloc, getFunction(dealloc, ForDefinition));
// Emit the Objective-C -dealloc entry point if it has
// something to do beyond messaging the superclass's -dealloc.
if (!dd->getBody()->empty() || isActorIsolated)
emitObjCDestructorThunk(dd);
}
// Emit the ivar initializer, if needed.
if (requiresIVarInitialization(*this, cd)) {
auto ivarInitializer = SILDeclRef(cd, SILDeclRef::Kind::IVarInitializer)
.asForeign();
emitFunctionDefinition(ivarInitializer,
getFunction(ivarInitializer, ForDefinition));
}
// Emit the ivar destroyer, if needed.
if (hasNonTrivialIVars(cd)) {
auto ivarDestroyer = SILDeclRef(cd, SILDeclRef::Kind::IVarDestroyer)
.asForeign();
emitFunctionDefinition(ivarDestroyer,
getFunction(ivarDestroyer, ForDefinition));
}
}
void SILGenModule::emitDeallocatorImpl(SILDeclRef constant, SILFunction *f) {
auto *dd = cast<DestructorDecl>(constant.getDecl());
auto *nom = dd->getDeclContext()->getSelfNominalTypeDecl();
if (auto *cd = dyn_cast<ClassDecl>(nom)) {
if (usesObjCAllocator(cd)) {
preEmitFunction(constant, f, dd);
PrettyStackTraceSILFunction X("silgen emitDestructor -dealloc", f);
f->createProfiler(constant);
SILGenFunction(*this, *f, dd).emitObjCDestructor(constant);
postEmitFunction(constant, f);
return;
}
}
auto loc = RegularLocation::getAutoGeneratedLocation(dd);
preEmitFunction(constant, f, loc);
PrettyStackTraceSILFunction X("silgen emitDeallocatingDestructor", f);
bool isIsolated = constant.kind == SILDeclRef::Kind::IsolatedDeallocator;
SILGenFunction(*this, *f, dd).emitDeallocatingDestructor(dd, isIsolated);
postEmitFunction(constant, f);
return;
}
void SILGenModule::emitDestructor(ClassDecl *cd, DestructorDecl *dd) {
emitAbstractFuncDecl(dd);
// Emit the ivar destroyer, if needed.
if (requiresIVarDestroyer(cd)) {
SILDeclRef ivarDestroyer(cd, SILDeclRef::Kind::IVarDestroyer);
emitFunctionDefinition(ivarDestroyer,
getFunction(ivarDestroyer, ForDefinition));
}
// 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.
if (shouldEmitFunctionBody(dd)) {
SILDeclRef destroyer(dd, SILDeclRef::Kind::Destroyer);
emitFunctionDefinition(destroyer, getFunction(destroyer, ForDefinition));
}
// Emit the isolated deallocating destructor.
// If emitted, it implements actual deallocating and deallocating destructor
// only switches executor
if (needsIsolatingDestructor(dd)) {
SILDeclRef deallocator(dd, SILDeclRef::Kind::IsolatedDeallocator);
emitFunctionDefinition(deallocator,
getFunction(deallocator, ForDefinition));
}
// Emit the deallocating destructor.
{
SILDeclRef deallocator(dd, SILDeclRef::Kind::Deallocator);
emitFunctionDefinition(deallocator,
getFunction(deallocator, ForDefinition));
}
}
void SILGenModule::emitMoveOnlyDestructor(NominalTypeDecl *cd,
DestructorDecl *dd) {
assert(!cd->canBeCopyable());
emitAbstractFuncDecl(dd);
// Emit the deallocating destructor if we have a body.
if (shouldEmitFunctionBody(dd)) {
SILDeclRef deallocator(dd, SILDeclRef::Kind::Deallocator);
emitFunctionDefinition(deallocator,
getFunction(deallocator, ForDefinition));
}
}
void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant,
ParamDecl *param) {
switch (param->getDefaultArgumentKind()) {
case DefaultArgumentKind::None:
llvm_unreachable("No default argument here?");
case DefaultArgumentKind::Normal:
case DefaultArgumentKind::StoredProperty:
emitOrDelayFunction(constant);
break;
case DefaultArgumentKind::Inherited:
#define MAGIC_IDENTIFIER(NAME, STRING) \
case DefaultArgumentKind::NAME:
#include "swift/AST/MagicIdentifierKinds.def"
case DefaultArgumentKind::NilLiteral:
case DefaultArgumentKind::EmptyArray:
case DefaultArgumentKind::EmptyDictionary:
case DefaultArgumentKind::ExpressionMacro:
break;
}
}
void SILGenModule::
emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
// The SIL emitted for property init expressions is only needed by clients of
// resilient modules if the property belongs to a frozen type. When
// -experimental-skip-non-exportable-decls is specified, skip emitting
// property inits if possible.
if (M.getOptions().SkipNonExportableDecls &&
!pbd->getAnchoringVarDecl(i)->isInitExposedToClients())
return;
// Force the executable init to be type checked before emission.
if (!pbd->getCheckedAndContextualizedExecutableInit(i))
return;
auto *var = pbd->getAnchoringVarDecl(i);
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
emitOrDelayFunction(constant);
}
void SILGenModule::
emitPropertyWrapperBackingInitializer(VarDecl *var) {
if (M.getOptions().SkipNonExportableDecls)
return;
auto initInfo = var->getPropertyWrapperInitializerInfo();
if (initInfo.hasInitFromWrappedValue()) {
// FIXME: Fully typecheck the original property's init expression on-demand
// for lazy typechecking mode.
SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperBackingInitializer);
emitOrDelayFunction(constant);
}
if (initInfo.hasInitFromProjectedValue()) {
SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue);
emitOrDelayFunction(constant);
}
}
void SILGenModule::emitPropertyWrappedFieldInitAccessor(VarDecl *var) {
SILDeclRef constant(var, SILDeclRef::Kind::PropertyWrappedFieldInitAccessor);
emitOrDelayFunction(constant);
}
SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName,
PatternBindingDecl *binding,
unsigned pbdEntry) {
ASTContext &C = M.getASTContext();
auto *onceBuiltin =
cast<FuncDecl>(getBuiltinValueDecl(C, C.getIdentifier("once")));
auto blockParam = onceBuiltin->getParameters()->get(1);
auto *initType = blockParam->getTypeInContext()->castTo<FunctionType>();
auto initSILType = cast<SILFunctionType>(
Types.getLoweredRValueType(TypeExpansionContext::minimal(), initType));
SILGenFunctionBuilder builder(*this);
auto *f = builder.createFunction(
SILLinkage::Private, funcName, initSILType, nullptr, SILLocation(binding),
IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic,
IsNotDistributed, IsNotRuntimeAccessible);
f->setSpecialPurpose(SILFunction::Purpose::GlobalInitOnceFunction);
f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f));
auto dc = binding->getDeclContext();
SILGenFunction(*this, *f, dc).emitLazyGlobalInitializer(binding, pbdEntry);
emitLazyConformancesForFunction(f);
f->verifyIncompleteOSSA();
return f;
}
void SILGenModule::emitGlobalAccessor(VarDecl *global,
SILGlobalVariable *onceToken,
SILFunction *onceFunc) {
SILDeclRef accessor(global, SILDeclRef::Kind::GlobalAccessor);
delayedGlobals[global] = std::make_pair(onceToken, onceFunc);
emitOrDelayFunction(accessor);
}
void SILGenModule::emitArgumentGenerators(SILDeclRef::Loc decl,
ParameterList *paramList) {
unsigned index = 0;
for (auto param : *paramList) {
if (param->isDefaultArgument())
emitDefaultArgGenerator(SILDeclRef::getDefaultArgGenerator(decl, index),
param);
if (param->hasExternalPropertyWrapper())
emitPropertyWrapperBackingInitializer(param);
++index;
}
}
void SILGenModule::emitObjCMethodThunk(FuncDecl *method) {
auto thunk = SILDeclRef(method).asForeign();
// 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.
emitNativeToForeignThunk(thunk);
}
void SILGenModule::emitObjCPropertyMethodThunks(AbstractStorageDecl *prop) {
auto *getter = prop->getOpaqueAccessor(AccessorKind::Get);
// If we don't actually need an entry point for the getter, do nothing.
if (!getter || !requiresObjCMethodEntryPoint(getter))
return;
auto getterRef = SILDeclRef(getter, SILDeclRef::Kind::Func).asForeign();
// Don't emit the thunks if they already exist.
if (hasFunction(getterRef))
return;
// ObjC entry points are always externally usable, so emitting can't be
// delayed.
emitNativeToForeignThunk(getterRef);
if (!prop->isSettable(prop->getDeclContext()))
return;
// FIXME: Add proper location.
auto *setter = prop->getOpaqueAccessor(AccessorKind::Set);
auto setterRef = SILDeclRef(setter, SILDeclRef::Kind::Func).asForeign();
emitNativeToForeignThunk(setterRef);
}
void SILGenModule::emitObjCConstructorThunk(ConstructorDecl *constructor) {
auto thunk = SILDeclRef(constructor, SILDeclRef::Kind::Initializer)
.asForeign();
// 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.
emitNativeToForeignThunk(thunk);
}
void SILGenModule::emitObjCDestructorThunk(DestructorDecl *destructor) {
auto thunk = SILDeclRef(destructor, SILDeclRef::Kind::Deallocator)
.asForeign();
// Don't emit the thunk if it already exists.
if (hasFunction(thunk))
return;
emitNativeToForeignThunk(thunk);
}
void SILGenModule::visitPatternBindingDecl(PatternBindingDecl *pd) {
for (auto i : range(pd->getNumPatternEntries()))
if (pd->getExecutableInit(i))
emitGlobalInitialization(pd, i);
}
void SILGenModule::visitVarDecl(VarDecl *vd) {
if (vd->hasStorage())
addGlobalVariable(vd);
visitEmittedAccessors(vd, [&](AccessorDecl *accessor) {
emitFunction(accessor);
});
tryEmitPropertyDescriptor(vd);
}
void SILGenModule::visitSubscriptDecl(SubscriptDecl *sd) {
llvm_unreachable("top-level subscript?");
}
void SILGenModule::visitMissingDecl(MissingDecl *sd) {
llvm_unreachable("missing decl in SILGen");
}
void SILGenModule::visitMacroDecl(MacroDecl *d) {
// nothing to emit for macros
}
void SILGenModule::visitMacroExpansionDecl(MacroExpansionDecl *d) {
// Expansion already visited as auxiliary decls.
}
void SILGenModule::visitEmittedAccessors(
AbstractStorageDecl *D, llvm::function_ref<void(AccessorDecl *)> callback) {
D->visitEmittedAccessors([&](AccessorDecl *accessor) {
if (shouldSkipDecl(accessor))
return;
callback(accessor);
});
}
bool
SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
ResilienceExpansion expansion) {
// If the declaration is resilient, we have to treat the component as
// computed.
if (decl->isResilient(M.getSwiftModule(), expansion))
return false;
auto strategy = decl->getAccessStrategy(
AccessSemantics::Ordinary,
decl->supportsMutation() ? AccessKind::ReadWrite : AccessKind::Read,
M.getSwiftModule(), expansion, std::nullopt,
/*useOldABI=*/false);
switch (strategy.getKind()) {
case AccessStrategy::Storage: {
// Keypaths rely on accessors to handle the special behavior of weak,
// unowned, or static properties.
if (decl->getInterfaceType()->is<ReferenceStorageType>() ||
decl->isStatic())
return false;
// If the field offset depends on the generic instantiation, we have to
// load it from metadata when instantiating the keypath component.
//
// However the metadata offset itself will not be fixed if the superclass
// is resilient. Fall back to treating the property as computed in this
// case.
//
// See the call to getClassFieldOffsetOffset() inside
// emitKeyPathComponent().
if (auto *parentClass = dyn_cast<ClassDecl>(decl->getDeclContext())) {
if (parentClass->hasGenericParamList()) {
auto ancestry = parentClass->checkAncestry();
if (ancestry.contains(AncestryFlags::ResilientOther))
return false;
}
}
// If the stored value would need to be reabstracted in fully opaque
// context, then we have to treat the component as computed.
auto componentObjTy = decl->getValueInterfaceType();
if (auto genericEnv =
decl->getInnermostDeclContext()->getGenericEnvironmentOfContext())
componentObjTy = genericEnv->mapTypeIntoContext(componentObjTy);
auto storageTy = M.Types.getSubstitutedStorageType(
TypeExpansionContext::minimal(), decl, componentObjTy);
auto opaqueTy = M.Types.getLoweredRValueType(
TypeExpansionContext::noOpaqueTypeArchetypesSubstitution(expansion),
AbstractionPattern::getOpaque(), componentObjTy);
return storageTy.getASTType() == opaqueTy;
}
case AccessStrategy::DirectToAccessor:
case AccessStrategy::DispatchToAccessor:
case AccessStrategy::MaterializeToTemporary:
case AccessStrategy::DispatchToDistributedThunk:
return false;
}
llvm_unreachable("unhandled strategy");
}
static bool canStorageUseTrivialDescriptor(SILGenModule &SGM,
AbstractStorageDecl *decl) {
// A property can use a trivial property descriptor if the key path component
// that an external module would form given publicly-exported information
// about the property is never equivalent to the canonical component for the
// key path.
// This means that the property isn't stored (without promising to be always
// stored) and doesn't have a setter with less-than-public visibility.
auto expansion = ResilienceExpansion::Maximal;
if (!SGM.M.getSwiftModule()->isResilient()) {
if (SGM.canStorageUseStoredKeyPathComponent(decl, expansion)) {
// External modules can't directly access storage, unless this is a
// property in a fixed-layout type.
// Assert here as key path component cannot refer to a static var.
assert(!decl->isStatic());
// By this point, decl is a fixed layout or its enclosing type is non-resilient.
return true;
}
// If the type is computed and doesn't have a setter that's hidden from
// the public, then external components can form the canonical key path
// without our help.
auto *setter = decl->getOpaqueAccessor(AccessorKind::Set);
if (!setter)
return true;
if (setter->getFormalAccessScope(nullptr, true).isPublicOrPackage())
return true;
return false;
}
// A resilient module needs to handle binaries compiled against its older
// versions. This means we have to be a bit more conservative, since in
// earlier versions, a settable property may have withheld the setter,
// or a fixed-layout type may not have been.
// Without availability information, only get-only computed properties
// can resiliently use trivial descriptors.
return (!SGM.canStorageUseStoredKeyPathComponent(decl, expansion) &&
!decl->supportsMutation());
}
void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) {
// TODO: Key path code emission doesn't handle opaque values properly yet.
if (!SILModuleConventions(M).useLoweredAddresses())
return;
auto descriptorContext = decl->getPropertyDescriptorGenericSignature();
if (!descriptorContext)
return;
PrettyStackTraceDecl stackTrace("emitting property descriptor for", decl);
Type baseTy;
if (decl->getDeclContext()->isTypeContext()) {
baseTy = decl->getDeclContext()->getSelfInterfaceType()
->getReducedType(*descriptorContext);
if (decl->isStatic()) {
baseTy = MetatypeType::get(baseTy);
}
} else {
// TODO: Global variables should eventually be referenceable as
// key paths from (), viz. baseTy = TupleType::getEmpty(getASTContext());
llvm_unreachable("should not export a property descriptor yet");
}
auto genericEnv = descriptorContext->getGenericEnvironment();
unsigned baseOperand = 0;
bool needsGenericContext = true;
if (canStorageUseTrivialDescriptor(*this, decl)) {
(void)SILProperty::create(M, /*serializedKind*/ 0, decl, std::nullopt);
return;
}
SubstitutionMap subs;
if (genericEnv) {
// The substitutions are used when invoking the underlying accessors, so
// we get these from the original declaration generic environment, even if
// `getPropertyDescriptorGenericSignature` computed a different generic
// environment, since the accessors will not need the extra Copyable or
// Escapable requirements.
subs = SubstitutionMap::get(decl->getInnermostDeclContext()
->getGenericSignatureOfContext(),
genericEnv->getForwardingSubstitutionMap());
}
auto component = emitKeyPathComponentForDecl(SILLocation(decl),
genericEnv,
ResilienceExpansion::Maximal,
baseOperand, needsGenericContext,
subs, decl, {},
baseTy->getCanonicalType(),
M.getSwiftModule(),
/*property descriptor*/ true);
(void)SILProperty::create(M, /*serializedKind*/ 0, decl, component);
}
void SILGenModule::emitSourceFile(SourceFile *sf) {
// Type-check the file if we haven't already.
performTypeChecking(*sf);
if (sf->isScriptMode()) {
emitEntryPoint(sf);
}
for (auto *D : sf->getTopLevelDecls()) {
// Emit auxiliary decls.
D->visitAuxiliaryDecls([&](Decl *auxiliaryDecl) {
visit(auxiliaryDecl);
});
visit(D);
}
// FIXME: Visit macro-generated extensions separately.
//
// The code below that visits auxiliary decls of the top-level
// decls in the source file does not work for nested types with
// attached conformance macros:
// ```
// struct Outer {
// @AddConformance struct Inner {}
// }
// ```
// Because the attached-to decl is not at the top-level. To fix this,
// visit the macro-generated conformances that are recorded in the
// synthesized file unit to cover all macro-generated extension decls.
if (auto *synthesizedFile = sf->getSynthesizedFile()) {
for (auto *D : synthesizedFile->getTopLevelDecls()) {
if (!isa<ExtensionDecl>(D))
continue;
auto *sf = D->getInnermostDeclContext()->getParentSourceFile();
if (sf->getFulfilledMacroRole() != MacroRole::Conformance &&
sf->getFulfilledMacroRole() != MacroRole::Extension)
continue;
visit(D);
}
}
for (Decl *D : sf->getHoistedDecls()) {
visit(D);
}
for (TypeDecl *TD : sf->getLocalTypeDecls()) {
// FIXME: Delayed parsing would prevent these types from being added to
// the module in the first place.
if (TD->getDeclContext()->getInnermostSkippedFunctionContext())
continue;
visit(TD);
}
// If the source file contains an artificial main, emit the implicit
// top-level code.
if (auto *mainDecl = sf->getMainDecl()) {
if (isa<FuncDecl>(mainDecl) &&
static_cast<FuncDecl *>(mainDecl)->hasAsync()) {
auto ref = SILDeclRef::getAsyncMainDeclEntryPoint(mainDecl);
emitFunctionDefinition(ref, getFunction(ref, ForDefinition));
}
auto ref = SILDeclRef::getMainDeclEntryPoint(mainDecl);
emitFunctionDefinition(ref, getFunction(ref, ForDefinition));
}
}
void SILGenModule::emitSymbolSource(SymbolSource Source) {
switch (Source.kind) {
case SymbolSource::Kind::SIL: {
auto ref = Source.getSILDeclRef();
emitFunctionDefinition(ref, getFunction(ref, ForDefinition));
break;
}
case SymbolSource::Kind::Global:
addGlobalVariable(Source.getGlobal());
break;
case SymbolSource::Kind::IR:
llvm_unreachable("Unimplemented: Emission of LinkEntities");
case SymbolSource::Kind::Unknown:
case SymbolSource::Kind::LinkerDirective:
// Nothing to do
break;
}
}
std::unique_ptr<SILModule>
ASTLoweringRequest::evaluate(Evaluator &evaluator,
ASTLoweringDescriptor desc) const {
// If we have a .sil file to parse, defer to the parsing request.
if (desc.getSourceFileToParse()) {
return evaluateOrFatal(evaluator, ParseSILModuleRequest{desc});
}
auto silMod = SILModule::createEmptyModule(desc.context, desc.conv,
desc.opts, desc.irgenOptions);
auto &ctx = silMod->getASTContext();
FrontendStatsTracer tracer(ctx.Stats, "SILGen");
// If all function bodies are being skipped there's no reason to do any
// SIL generation.
if (desc.opts.SkipFunctionBodies == FunctionBodySkipping::All)
return silMod;
// Skip emitting SIL if there's been any compilation errors
if (ctx.hadError() &&
ctx.LangOpts.AllowModuleWithCompilerErrors)
return silMod;
SILGenModule SGM(*silMod, silMod->getSwiftModule());
// Emit a specific set of SILDeclRefs if needed.
if (auto Sources = desc.SourcesToEmit) {
for (auto Source : *Sources)
SGM.emitSymbolSource(std::move(Source));
}
// Emit any whole-files needed.
for (auto file : desc.getFilesToEmit()) {
if (auto *nextSF = dyn_cast<SourceFile>(file))
SGM.emitSourceFile(nextSF);
}
// Also make sure to process any intermediate files that may contain SIL.
bool shouldDeserialize =
llvm::any_of(desc.getFilesToEmit(), [](const FileUnit *File) -> bool {
return isa<SerializedASTFile>(File);
});
if (shouldDeserialize) {
auto *primary = desc.context.dyn_cast<FileUnit *>();
silMod->getSILLoader()->getAllForModule(silMod->getSwiftModule()->getName(),
primary);
}
// 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.pendingForcedFunctions.empty()
|| !SGM.pendingConformances.empty()) {
while (!SGM.pendingForcedFunctions.empty()) {
auto &front = SGM.pendingForcedFunctions.front();
SGM.emitFunctionDefinition(
front, SGM.getEmittedFunction(front, ForDefinition));
SGM.pendingForcedFunctions.pop_front();
}
while (!SGM.pendingConformances.empty()) {
(void)SGM.getWitnessTable(SGM.pendingConformances.front());
SGM.pendingConformances.pop_front();
}
}
return silMod;
}
std::unique_ptr<SILModule>
swift::performASTLowering(ModuleDecl *mod, Lowering::TypeConverter &tc,
const SILOptions &options,
const IRGenOptions *irgenOptions) {
auto desc = ASTLoweringDescriptor::forWholeModule(mod, tc, options,
std::nullopt, irgenOptions);
return evaluateOrFatal(mod->getASTContext().evaluator,
ASTLoweringRequest{desc});
}
std::unique_ptr<SILModule> swift::performASTLowering(CompilerInstance &CI,
SymbolSources Sources) {
auto *M = CI.getMainModule();
const auto &Invocation = CI.getInvocation();
const auto &SILOpts = Invocation.getSILOptions();
const auto &IRGenOpts = Invocation.getIRGenOptions();
auto &TC = CI.getSILTypes();
auto Desc = ASTLoweringDescriptor::forWholeModule(
M, TC, SILOpts, std::move(Sources), &IRGenOpts);
return evaluateOrFatal(M->getASTContext().evaluator,
ASTLoweringRequest{Desc});
}
std::unique_ptr<SILModule>
swift::performASTLowering(FileUnit &sf, Lowering::TypeConverter &tc,
const SILOptions &options,
const IRGenOptions *irgenOptions) {
auto desc =
ASTLoweringDescriptor::forFile(sf, tc, options, std::nullopt, irgenOptions);
return evaluateOrFatal(sf.getASTContext().evaluator,
ASTLoweringRequest{desc});
}