/// ----------------------------------------------------------/// /// Argument Explosion transformation. /// /// ----------------------------------------------------------/// bool FunctionSignatureTransform::ArgumentExplosionAnalyzeParameters() { // Did we decide we should optimize any parameter? bool SignatureOptimize = false; auto Args = F->begin()->getFunctionArguments(); ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(RCIA->get(F), F); // Analyze the argument information. for (unsigned i = 0, e = Args.size(); i != e; ++i) { ArgumentDescriptor &A = ArgumentDescList[i]; // Do not optimize argument. if (!A.canOptimizeLiveArg()) { continue; } A.ProjTree.computeUsesAndLiveness(A.Arg); A.Explode = A.shouldExplode(ArgToReturnReleaseMap); // Modified self argument. if (A.Explode && Args[i]->isSelf()) { shouldModifySelfArgument = true; } SignatureOptimize |= A.Explode; } return SignatureOptimize; }
/// ----------------------------------------------------------/// /// Owned to Guaranteed transformation. /// /// ----------------------------------------------------------/// bool FunctionSignatureTransform::OwnedToGuaranteedAnalyzeParameters() { auto Args = F->begin()->getFunctionArguments(); // A map from consumed SILArguments to the release associated with an // argument. // // TODO: The return block and throw block should really be abstracted away. ConsumedArgToEpilogueReleaseMatcher ArgToReturnReleaseMap(RCIA->get(F), F); ConsumedArgToEpilogueReleaseMatcher ArgToThrowReleaseMap( RCIA->get(F), F, ConsumedArgToEpilogueReleaseMatcher::ExitKind::Throw); // Did we decide we should optimize any parameter? bool SignatureOptimize = false; // Analyze the argument information. for (unsigned i = 0, e = Args.size(); i != e; ++i) { ArgumentDescriptor &A = ArgumentDescList[i]; if (!A.canOptimizeLiveArg()) { continue; } // See if we can find a ref count equivalent strong_release or release_value // at the end of this function if our argument is an @owned parameter. if (A.hasConvention(SILArgumentConvention::Direct_Owned)) { auto Releases = ArgToReturnReleaseMap.getReleasesForArgument(A.Arg); if (!Releases.empty()) { // If the function has a throw block we must also find a matching // release in the throw block. auto ReleasesInThrow = ArgToThrowReleaseMap.getReleasesForArgument(A.Arg); if (!ArgToThrowReleaseMap.hasBlock() || !ReleasesInThrow.empty()) { A.CalleeRelease = Releases; A.CalleeReleaseInThrowBlock = ReleasesInThrow; // We can convert this parameter to a @guaranteed. A.OwnedToGuaranteed = true; SignatureOptimize = true; } } } // Modified self argument. if (A.OwnedToGuaranteed && Args[i]->isSelf()) { shouldModifySelfArgument = true; } } return SignatureOptimize; }
bool FunctionSignatureTransform::OwnedToGuaranteedAnalyzeResults() { auto FTy = F->getLoweredFunctionType(); // For now, only do anything if there's a single direct result. if (FTy->getDirectResults().size() != 1) return false; bool SignatureOptimize = false; if (ResultDescList[0].hasConvention(ResultConvention::Owned)) { auto &RI = ResultDescList[0]; // We have an @owned return value, find the epilogue retains now. ConsumedResultToEpilogueRetainMatcher ReturnRetainMap(RCIA->get(F), AA, F); auto Retains = ReturnRetainMap.getEpilogueRetains(); // We do not need to worry about the throw block, as the return value is only // going to be used in the return block/normal block of the try_apply // instruction. if (!Retains.empty()) { RI.CalleeRetain = Retains; SignatureOptimize = true; RI.OwnedToGuaranteed = true; } } return SignatureOptimize; }