@@ -357,23 +357,19 @@ bool FunctionAccessStorage::summarizeFunction(SILFunction *F) {
357
357
// conservative value, since analyzeInstruction will never be called.
358
358
//
359
359
// 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) {
362
363
setWorstEffects ();
363
364
// May as well consider this a successful summary since there are no
364
365
// instructions to visit anyway.
365
366
return true ;
366
367
}
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) {
374
369
accessResult.setUnidentifiedAccess (SILAccessKind::Modify);
375
- else if (mayRead)
370
+ } else if (b == SILInstruction::MemoryBehavior::MayRead) {
376
371
accessResult.setUnidentifiedAccess (SILAccessKind::Read);
372
+ }
377
373
378
374
// If function side effects is "readnone" then this result will have an empty
379
375
// storageAccessSet and unidentifiedAccess == None.
@@ -393,6 +389,161 @@ bool FunctionAccessStorage::summarizeCall(FullApplySite fullApply) {
393
389
return false ;
394
390
}
395
391
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
+
396
547
SILAnalysis *swift::createAccessStorageAnalysis (SILModule *) {
397
548
return new AccessStorageAnalysis ();
398
549
}
0 commit comments