/// Emit dealloc_stack for all temporaries. void PartialApplyCombiner::deallocateTemporaries() { // Insert dealloc_stack instructions at all function exit points. for (SILBasicBlock &BB : *PAI->getFunction()) { TermInst *Term = BB.getTerminator(); if (!Term->isFunctionExiting()) continue; for (auto Op : Tmps) { Builder.setInsertionPoint(Term); Builder.createDeallocStack(PAI->getLoc(), Op); } } }
/// Returns true on success. bool PartialApplyCombiner::allocateTemporaries() { // Copy the original arguments of the partial_apply into // newly created temporaries and use these temporaries instead of // the original arguments afterwards. // This is done to "extend" the life-time of original partial_apply // arguments, as they may be destroyed/deallocated before the last // use by one of the apply instructions. // TODO: // Copy arguments of the partial_apply into new temporaries // only if the lifetime of arguments ends before their uses // by apply instructions. bool needsReleases = false; CanSILFunctionType PAITy = dyn_cast<SILFunctionType>(PAI->getCallee()->getType().getSwiftType()); // Emit a destroy value for each captured closure argument. ArrayRef<SILParameterInfo> Params = PAITy->getParameters(); auto Args = PAI->getArguments(); unsigned Delta = Params.size() - Args.size(); llvm::SmallVector<std::pair<SILValue, unsigned>, 8> ArgsToHandle; for (unsigned AI = 0, AE = Args.size(); AI != AE; ++AI) { SILValue Arg = Args[AI]; SILParameterInfo Param = Params[AI + Delta]; if (Param.isIndirectMutating()) continue; // Create a temporary and copy the argument into it, if: // - the argument stems from an alloc_stack // - the argument is consumed by the callee and is indirect // (e.g. it is an @in argument) if (isa<AllocStackInst>(Arg) || (Param.isConsumed() && Param.isIndirect())) { // If the temporary is non-trivial, we need to release it later. if (!Arg->getType().isTrivial(PAI->getModule())) needsReleases = true; ArgsToHandle.push_back(std::make_pair(Arg, AI)); } } if (needsReleases) { // Compute the set of endpoints, which will be used to insert releases of // temporaries. This may fail if the frontier is located on a critical edge // which we may not split (no CFG changes in SILCombine). ValueLifetimeAnalysis VLA(PAI); if (!VLA.computeFrontier(PAFrontier, ValueLifetimeAnalysis::DontModifyCFG)) return false; } for (auto ArgWithIdx : ArgsToHandle) { SILValue Arg = ArgWithIdx.first; Builder.setInsertionPoint(PAI->getFunction()->begin()->begin()); // Create a new temporary at the beginning of a function. auto *Tmp = Builder.createAllocStack(PAI->getLoc(), Arg->getType(), {/*Constant*/ true, ArgWithIdx.second}); Builder.setInsertionPoint(PAI); // Copy argument into this temporary. Builder.createCopyAddr(PAI->getLoc(), Arg, Tmp, IsTake_t::IsNotTake, IsInitialization_t::IsInitialization); Tmps.push_back(Tmp); ArgToTmp.insert(std::make_pair(Arg, Tmp)); } return true; }