text: //===------- 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, NewF.getTypeExpansionContext());
        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, ArgDesc.Decl);
      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, F->getTypeExpansionContext());
      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;
  
    /// 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());
  
    /// 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(), SubstitutionMap(),
        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(Builder.getTypeExpansionContext());
  
    /// 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(),
                                      Builder.getTypeExpansionContext());
      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.getTypeExpansionContext())) {
      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(););
  }
  