/// Specialize a partial_apply by promoting the parameters indicated by /// indices. We expect these parameters to be replaced by stack address /// references. static PartialApplyInst * specializePartialApply(PartialApplyInst *PartialApply, ArgIndexList &PromotedArgIndices, bool &CFGChanged) { auto *FRI = cast<FunctionRefInst>(PartialApply->getCallee()); assert(FRI && "Expected a direct partial_apply!"); auto *F = FRI->getReferencedFunction(); assert(F && "Expected a referenced function!"); IsSerialized_t Serialized = IsNotSerialized; if (PartialApply->getFunction()->isSerialized()) Serialized = IsSerializable; std::string ClonedName = getClonedName(F, Serialized, PromotedArgIndices); auto &M = PartialApply->getModule(); SILFunction *ClonedFn; if (auto *PrevFn = M.lookUpFunction(ClonedName)) { assert(PrevFn->isSerialized() == Serialized); ClonedFn = PrevFn; } else { // Clone the function the existing partial_apply references. PromotedParamCloner Cloner(F, Serialized, PromotedArgIndices, ClonedName); Cloner.populateCloned(); ClonedFn = Cloner.getCloned(); } // Now create the new partial_apply using the cloned function. llvm::SmallVector<SILValue, 16> Args; ValueLifetimeAnalysis::Frontier PAFrontier; // Promote the arguments that need promotion. for (auto &O : PartialApply->getArgumentOperands()) { auto ArgIndex = getArgIndexForOperand(&O); if (!count(PromotedArgIndices, ArgIndex)) { Args.push_back(O.get()); continue; } // If this argument is promoted, it is a box that we're turning into an // address because we've proven we can keep this value on the stack. The // partial_apply had ownership of this box so we must now release it // explicitly when the partial_apply is released. auto *Box = cast<SingleValueInstruction>(O.get()); assert((isa<AllocBoxInst>(Box) || isa<CopyValueInst>(Box)) && "Expected either an alloc box or a copy of an alloc box"); SILBuilder B(Box); Args.push_back(B.createProjectBox(Box->getLoc(), Box, 0)); if (PAFrontier.empty()) { ValueLifetimeAnalysis VLA(PartialApply); CFGChanged |= !VLA.computeFrontier(PAFrontier, ValueLifetimeAnalysis::AllowToModifyCFG); assert(!PAFrontier.empty() && "partial_apply must have at least one use " "to release the returned function"); } // Insert destroys of the box at each point where the partial_apply becomes // dead. for (SILInstruction *FrontierInst : PAFrontier) { SILBuilderWithScope Builder(FrontierInst); Builder.createDestroyValue(PartialApply->getLoc(), Box); } } SILBuilderWithScope Builder(PartialApply); // Build the function_ref and partial_apply. SILValue FunctionRef = Builder.createFunctionRef(PartialApply->getLoc(), ClonedFn); return Builder.createPartialApply( PartialApply->getLoc(), FunctionRef, PartialApply->getSubstitutions(), Args, PartialApply->getType().getAs<SILFunctionType>()->getCalleeConvention()); }
/// Specialize a partial_apply by promoting the parameters indicated by /// indices. We expect these parameters to be replaced by stack address /// references. static PartialApplyInst * specializePartialApply(PartialApplyInst *PartialApply, ParamIndexList &PromotedParamIndices, bool &CFGChanged) { auto *FRI = cast<FunctionRefInst>(PartialApply->getCallee()); assert(FRI && "Expected a direct partial_apply!"); auto *F = FRI->getReferencedFunction(); assert(F && "Expected a referenced function!"); std::string ClonedName = getClonedName(F, PromotedParamIndices); auto &M = PartialApply->getModule(); SILFunction *ClonedFn; if (auto *PrevFn = M.lookUpFunction(ClonedName)) { ClonedFn = PrevFn; } else { // Clone the function the existing partial_apply references. PromotedParamCloner Cloner(F, PromotedParamIndices, ClonedName); Cloner.populateCloned(); ClonedFn = Cloner.getCloned(); } // Now create the new partial_apply using the cloned function. llvm::SmallVector<SILValue, 16> Args; ValueLifetimeAnalysis::Frontier PAFrontier; // Promote the arguments that need promotion. for (auto &O : PartialApply->getArgumentOperands()) { auto ParamIndex = getParameterIndexForOperand(&O); if (!std::count(PromotedParamIndices.begin(), PromotedParamIndices.end(), ParamIndex)) { Args.push_back(O.get()); continue; } // If this argument is promoted, it is a box that we're // turning into an address because we've proven we can // keep this value on the stack. The partial_apply had ownership // of this box so we must now release it explicitly when the // partial_apply is released. auto box = cast<AllocBoxInst>(O.get()); // If the box address has a MUI, route accesses through it so DI still // works. SILInstruction *promoted = nullptr; int numAddrUses = 0; for (Operand *BoxUse : box->getUses()) { if (auto *PBI = dyn_cast<ProjectBoxInst>(BoxUse->getUser())) { for (auto PBIUse : PBI->getUses()) { numAddrUses++; if (auto MUI = dyn_cast<MarkUninitializedInst>(PBIUse->getUser())) promoted = MUI; } } } assert((!promoted || numAddrUses == 1) && "box value used by mark_uninitialized but not exclusively!"); // We only reuse an existing project_box if it directly follows the // alloc_box. This makes sure that the project_box dominates the // partial_apply. if (!promoted) promoted = getOrCreateProjectBox(box); Args.push_back(promoted); if (PAFrontier.empty()) { ValueLifetimeAnalysis VLA(PartialApply); CFGChanged |= !VLA.computeFrontier(PAFrontier, ValueLifetimeAnalysis::AllowToModifyCFG); assert(!PAFrontier.empty() && "partial_apply must have at least one use " "to release the returned function"); } // Insert releases after each point where the partial_apply becomes dead. for (SILInstruction *FrontierInst : PAFrontier) { SILBuilderWithScope Builder(FrontierInst); Builder.emitStrongReleaseAndFold(PartialApply->getLoc(), O.get()); } } SILBuilderWithScope Builder(PartialApply); // Build the function_ref and partial_apply. SILValue FunctionRef = Builder.createFunctionRef(PartialApply->getLoc(), ClonedFn); CanSILFunctionType CanFnTy = ClonedFn->getLoweredFunctionType(); auto const &Subs = PartialApply->getSubstitutions(); CanSILFunctionType SubstCalleeTy = CanFnTy->substGenericArgs(M, M.getSwiftModule(), Subs); return Builder.createPartialApply(PartialApply->getLoc(), FunctionRef, SILType::getPrimitiveObjectType(SubstCalleeTy), PartialApply->getSubstitutions(), Args, PartialApply->getType()); }