ApplySite SILPerformanceInliner::specializeGeneric( ApplySite Apply, llvm::SmallVectorImpl<ApplySite> &NewApplies) { assert(NewApplies.empty() && "Expected out parameter for new applies!"); if (!Apply.hasSubstitutions()) return ApplySite(); auto *Callee = Apply.getCalleeFunction(); if (!Callee || Callee->isExternalDeclaration()) return ApplySite(); auto Filter = [](SILInstruction *I) -> bool { return ApplySite::isa(I) != ApplySite(); }; CloneCollector Collector(Filter); SILFunction *SpecializedFunction; auto Specialized = trySpecializeApplyOfGeneric(Apply, SpecializedFunction, Collector); if (!Specialized) return ApplySite(); // Track the new applies from the specialization. for (auto NewCallSite : Collector.getInstructionPairs()) NewApplies.push_back(ApplySite(NewCallSite.first)); auto FullApply = FullApplySite::isa(Apply.getInstruction()); if (!FullApply) { assert(!FullApplySite::isa(Specialized.getInstruction()) && "Unexpected full apply generated!"); // Replace the old apply with the new and delete the old. replaceDeadApply(Apply, Specialized.getInstruction()); return ApplySite(Specialized); } // Replace the old apply with the new and delete the old. replaceDeadApply(Apply, Specialized.getInstruction()); return Specialized; }
/// For each argument in the range of the callee arguments being applied at the /// given apply site, use the summary analysis to determine whether the /// arguments will be accessed in a way that conflicts with any currently in /// progress accesses. If so, diagnose. static void checkCaptureAccess(ApplySite Apply, AccessState &State) { SILFunction *Callee = Apply.getCalleeFunction(); if (!Callee || Callee->empty()) return; const AccessSummaryAnalysis::FunctionSummary &FS = State.ASA->getOrCreateSummary(Callee); for (unsigned ArgumentIndex : range(Apply.getNumArguments())) { unsigned CalleeIndex = Apply.getCalleeArgIndexOfFirstAppliedArg() + ArgumentIndex; const AccessSummaryAnalysis::ArgumentSummary &AS = FS.getAccessForArgument(CalleeIndex); const auto &SubAccesses = AS.getSubAccesses(); // Is the capture accessed in the callee? if (SubAccesses.empty()) continue; SILValue Argument = Apply.getArgument(ArgumentIndex); assert(Argument->getType().isAddress()); // A valid AccessedStorage should alway sbe found because Unsafe accesses // are not tracked by AccessSummaryAnalysis. const AccessedStorage &Storage = findValidAccessedStorage(Argument); auto AccessIt = State.Accesses->find(Storage); // Are there any accesses in progress at the time of the call? if (AccessIt == State.Accesses->end()) continue; const AccessInfo &Info = AccessIt->getSecond(); if (auto Conflict = findConflictingArgumentAccess(AS, Storage, Info)) State.ConflictingAccesses.push_back(*Conflict); } }
bool GenericSpecializer::specializeAppliesInFunction(SILFunction &F) { bool Changed = false; llvm::SmallVector<SILInstruction *, 8> DeadApplies; for (auto &BB : F) { for (auto It = BB.begin(), End = BB.end(); It != End;) { auto &I = *It++; // Skip non-apply instructions, apply instructions with no // substitutions, apply instructions where we do not statically // know the called function, and apply instructions where we do // not have the body of the called function. ApplySite Apply = ApplySite::isa(&I); if (!Apply || !Apply.hasSubstitutions()) continue; auto *Callee = Apply.getCalleeFunction(); if (!Callee || !Callee->isDefinition()) continue; // We have a call that can potentially be specialized, so // attempt to do so. // The specializer helper function currently expects a collector // argument, but we aren't going to make use of the results so // we'll have our filter always return false; auto Filter = [](SILInstruction *I) -> bool { return false; }; CloneCollector Collector(Filter); SILFunction *SpecializedFunction; auto Specialized = trySpecializeApplyOfGeneric(Apply, SpecializedFunction, Collector); if (Specialized) { Changed = true; // If calling the specialization utility resulted in a new // function (as opposed to returning a previous // specialization), we need to notify the pass manager so that // the new function gets optimized. if (SpecializedFunction) notifyPassManagerOfFunction(SpecializedFunction); auto *AI = Apply.getInstruction(); if (!isa<TryApplyInst>(AI)) AI->replaceAllUsesWith(Specialized.getInstruction()); DeadApplies.push_back(AI); } } } // Remove all the now-dead applies. while (!DeadApplies.empty()) { auto *AI = DeadApplies.pop_back_val(); recursivelyDeleteTriviallyDeadInstructions(AI, true); } return Changed; }