static bool verifySILSelfParameterType(SILDeclRef DeclRef, SILFunction *F, CanSILFunctionType FTy) { SILModule &M = F->getModule(); SILParameterInfo PInfo = FTy->getSelfParameter(); CanType CTy = PInfo.getType(); SILType Ty = SILType::getPrimitiveObjectType(CTy); // We do not care about trivial parameters (for now). There seem to be // cases where we lower them as unowned. // // *NOTE* We do not run this check when we have a generic type since // *generic types do not have type lowering and are always treated as // *non-trivial since we do not know the type. if (CTy->hasArchetype() || CTy->hasTypeParameter() || M.getTypeLowering(Ty).isTrivial()) return true; // If this function is a constructor or destructor, bail. These have @owned // parameters. if (DeclRef.isConstructor() || DeclRef.isDestructor()) return true; // Otherwise, if this function type has a guaranteed self parameter type, // make sure that we have a +0 self param. return !FTy->getExtInfo().hasGuaranteedSelfParam() || PInfo.isGuaranteed() || PInfo.isIndirectMutating(); }
void SILCombiner::eraseApply(FullApplySite FAS, const UserListTy &Users) { // Make sure to release and destroy any owned or in-arguments. auto FuncType = FAS.getOrigCalleeType(); assert(FuncType->getParameters().size() == FAS.getNumArguments() && "mismatching number of arguments"); for (int i = 0, e = FAS.getNumArguments(); i < e; ++i) { SILParameterInfo PI = FuncType->getParameters()[i]; auto Arg = FAS.getArgument(i); switch (PI.getConvention()) { case ParameterConvention::Indirect_In: Builder.createDestroyAddr(FAS.getLoc(), Arg); break; case ParameterConvention::Direct_Owned: Builder.createReleaseValue(FAS.getLoc(), Arg, Atomicity::Atomic); break; case ParameterConvention::Indirect_In_Guaranteed: case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: case ParameterConvention::Direct_Unowned: case ParameterConvention::Direct_Deallocating: case ParameterConvention::Direct_Guaranteed: break; } } // Erase all of the reference counting instructions (in reverse order to have // no dangling uses). for (auto rit = Users.rbegin(), re = Users.rend(); rit != re; ++rit) eraseInstFromFunction(**rit); // And the Apply itself. eraseInstFromFunction(*FAS.getInstruction()); }
clang::CanQualType IRGenModule::getClangType(SILParameterInfo params) { auto clangType = getClangType(params.getSILType()); // @block_storage types must be @inout_aliasable and have // special lowering if (!params.getSILType().is<SILBlockStorageType>()) { if (params.isIndirectMutating()) { return getClangASTContext().getPointerType(clangType); } if (params.isIndirect()) { auto constTy = getClangASTContext().getCanonicalType(clangType.withConst()); return getClangASTContext().getPointerType(constTy); } } return clangType; }
/// 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; }
void ClosureSpecializer::gatherCallSites( SILFunction *Caller, llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates, llvm::DenseSet<FullApplySite> &MultipleClosureAI) { // A set of apply inst that we have associated with a closure. We use this to // make sure that we do not handle call sites with multiple closure arguments. llvm::DenseSet<FullApplySite> VisitedAI; // For each basic block BB in Caller... for (auto &BB : *Caller) { // For each instruction II in BB... for (auto &II : BB) { // If II is not a closure that we support specializing, skip it... if (!isSupportedClosure(&II)) continue; ClosureInfo *CInfo = nullptr; // Go through all uses of our closure. for (auto *Use : II.getUses()) { // If this use is not an apply inst or an apply inst with // substitutions, there is nothing interesting for us to do, so // continue... auto AI = FullApplySite::isa(Use->getUser()); if (!AI || AI.hasSubstitutions()) continue; // Check if we have already associated this apply inst with a closure to // be specialized. We do not handle applies that take in multiple // closures at this time. if (!VisitedAI.insert(AI).second) { MultipleClosureAI.insert(AI); continue; } // If AI does not have a function_ref definition as its callee, we can // not do anything here... so continue... SILFunction *ApplyCallee = AI.getReferencedFunction(); if (!ApplyCallee || ApplyCallee->isExternalDeclaration()) continue; // Ok, we know that we can perform the optimization but not whether or // not the optimization is profitable. Find the index of the argument // corresponding to our partial apply. Optional<unsigned> ClosureIndex; for (unsigned i = 0, e = AI.getNumArguments(); i != e; ++i) { if (AI.getArgument(i) != SILValue(&II)) continue; ClosureIndex = i; DEBUG(llvm::dbgs() << " Found callsite with closure argument at " << i << ": " << *AI.getInstruction()); break; } // If we did not find an index, there is nothing further to do, // continue. if (!ClosureIndex.hasValue()) continue; // Make sure that the Closure is invoked in the Apply's callee. We only // want to perform closure specialization if we know that we will be // able to change a partial_apply into an apply. // // TODO: Maybe just call the function directly instead of moving the // partial apply? SILValue Arg = ApplyCallee->getArgument(ClosureIndex.getValue()); if (std::none_of(Arg->use_begin(), Arg->use_end(), [&Arg](Operand *Op) -> bool { auto UserAI = FullApplySite::isa(Op->getUser()); return UserAI && UserAI.getCallee() == Arg; })) { continue; } auto NumIndirectResults = AI.getSubstCalleeType()->getNumIndirectResults(); assert(ClosureIndex.getValue() >= NumIndirectResults); auto ClosureParamIndex = ClosureIndex.getValue() - NumIndirectResults; auto ParamInfo = AI.getSubstCalleeType()->getParameters(); SILParameterInfo ClosureParamInfo = ParamInfo[ClosureParamIndex]; // Get all non-failure exit BBs in the Apply Callee if our partial apply // is guaranteed. If we do not understand one of the exit BBs, bail. // // We need this to make sure that we insert a release in the appropriate // locations to balance the +1 from the creation of the partial apply. llvm::TinyPtrVector<SILBasicBlock *> NonFailureExitBBs; if (ClosureParamInfo.isGuaranteed() && !findAllNonFailureExitBBs(ApplyCallee, NonFailureExitBBs)) { continue; } // Compute the final release points of the closure. We will insert // release of the captured arguments here. if (!CInfo) { CInfo = new ClosureInfo(&II); ValueLifetimeAnalysis VLA(CInfo->Closure); VLA.computeFrontier(CInfo->LifetimeFrontier, ValueLifetimeAnalysis::AllowToModifyCFG); } // Now we know that CSDesc is profitable to specialize. Add it to our // call site list. CInfo->CallSites.push_back( CallSiteDescriptor(CInfo, AI, ClosureIndex.getValue(), ClosureParamInfo, std::move(NonFailureExitBBs))); } if (CInfo) ClosureCandidates.push_back(CInfo); } } }