Files
swift-mirror/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp
Andrew Trick 7d0a772542 Fix ExistentialSpecializer: inherited conformance
The ExistentialSpecializer incorrectly assumed that an existential's conformances match an opened archetype. They don't. Opened archetypes strip inherited conformances per the ABI for generic argument passing. Existential values retain those inherited conformances (for some inexplicable reason).

- Rename ASTContext::getExistentialSignature() to
  getOpenedArchetypeSiganture() because it was doing exactly the wrong
  thing for existentials.

- Fix ConcreteExistentialInfo to produce the correct SubstitutionMap.

- Fix ExistentialSpecializer to generate the correct conformances for
  init_existential by adding a collectExistentialConformances() helper.

Fixes <rdar://problem/57025861> "Assertion failed: (conformances.size() == numConformanceRequirements)" in ExistentialSpecializer on inlined code
2019-11-22 01:56:20 -08:00

642 lines
25 KiB
C++

//===------- ExistentialTransform.cpp - Transform Existential Args -------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Transform existential parameters to generic ones.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "sil-existential-transform"
#include "ExistentialTransform.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/SIL/OptimizationRemark.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/TypeSubstCloner.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
#include "swift/SILOptimizer/Utils/Existential.h"
#include "swift/SILOptimizer/Utils/Generics.h"
#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
#include "swift/SILOptimizer/Utils/SpecializationMangler.h"
#include "llvm/ADT/SmallVector.h"
using namespace swift;
using llvm::SmallDenseMap;
using llvm::SmallPtrSet;
using llvm::SmallVector;
using llvm::SmallVectorImpl;
/// Create a SILCloner for Existential Specilizer.
namespace {
class ExistentialSpecializerCloner
: public TypeSubstCloner<ExistentialSpecializerCloner,
SILOptFunctionBuilder> {
using SuperTy =
TypeSubstCloner<ExistentialSpecializerCloner, SILOptFunctionBuilder>;
friend class SILInstructionVisitor<ExistentialSpecializerCloner>;
friend class SILCloner<ExistentialSpecializerCloner>;
SILFunction *OrigF;
SmallVector<ArgumentDescriptor, 4> &ArgumentDescList;
SmallDenseMap<int, GenericTypeParamType *> &ArgToGenericTypeMap;
SmallDenseMap<int, ExistentialTransformArgumentDescriptor>
&ExistentialArgDescriptor;
// Use one OpenedArchetypesTracker while cloning.
SILOpenedArchetypesTracker OpenedArchetypesTracker;
// AllocStack instructions introduced in the new prolog that require cleanup.
SmallVector<AllocStackInst *, 4> AllocStackInsts;
// Temporary values introduced in the new prolog that require cleanup.
SmallVector<SILValue, 4> CleanupValues;
protected:
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
SILClonerWithScopes<ExistentialSpecializerCloner>::postProcess(Orig,
Cloned);
}
void cloneArguments(SmallVectorImpl<SILValue> &entryArgs);
public:
ExistentialSpecializerCloner(
SILFunction *OrigF, SILFunction *NewF, SubstitutionMap Subs,
SmallVector<ArgumentDescriptor, 4> &ArgumentDescList,
SmallDenseMap<int, GenericTypeParamType *> &ArgToGenericTypeMap,
SmallDenseMap<int, ExistentialTransformArgumentDescriptor>
&ExistentialArgDescriptor)
: SuperTy(*NewF, *OrigF, Subs), OrigF(OrigF),
ArgumentDescList(ArgumentDescList),
ArgToGenericTypeMap(ArgToGenericTypeMap),
ExistentialArgDescriptor(ExistentialArgDescriptor),
OpenedArchetypesTracker(NewF) {
getBuilder().setOpenedArchetypesTracker(&OpenedArchetypesTracker);
}
void cloneAndPopulateFunction();
};
} // end anonymous namespace
/// This function will create the generic version.
void ExistentialSpecializerCloner::cloneAndPopulateFunction() {
SmallVector<SILValue, 4> entryArgs;
entryArgs.reserve(OrigF->getArguments().size());
cloneArguments(entryArgs);
// Visit original BBs in depth-first preorder, starting with the
// entry block, cloning all instructions and terminators.
auto *NewEntryBB = getBuilder().getFunction().getEntryBlock();
cloneFunctionBody(&Original, NewEntryBB, entryArgs);
// Cleanup allocations created in the new prolog.
SmallVector<SILBasicBlock *, 4> exitingBlocks;
getBuilder().getFunction().findExitingBlocks(exitingBlocks);
for (auto *exitBB : exitingBlocks) {
SILBuilderWithScope Builder(exitBB->getTerminator());
// A return location can't be used for a non-return instruction.
auto loc = RegularLocation::getAutoGeneratedLocation();
for (SILValue cleanupVal : CleanupValues)
Builder.createDestroyAddr(loc, cleanupVal);
for (auto *ASI : llvm::reverse(AllocStackInsts))
Builder.createDeallocStack(loc, ASI);
}
}
// Gather the conformances needed for an existential value based on an opened
// archetype. This adds any conformances inherited from superclass constraints.
static ArrayRef<ProtocolConformanceRef>
collectExistentialConformances(ModuleDecl *M, CanType openedType,
CanType existentialType) {
assert(!openedType.isAnyExistentialType());
auto layout = existentialType.getExistentialLayout();
auto protocols = layout.getProtocols();
SmallVector<ProtocolConformanceRef, 4> conformances;
for (auto proto : protocols) {
auto conformance = M->lookupConformance(openedType, proto->getDecl());
assert(conformance);
conformances.push_back(conformance);
}
return M->getASTContext().AllocateCopy(conformances);
}
// Create the entry basic block with the function arguments.
void ExistentialSpecializerCloner::cloneArguments(
SmallVectorImpl<SILValue> &entryArgs) {
auto &M = OrigF->getModule();
// Create the new entry block.
SILFunction &NewF = getBuilder().getFunction();
SILBasicBlock *ClonedEntryBB = NewF.createBasicBlock();
/// Builder will have a ScopeClone with a debugscope that is inherited from
/// the F.
ScopeCloner SC(NewF);
auto DebugScope = SC.getOrCreateClonedScope(OrigF->getDebugScope());
// Setup a NewFBuilder for the new entry block, reusing the cloner's
// SILBuilderContext.
SILBuilder NewFBuilder(ClonedEntryBB, DebugScope,
getBuilder().getBuilderContext());
auto InsertLoc = RegularLocation::getAutoGeneratedLocation();
auto NewFTy = NewF.getLoweredFunctionType();
SmallVector<SILParameterInfo, 4> params;
params.append(NewFTy->getParameters().begin(), NewFTy->getParameters().end());
for (auto &ArgDesc : ArgumentDescList) {
auto iter = ArgToGenericTypeMap.find(ArgDesc.Index);
if (iter == ArgToGenericTypeMap.end()) {
// Clone arguments that are not rewritten.
auto Ty = params[ArgDesc.Index].getArgumentType(M, NewFTy);
auto LoweredTy = NewF.getLoweredType(NewF.mapTypeIntoContext(Ty));
auto MappedTy =
LoweredTy.getCategoryType(ArgDesc.Arg->getType().getCategory());
auto *NewArg =
ClonedEntryBB->createFunctionArgument(MappedTy, ArgDesc.Decl);
NewArg->setOwnershipKind(ValueOwnershipKind(
NewF, MappedTy, ArgDesc.Arg->getArgumentConvention()));
entryArgs.push_back(NewArg);
continue;
}
// Create the generic argument.
GenericTypeParamType *GenericParam = iter->second;
SILType GenericSILType =
NewF.getLoweredType(NewF.mapTypeIntoContext(GenericParam));
GenericSILType = GenericSILType.getCategoryType(
ArgDesc.Arg->getType().getCategory());
auto *NewArg = ClonedEntryBB->createFunctionArgument(GenericSILType);
NewArg->setOwnershipKind(ValueOwnershipKind(
NewF, GenericSILType, ArgDesc.Arg->getArgumentConvention()));
// Determine the Conformances.
SILType ExistentialType = ArgDesc.Arg->getType().getObjectType();
CanType OpenedType = NewArg->getType().getASTType();
auto Conformances = collectExistentialConformances(
M.getSwiftModule(), OpenedType, ExistentialType.getASTType());
auto ExistentialRepr =
ArgDesc.Arg->getType().getPreferredExistentialRepresentation();
auto &EAD = ExistentialArgDescriptor[ArgDesc.Index];
switch (ExistentialRepr) {
case ExistentialRepresentation::Opaque: {
/// Create this sequence for init_existential_addr.:
/// bb0(%0 : $*T):
/// %3 = alloc_stack $P
/// %4 = init_existential_addr %3 : $*P, $T
/// copy_addr [take] %0 to [initialization] %4 : $*T
/// %7 = open_existential_addr immutable_access %3 : $*P to
/// $*@opened P
auto *ASI =
NewFBuilder.createAllocStack(InsertLoc, ArgDesc.Arg->getType());
AllocStackInsts.push_back(ASI);
auto *EAI = NewFBuilder.createInitExistentialAddr(
InsertLoc, ASI, NewArg->getType().getASTType(), NewArg->getType(),
Conformances);
bool origConsumed = EAD.isConsumed;
// If the existential is not consumed in the function body, then the one
// we introduce here needs cleanup.
if (!origConsumed)
CleanupValues.push_back(ASI);
NewFBuilder.createCopyAddr(InsertLoc, NewArg, EAI,
origConsumed ? IsTake_t::IsTake
: IsTake_t::IsNotTake,
IsInitialization_t::IsInitialization);
entryArgs.push_back(ASI);
break;
}
case ExistentialRepresentation::Class: {
SILValue NewArgValue = NewArg;
if (!NewArg->getType().isObject()) {
NewArgValue = NewFBuilder.createLoad(InsertLoc, NewArg,
LoadOwnershipQualifier::Unqualified);
}
// FIXME_ownership: init_existential_ref always takes ownership of the
// incoming reference. If the argument convention is borrowed
// (!isConsumed), then we should create a copy_value here and add this new
// existential to the CleanupValues vector.
/// Simple case: Create an init_existential.
/// %5 = init_existential_ref %0 : $T : $T, $P
SILValue InitRef = NewFBuilder.createInitExistentialRef(
InsertLoc, ArgDesc.Arg->getType().getObjectType(),
NewArg->getType().getASTType(),
NewArgValue, Conformances);
if (!NewArg->getType().isObject()) {
auto alloc = NewFBuilder.createAllocStack(InsertLoc,
InitRef->getType());
NewFBuilder.createStore(InsertLoc, InitRef, alloc,
StoreOwnershipQualifier::Unqualified);
InitRef = alloc;
AllocStackInsts.push_back(alloc);
}
entryArgs.push_back(InitRef);
break;
}
default: {
llvm_unreachable("Unhandled existential type in ExistentialTransform!");
break;
}
};
}
}
/// Create a new function name for the newly generated protocol constrained
/// generic function.
std::string ExistentialTransform::createExistentialSpecializedFunctionName() {
for (auto const &IdxIt : ExistentialArgDescriptor) {
int Idx = IdxIt.first;
Mangler.setArgumentExistentialToGeneric(Idx);
}
auto MangledName = Mangler.mangle();
assert(!F->getModule().hasFunction(MangledName));
return MangledName;
}
/// Convert all existential argument types to generic argument type.
void ExistentialTransform::convertExistentialArgTypesToGenericArgTypes(
SmallVectorImpl<GenericTypeParamType *> &genericParams,
SmallVectorImpl<Requirement> &requirements) {
SILModule &M = F->getModule();
auto &Ctx = M.getASTContext();
auto FTy = F->getLoweredFunctionType();
/// If the original function is generic, then maintain the same.
auto OrigGenericSig = FTy->getInvocationGenericSignature();
/// Original list of parameters
SmallVector<SILParameterInfo, 4> params;
params.append(FTy->getParameters().begin(), FTy->getParameters().end());
/// Determine the existing generic parameter depth.
int Depth = 0;
if (OrigGenericSig != nullptr) {
Depth = OrigGenericSig->getGenericParams().back()->getDepth() + 1;
}
/// Index of the Generic Parameter.
int GPIdx = 0;
/// Convert the protocol arguments of F to generic ones.
for (auto const &IdxIt : ExistentialArgDescriptor) {
int Idx = IdxIt.first;
auto &param = params[Idx];
auto PType = param.getArgumentType(M, FTy);
assert(PType.isExistentialType());
/// Generate new generic parameter.
auto *NewGenericParam = GenericTypeParamType::get(Depth, GPIdx++, Ctx);
genericParams.push_back(NewGenericParam);
Requirement NewRequirement(RequirementKind::Conformance, NewGenericParam,
PType);
requirements.push_back(NewRequirement);
ArgToGenericTypeMap.insert(
std::pair<int, GenericTypeParamType *>(Idx, NewGenericParam));
assert(ArgToGenericTypeMap.find(Idx) != ArgToGenericTypeMap.end());
}
}
/// Create the signature for the newly generated protocol constrained generic
/// function.
CanSILFunctionType
ExistentialTransform::createExistentialSpecializedFunctionType() {
auto FTy = F->getLoweredFunctionType();
SILModule &M = F->getModule();
auto &Ctx = M.getASTContext();
GenericSignature NewGenericSig;
GenericEnvironment *NewGenericEnv;
/// If the original function is generic, then maintain the same.
auto OrigGenericSig = FTy->getInvocationGenericSignature();
SmallVector<GenericTypeParamType *, 2> GenericParams;
SmallVector<Requirement, 2> Requirements;
/// Convert existential argument types to generic argument types.
convertExistentialArgTypesToGenericArgTypes(GenericParams, Requirements);
/// Compute the updated generic signature.
NewGenericSig = evaluateOrDefault(
Ctx.evaluator,
AbstractGenericSignatureRequest{
OrigGenericSig.getPointer(), std::move(GenericParams),
std::move(Requirements)},
GenericSignature());
NewGenericEnv = NewGenericSig->getGenericEnvironment();
/// Create a lambda for GenericParams.
auto getCanonicalType = [&](Type t) -> CanType {
return t->getCanonicalType(NewGenericSig);
};
/// Original list of parameters
SmallVector<SILParameterInfo, 4> params;
params.append(FTy->getParameters().begin(), FTy->getParameters().end());
/// Create the complete list of parameters.
int Idx = 0;
SmallVector<SILParameterInfo, 8> InterfaceParams;
InterfaceParams.reserve(params.size());
for (auto &param : params) {
auto iter = ArgToGenericTypeMap.find(Idx);
if (iter != ArgToGenericTypeMap.end()) {
auto GenericParam = iter->second;
InterfaceParams.push_back(SILParameterInfo(getCanonicalType(GenericParam),
param.getConvention()));
} else {
InterfaceParams.push_back(param);
}
Idx++;
}
// Add error results.
Optional<SILResultInfo> InterfaceErrorResult;
if (FTy->hasErrorResult()) {
InterfaceErrorResult = FTy->getErrorResult();
}
/// Finally the ExtInfo.
auto ExtInfo = FTy->getExtInfo();
ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin);
auto witnessMethodConformance = FTy->getWitnessMethodConformanceOrInvalid();
/// Return the new signature.
return SILFunctionType::get(
NewGenericSig, ExtInfo, FTy->getCoroutineKind(),
FTy->getCalleeConvention(), InterfaceParams, FTy->getYields(),
FTy->getResults(), InterfaceErrorResult,
SubstitutionMap(), false,
Ctx, witnessMethodConformance);
}
/// Create the Thunk Body with always_inline attribute.
void ExistentialTransform::populateThunkBody() {
SILModule &M = F->getModule();
F->setThunk(IsSignatureOptimizedThunk);
F->setInlineStrategy(AlwaysInline);
/// Remove original body of F.
for (auto It = F->begin(), End = F->end(); It != End;) {
auto *BB = &*It++;
removeDeadBlock(BB);
}
/// Create a basic block and the function arguments.
auto *ThunkBody = F->createBasicBlock();
for (auto &ArgDesc : ArgumentDescList) {
auto argumentType = ArgDesc.Arg->getType();
ThunkBody->createFunctionArgument(argumentType, ArgDesc.Decl);
}
/// Builder to add new instructions in the Thunk.
SILBuilder Builder(ThunkBody);
SILOpenedArchetypesTracker OpenedArchetypesTracker(F);
Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker);
Builder.setCurrentDebugScope(ThunkBody->getParent()->getDebugScope());
/// Location to insert new instructions.
auto Loc = ThunkBody->getParent()->getLocation();
/// Create the function_ref instruction to the NewF.
auto *FRI = Builder.createFunctionRefFor(Loc, NewF);
auto GenCalleeType = NewF->getLoweredFunctionType();
auto CalleeGenericSig = GenCalleeType->getInvocationGenericSignature();
auto OrigGenCalleeType = F->getLoweredFunctionType();
auto OrigCalleeGenericSig =
OrigGenCalleeType->getInvocationGenericSignature();
/// Determine arguments to Apply.
/// Generate opened existentials for generics.
SmallVector<SILValue, 8> ApplyArgs;
// Maintain a list of arg values to be destroyed. These are consumed by the
// convention and require a copy.
struct Temp {
SILValue DeallocStackEntry;
SILValue DestroyValue;
};
SmallVector<Temp, 8> Temps;
SmallDenseMap<GenericTypeParamType *, Type> GenericToOpenedTypeMap;
for (auto &ArgDesc : ArgumentDescList) {
auto iter = ArgToGenericTypeMap.find(ArgDesc.Index);
auto it = ExistentialArgDescriptor.find(ArgDesc.Index);
if (iter != ArgToGenericTypeMap.end() &&
it != ExistentialArgDescriptor.end()) {
ExistentialTransformArgumentDescriptor &ETAD = it->second;
OpenedArchetypeType *Opened;
auto OrigOperand = ThunkBody->getArgument(ArgDesc.Index);
auto SwiftType = ArgDesc.Arg->getType().getASTType();
auto OpenedType =
SwiftType->openAnyExistentialType(Opened)->getCanonicalType();
auto OpenedSILType = NewF->getLoweredType(OpenedType);
SILValue archetypeValue;
auto ExistentialRepr =
ArgDesc.Arg->getType().getPreferredExistentialRepresentation();
switch (ExistentialRepr) {
case ExistentialRepresentation::Opaque: {
archetypeValue = Builder.createOpenExistentialAddr(
Loc, OrigOperand, OpenedSILType, it->second.AccessType);
SILValue calleeArg = archetypeValue;
if (ETAD.isConsumed) {
// open_existential_addr projects a borrowed address into the
// existential box. Since the callee consumes the generic value, we
// must pass in a copy.
auto *ASI =
Builder.createAllocStack(Loc, OpenedSILType);
Builder.createCopyAddr(Loc, archetypeValue, ASI, IsNotTake,
IsInitialization_t::IsInitialization);
Temps.push_back({ASI, OrigOperand});
calleeArg = ASI;
}
ApplyArgs.push_back(calleeArg);
break;
}
case ExistentialRepresentation::Class: {
// If the operand is not object type, we need an explicit load.
SILValue OrigValue = OrigOperand;
if (!OrigOperand->getType().isObject()) {
OrigValue = Builder.createLoad(Loc, OrigValue,
LoadOwnershipQualifier::Unqualified);
}
// OpenExistentialRef forwards ownership, so it does the right thing
// regardless of whether the argument is borrowed or consumed.
archetypeValue =
Builder.createOpenExistentialRef(Loc, OrigValue, OpenedSILType);
if (!OrigOperand->getType().isObject()) {
SILValue ASI = Builder.createAllocStack(Loc, OpenedSILType);
Builder.createStore(Loc, archetypeValue, ASI,
StoreOwnershipQualifier::Unqualified);
Temps.push_back({ASI, SILValue()});
archetypeValue = ASI;
}
ApplyArgs.push_back(archetypeValue);
break;
}
default: {
llvm_unreachable("Unhandled existential type in ExistentialTransform!");
break;
}
};
GenericToOpenedTypeMap.insert(
std::pair<GenericTypeParamType *, Type>(iter->second, OpenedType));
assert(GenericToOpenedTypeMap.find(iter->second) !=
GenericToOpenedTypeMap.end());
} else {
ApplyArgs.push_back(ThunkBody->getArgument(ArgDesc.Index));
}
}
unsigned int OrigDepth = 0;
if (F->getLoweredFunctionType()->isPolymorphic()) {
OrigDepth = OrigCalleeGenericSig->getGenericParams().back()->getDepth() + 1;
}
SubstitutionMap OrigSubMap = F->getForwardingSubstitutionMap();
/// Create substitutions for Apply instructions.
auto SubMap = SubstitutionMap::get(
CalleeGenericSig,
[&](SubstitutableType *type) -> Type {
if (auto *GP = dyn_cast<GenericTypeParamType>(type)) {
if (GP->getDepth() < OrigDepth) {
return Type(GP).subst(OrigSubMap);
} else {
auto iter = GenericToOpenedTypeMap.find(GP);
assert(iter != GenericToOpenedTypeMap.end());
return iter->second;
}
} else {
return type;
}
},
MakeAbstractConformanceForGenericType());
/// Perform the substitutions.
auto SubstCalleeType = GenCalleeType->substGenericArgs(
M, SubMap, Builder.getTypeExpansionContext());
/// Obtain the Result Type.
SILValue ReturnValue;
auto FunctionTy = NewF->getLoweredFunctionType();
SILFunctionConventions Conv(SubstCalleeType, M);
SILType ResultType = Conv.getSILResultType();
/// If the original function has error results, we need to generate a
/// try_apply to call a function with an error result.
if (FunctionTy->hasErrorResult()) {
SILFunction *Thunk = ThunkBody->getParent();
SILBasicBlock *NormalBlock = Thunk->createBasicBlock();
ReturnValue =
NormalBlock->createPhiArgument(ResultType, ValueOwnershipKind::Owned);
SILBasicBlock *ErrorBlock = Thunk->createBasicBlock();
SILType Error = Conv.getSILType(FunctionTy->getErrorResult());
auto *ErrorArg =
ErrorBlock->createPhiArgument(Error, ValueOwnershipKind::Owned);
Builder.createTryApply(Loc, FRI, SubMap, ApplyArgs, NormalBlock,
ErrorBlock);
Builder.setInsertionPoint(ErrorBlock);
Builder.createThrow(Loc, ErrorArg);
Builder.setInsertionPoint(NormalBlock);
} else {
/// Create the Apply with substitutions
ReturnValue = Builder.createApply(Loc, FRI, SubMap, ApplyArgs);
}
auto cleanupLoc = RegularLocation::getAutoGeneratedLocation();
for (auto &Temp : llvm::reverse(Temps)) {
// The original argument was copied into a temporary and consumed by the
// callee as such:
// bb (%consumedExistential : $*Protocol)
// %valAdr = open_existential_addr %consumedExistential
// %temp = alloc_stack $T
// copy_addr %valAdr to %temp // <== Temp CopyAddr
// apply(%temp) // <== Temp is consumed by the apply
//
// Destroy the original arument and deallocation the temporary:
// destroy_addr %consumedExistential : $*Protocol
// dealloc_stack %temp : $*T
if (Temp.DestroyValue)
Builder.createDestroyAddr(cleanupLoc, Temp.DestroyValue);
if (Temp.DeallocStackEntry)
Builder.createDeallocStack(cleanupLoc, Temp.DeallocStackEntry);
}
/// Set up the return results.
if (NewF->isNoReturnFunction()) {
Builder.createUnreachable(Loc);
} else {
Builder.createReturn(Loc, ReturnValue);
}
}
/// Strategy to specialize existential arguments:
/// (1) Create a protocol constrained generic function from the old function;
/// (2) Create a thunk for the original function that invokes (1) including
/// setting
/// its inline strategy as always inline.
void ExistentialTransform::createExistentialSpecializedFunction() {
std::string Name = createExistentialSpecializedFunctionName();
SILLinkage linkage = getSpecializedLinkage(F, F->getLinkage());
/// Create devirtualized function type.
auto NewFTy = createExistentialSpecializedFunctionType();
auto NewFGenericSig = NewFTy->getInvocationGenericSignature();
auto NewFGenericEnv = NewFGenericSig->getGenericEnvironment();
/// Step 1: Create the new protocol constrained generic function.
NewF = FunctionBuilder.createFunction(
linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(),
F->isTransparent(), F->isSerialized(), IsNotDynamic, F->getEntryCount(),
F->isThunk(), F->getClassSubclassScope(), F->getInlineStrategy(),
F->getEffectsKind(), nullptr, F->getDebugScope());
/// Set the semantics attributes for the new function.
for (auto &Attr : F->getSemanticsAttrs())
NewF->addSemanticsAttr(Attr);
/// Set Unqualified ownership, if any.
if (!F->hasOwnership()) {
NewF->setOwnershipEliminated();
}
/// Step 1a: Populate the body of NewF.
SubstitutionMap Subs = SubstitutionMap::get(
NewFGenericSig,
[&](SubstitutableType *type) -> Type {
return NewFGenericEnv->mapTypeIntoContext(type);
},
LookUpConformanceInModule(F->getModule().getSwiftModule()));
ExistentialSpecializerCloner cloner(F, NewF, Subs, ArgumentDescList,
ArgToGenericTypeMap,
ExistentialArgDescriptor);
cloner.cloneAndPopulateFunction();
/// Step 2: Create the thunk with always_inline and populate its body.
populateThunkBody();
assert(F->getDebugScope()->Parent != NewF->getDebugScope()->Parent);
LLVM_DEBUG(llvm::dbgs() << "After ExistentialSpecializer Pass\n"; F->dump();
NewF->dump(););
}