@@ -357,23 +357,19 @@ bool FunctionAccessStorage::summarizeFunction(SILFunction *F) {
357357 // conservative value, since analyzeInstruction will never be called.
358358 //
359359 // If FunctionSideEffects can be summarized, use that information.
360- FunctionSideEffects functionSideEffects;
361- if (!functionSideEffects.summarizeFunction (F)) {
360+
361+ auto b = F->getMemoryBehavior (/* observeRetains*/ false );
362+ if (b == SILInstruction::MemoryBehavior::MayHaveSideEffects) {
362363 setWorstEffects ();
363364 // May as well consider this a successful summary since there are no
364365 // instructions to visit anyway.
365366 return true ;
366367 }
367- bool mayRead = functionSideEffects.getGlobalEffects ().mayRead ();
368- bool mayWrite = functionSideEffects.getGlobalEffects ().mayWrite ();
369- for (auto ¶mEffects : functionSideEffects.getParameterEffects ()) {
370- mayRead |= paramEffects.mayRead ();
371- mayWrite |= paramEffects.mayWrite ();
372- }
373- if (mayWrite)
368+ if (b >= SILInstruction::MemoryBehavior::MayWrite) {
374369 accessResult.setUnidentifiedAccess (SILAccessKind::Modify);
375- else if (mayRead)
370+ } else if (b == SILInstruction::MemoryBehavior::MayRead) {
376371 accessResult.setUnidentifiedAccess (SILAccessKind::Read);
372+ }
377373
378374 // If function side effects is "readnone" then this result will have an empty
379375 // storageAccessSet and unidentifiedAccess == None.
@@ -393,6 +389,161 @@ bool FunctionAccessStorage::summarizeCall(FullApplySite fullApply) {
393389 return false ;
394390}
395391
392+ void AccessStorageAnalysis::initialize (
393+ SILPassManager *PM) {
394+ BCA = PM->getAnalysis <BasicCalleeAnalysis>();
395+ }
396+
397+ void AccessStorageAnalysis::invalidate () {
398+ functionInfoMap.clear ();
399+ allocator.DestroyAll ();
400+ LLVM_DEBUG (llvm::dbgs () << " invalidate all\n " );
401+ }
402+
403+ void AccessStorageAnalysis::invalidate (
404+ SILFunction *F, InvalidationKind K) {
405+ if (FunctionInfo *FInfo = functionInfoMap.lookup (F)) {
406+ LLVM_DEBUG (llvm::dbgs () << " invalidate " << FInfo->F ->getName () << ' \n ' );
407+ invalidateIncludingAllCallers (FInfo);
408+ }
409+ }
410+
411+ void AccessStorageAnalysis::getCalleeEffects (
412+ FunctionAccessStorage &calleeEffects, FullApplySite fullApply) {
413+ if (calleeEffects.summarizeCall (fullApply))
414+ return ;
415+
416+ auto callees = BCA->getCalleeList (fullApply);
417+ if (!callees.allCalleesVisible () ||
418+ // @callee_owned function calls implicitly release the context, which
419+ // may call deinits of boxed values.
420+ // TODO: be less conservative about what destructors might be called.
421+ fullApply.getOrigCalleeType ()->isCalleeConsumed ()) {
422+ calleeEffects.setWorstEffects ();
423+ return ;
424+ }
425+
426+ // We can see all the callees, so merge the effects from all of them.
427+ for (auto *callee : callees)
428+ calleeEffects.mergeFrom (getEffects (callee));
429+ }
430+
431+ void AccessStorageAnalysis::analyzeFunction (
432+ FunctionInfo *functionInfo, FunctionOrder &bottomUpOrder,
433+ int recursionDepth) {
434+ functionInfo->needUpdateCallers = true ;
435+
436+ if (bottomUpOrder.prepareForVisiting (functionInfo))
437+ return ;
438+
439+ auto *F = functionInfo->F ;
440+ if (functionInfo->functionEffects .summarizeFunction (F))
441+ return ;
442+
443+ LLVM_DEBUG (llvm::dbgs () << " >> analyze " << F->getName () << ' \n ' );
444+
445+ // Check all instructions of the function
446+ for (auto &BB : *F) {
447+ for (auto &I : BB) {
448+ if (auto fullApply = FullApplySite::isa (&I))
449+ analyzeCall (functionInfo, fullApply, bottomUpOrder, recursionDepth);
450+ else
451+ functionInfo->functionEffects .analyzeInstruction (&I);
452+ }
453+ }
454+ LLVM_DEBUG (llvm::dbgs () << " << finished " << F->getName () << ' \n ' );
455+ }
456+
457+ void AccessStorageAnalysis::analyzeCall (
458+ FunctionInfo *functionInfo, FullApplySite fullApply,
459+ FunctionOrder &bottomUpOrder, int recursionDepth) {
460+
461+ FunctionAccessStorage applyEffects;
462+ if (applyEffects.summarizeCall (fullApply)) {
463+ functionInfo->functionEffects .mergeFromApply (applyEffects, fullApply);
464+ return ;
465+ }
466+
467+ if (recursionDepth >= MaxRecursionDepth) {
468+ functionInfo->functionEffects .setWorstEffects ();
469+ return ;
470+ }
471+ CalleeList callees = BCA->getCalleeList (fullApply);
472+ if (!callees.allCalleesVisible () ||
473+ // @callee_owned function calls implicitly release the context, which
474+ // may call deinits of boxed values.
475+ // TODO: be less conservative about what destructors might be called.
476+ fullApply.getOrigCalleeType ()->isCalleeConsumed ()) {
477+ functionInfo->functionEffects .setWorstEffects ();
478+ return ;
479+ }
480+ // Derive the effects of the apply from the known callees.
481+ // Defer merging callee effects until the callee is scheduled
482+ for (SILFunction *callee : callees) {
483+ FunctionInfo *calleeInfo = getFunctionInfo (callee);
484+ calleeInfo->addCaller (functionInfo, fullApply);
485+ if (!calleeInfo->isVisited ()) {
486+ // Recursively visit the called function.
487+ analyzeFunction (calleeInfo, bottomUpOrder, recursionDepth + 1 );
488+ bottomUpOrder.tryToSchedule (calleeInfo);
489+ }
490+ }
491+ }
492+
493+ void AccessStorageAnalysis::recompute (
494+ FunctionInfo *initialInfo) {
495+ allocNewUpdateID ();
496+
497+ LLVM_DEBUG (llvm::dbgs () << " recompute function-effect analysis with UpdateID "
498+ << getCurrentUpdateID () << ' \n ' );
499+
500+ // Collect and analyze all functions to recompute, starting at initialInfo.
501+ FunctionOrder bottomUpOrder (getCurrentUpdateID ());
502+ analyzeFunction (initialInfo, bottomUpOrder, 0 );
503+
504+ // Build the bottom-up order.
505+ bottomUpOrder.tryToSchedule (initialInfo);
506+ bottomUpOrder.finishScheduling ();
507+
508+ // Second step: propagate the side-effect information up the call-graph until
509+ // it stabilizes.
510+ bool needAnotherIteration;
511+ do {
512+ LLVM_DEBUG (llvm::dbgs () << " new iteration\n " );
513+ needAnotherIteration = false ;
514+
515+ for (FunctionInfo *functionInfo : bottomUpOrder) {
516+ if (!functionInfo->needUpdateCallers )
517+ continue ;
518+
519+ LLVM_DEBUG (llvm::dbgs () << " update callers of "
520+ << functionInfo->F ->getName () << ' \n ' );
521+ functionInfo->needUpdateCallers = false ;
522+
523+ // Propagate the function effects to all callers.
524+ for (const auto &E : functionInfo->getCallers ()) {
525+ assert (E.isValid ());
526+
527+ // Only include callers which we are actually recomputing.
528+ if (!bottomUpOrder.wasRecomputedWithCurrentUpdateID (E.Caller ))
529+ continue ;
530+
531+ LLVM_DEBUG (llvm::dbgs () << " merge into caller "
532+ << E.Caller ->F ->getName () << ' \n ' );
533+
534+ if (E.Caller ->functionEffects .mergeFromApply (
535+ functionInfo->functionEffects , FullApplySite (E.FAS ))) {
536+ E.Caller ->needUpdateCallers = true ;
537+ if (!E.Caller ->isScheduledAfter (functionInfo)) {
538+ // This happens if we have a cycle in the call-graph.
539+ needAnotherIteration = true ;
540+ }
541+ }
542+ }
543+ }
544+ } while (needAnotherIteration);
545+ }
546+
396547SILAnalysis *swift::createAccessStorageAnalysis (SILModule *) {
397548 return new AccessStorageAnalysis ();
398549}
0 commit comments