blob: a680bec395e1b80c1851f3df6c18ef09858d1397 [file] [log] [blame]
//===------- 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/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);
}
}
// Create the entry basic block with the function arguments.
void ExistentialSpecializerCloner::cloneArguments(
SmallVectorImpl<SILValue> &entryArgs) {
auto &M = OrigF->getModule();
auto &Ctx = M.getASTContext();
// 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].getType();
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.
SmallVector<ProtocolConformanceRef, 1> NewConformances;
auto ContextTy = NewF.mapTypeIntoContext(GenericParam);
auto OpenedArchetype = ContextTy->castTo<ArchetypeType>();
for (auto proto : OpenedArchetype->getConformsTo()) {
NewConformances.push_back(ProtocolConformanceRef(proto));
}
ArrayRef<ProtocolConformanceRef> Conformances =
Ctx.AllocateCopy(NewConformances);
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->getGenericSignature();
/// 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.getType();
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->getGenericSignature();
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->getWitnessMethodConformanceOrNone();
/// Return the new signature.
return SILFunctionType::get(
NewGenericSig, ExtInfo, FTy->getCoroutineKind(),
FTy->getCalleeConvention(), InterfaceParams, FTy->getYields(),
FTy->getResults(), InterfaceErrorResult, 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->getGenericSignature();
auto OrigGenCalleeType = F->getLoweredFunctionType();
auto OrigCalleeGenericSig = OrigGenCalleeType->getGenericSignature();
/// 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);
/// 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->getGenericSignature();
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(););
}