/// Return true if it's both legal and a good idea to explode this argument. static bool shouldExplode(ArgumentDescriptor &argDesc, ConsumedArgToEpilogueReleaseMatcher &ERM) { // We cannot optimize the argument. if (!argDesc.canOptimizeLiveArg()) return false; // See if the projection tree consists of potentially multiple levels of // structs containing one field. In such a case, there is no point in // exploding the argument. // // Also, in case of a type can not be exploded, e.g an enum, we treat it // as a singleton. if (argDesc.ProjTree.isSingleton()) return false; auto *arg = argDesc.Arg; if (!shouldExpand(arg->getModule(), arg->getType().getObjectType())) { return false; } // If this argument is @owned and we can not find all the releases for it // try to explode it, maybe we can find some of the releases and O2G some // of its components. // // This is a potentially a very profitable optimization. Ignore other // heuristics. if (arg->hasConvention(SILArgumentConvention::Direct_Owned) && ERM.hasSomeReleasesForArgument(arg)) return true; unsigned explosionSize = argDesc.ProjTree.getLiveLeafCount(); return explosionSize >= 1 && explosionSize <= 3; }
/// Compute what the function interface will look like based on the /// optimization we are doing on the given argument descriptor. Default /// implementation simply passes it through. void FunctionSignatureTransform:: computeOptimizedArgInterface(ArgumentDescriptor &AD, SILParameterInfoList &Out) { // If this argument is live, but we cannot optimize it. if (!AD.canOptimizeLiveArg()) { Out.push_back(AD.PInfo); return; } // If we have a dead argument, bail. if (AD.IsEntirelyDead) { ++NumDeadArgsEliminated; return; } // Explode the argument or not ? if (AD.Explode) { ++NumSROAArguments; llvm::SmallVector<const ProjectionTreeNode*, 8> LeafNodes; AD.ProjTree.getLeafNodes(LeafNodes); for (auto Node : LeafNodes) { SILType Ty = Node->getType(); DEBUG(llvm::dbgs() << " " << Ty << "\n"); // If Ty is trivial, just pass it directly. if (Ty.isTrivial(AD.Arg->getModule())) { SILParameterInfo NewInfo(Ty.getSwiftRValueType(), ParameterConvention::Direct_Unowned); Out.push_back(NewInfo); continue; } // Ty is not trivial, pass it through as the original calling convention. SILParameterInfo NewInfo(Ty.getSwiftRValueType(), AD.OwnedToGuaranteed ? ParameterConvention::Direct_Guaranteed : AD.PInfo.getConvention()); Out.push_back(NewInfo); } return; } // If we cannot explode this value, handle callee release and return. // If we found releases in the callee in the last BB on an @owned // parameter, change the parameter to @guaranteed and continue... if (AD.OwnedToGuaranteed) { ++NumOwnedConvertedToGuaranteed; SILParameterInfo NewInfo(AD.PInfo.getType(), ParameterConvention::Direct_Guaranteed); Out.push_back(NewInfo); return; } // Otherwise just propagate through the parameter info. Out.push_back(AD.PInfo); }