36
36
#include " swift/SIL/SILFunction.h"
37
37
#include " swift/SIL/SILUndef.h"
38
38
#include " swift/SILOptimizer/Analysis/ClosureScope.h"
39
+ #include " swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
39
40
#include " swift/SILOptimizer/PassManager/Transforms.h"
40
41
41
42
using namespace swift ;
@@ -68,7 +69,6 @@ struct AddressCapture {
68
69
69
70
AddressCapture (Operand &oper)
70
71
: site(oper.getUser()), calleeArgIdx(site.getCalleeArgIndex(oper)) {
71
- assert (isa<PartialApplyInst>(site));
72
72
if (site.getOrigCalleeConv ().getSILArgumentConvention (calleeArgIdx)
73
73
!= SILArgumentConvention::Indirect_InoutAliasable) {
74
74
site = ApplySite ();
@@ -272,8 +272,16 @@ void SelectEnforcement::analyzeProjection(ProjectBoxInst *projection) {
272
272
273
273
continue ;
274
274
}
275
- if (isa<PartialApplyInst>(user))
276
- Captures.emplace_back (AddressCapture (*use));
275
+ // Handle both partial applies and directly applied non-escaping closures.
276
+ if (ApplySite::isa (user)) {
277
+ AddressCapture capture (*use);
278
+ if (capture.isValid ())
279
+ Captures.emplace_back (capture);
280
+ else
281
+ // Only full apply sites can have non-inout_aliasable address arguments,
282
+ // but those aren't actually captures.
283
+ assert (FullApplySite::isa (user));
284
+ }
277
285
}
278
286
}
279
287
@@ -463,6 +471,13 @@ void SelectEnforcement::updateCapture(AddressCapture capture) {
463
471
if (hasPotentiallyEscapedAt (user))
464
472
dynamicCaptures.recordCapture (capture);
465
473
};
474
+ SingleValueInstruction *PAIUser = dyn_cast<PartialApplyInst>(capture.site );
475
+ if (!PAIUser) {
476
+ // This is a full apply site. Immediately record the capture and return.
477
+ captureIfEscaped (capture.site .getInstruction ());
478
+ return ;
479
+ }
480
+ // For partial applies, check all use points of the closure.
466
481
llvm::SmallSetVector<SingleValueInstruction *, 8 > worklist;
467
482
auto visitUse = [&](Operand *oper) {
468
483
auto *user = oper->getUser ();
@@ -513,7 +528,6 @@ void SelectEnforcement::updateCapture(AddressCapture capture) {
513
528
captureIfEscaped (user);
514
529
}
515
530
};
516
- SingleValueInstruction *PAIUser = dyn_cast<PartialApplyInst>(capture.site );
517
531
while (true ) {
518
532
for (auto *oper : PAIUser->getUses ())
519
533
visitUse (oper);
@@ -553,11 +567,10 @@ class AccessEnforcementSelection : public SILModuleTransform {
553
567
// they reference.
554
568
DynamicCaptures dynamicCaptures;
555
569
556
- // Per-function book-keeping. A box is processed the first time one of it's
557
- // accesses is handled. Don't process it again for subsequent accesses.
558
- llvm::DenseSet<AllocBoxInst *> handledBoxes;
559
-
560
570
#ifndef NDEBUG
571
+ // Per-function book-keeping to verify that a box is processed before all of
572
+ // its accesses and captures are seen.
573
+ llvm::DenseSet<AllocBoxInst *> handledBoxes;
561
574
llvm::DenseSet<SILFunction *> visited;
562
575
#endif
563
576
@@ -568,7 +581,7 @@ class AccessEnforcementSelection : public SILModuleTransform {
568
581
void processFunction (SILFunction *F);
569
582
SourceAccess getAccessKindForBox (ProjectBoxInst *projection);
570
583
SourceAccess getSourceAccess (SILValue address);
571
- void handlePartialApply (PartialApplyInst *PAI );
584
+ void handleApply (ApplySite apply );
572
585
void handleAccess (BeginAccessInst *access);
573
586
};
574
587
@@ -580,6 +593,9 @@ void AccessEnforcementSelection::run() {
580
593
}
581
594
582
595
void AccessEnforcementSelection::processFunction (SILFunction *F) {
596
+ if (F->isExternalDeclaration ())
597
+ return ;
598
+
583
599
LLVM_DEBUG (llvm::dbgs () << " Access Enforcement Selection in " << F->getName ()
584
600
<< " \n " );
585
601
@@ -599,29 +615,43 @@ void AccessEnforcementSelection::processFunction(SILFunction *F) {
599
615
}
600
616
visited.insert (F);
601
617
#endif
618
+
602
619
// Deserialized functions, which have been mandatory inlined, no longer meet
603
620
// the structural requirements on access markers required by this pass.
604
621
if (F->wasDeserializedCanonical ())
605
622
return ;
606
623
607
- for (auto &bb : *F) {
608
- for (auto ii = bb.begin (), ie = bb.end (); ii != ie;) {
624
+ // Perform an RPO walk so that boxes are always processed before their access.
625
+ auto *PO = getAnalysis<PostOrderAnalysis>()->get (F);
626
+ for (SILBasicBlock *bb : PO->getReversePostOrder ()) {
627
+ for (auto ii = bb->begin (), ie = bb->end (); ii != ie;) {
609
628
SILInstruction *inst = &*ii;
610
629
++ii;
611
630
612
- if (auto access = dyn_cast<BeginAccessInst>(inst))
631
+ // Analyze all boxes. Even if they aren't accessed in this function, they
632
+ // may still have captures that require dynamic enforcement because the
633
+ // box has escaped prior to the capture.
634
+ if (auto box = dyn_cast<AllocBoxInst>(inst)) {
635
+ SelectEnforcement (dynamicCaptures, box).run ();
636
+ assert (handledBoxes.insert (box).second );
637
+
638
+ } else if (auto access = dyn_cast<BeginAccessInst>(inst))
613
639
handleAccess (access);
614
640
615
641
else if (auto access = dyn_cast<BeginUnpairedAccessInst>(inst))
616
642
assert (access->getEnforcement () == SILAccessEnforcement::Dynamic);
617
643
618
- else if (auto pa = dyn_cast<PartialApplyInst>(inst))
619
- handlePartialApply (pa);
644
+ // Check for unboxed captures in both partial_applies and direct
645
+ // applications of non-escaping closures.
646
+ else if (auto apply = ApplySite::isa (inst))
647
+ handleApply (apply);
620
648
}
621
649
}
622
650
invalidateAnalysis (F, SILAnalysis::InvalidationKind::Instructions);
651
+ #ifndef NDEBUG
623
652
// There's no need to track handled boxes across functions.
624
653
handledBoxes.clear ();
654
+ #endif
625
655
}
626
656
627
657
SourceAccess
@@ -690,19 +720,17 @@ SourceAccess AccessEnforcementSelection::getSourceAccess(SILValue address) {
690
720
return SourceAccess::getStaticAccess ();
691
721
}
692
722
693
- void AccessEnforcementSelection::handlePartialApply (PartialApplyInst *PAI) {
694
- ApplySite site (PAI);
695
- auto calleeTy = PAI->getOrigCalleeType ();
723
+ void AccessEnforcementSelection::handleApply (ApplySite apply) {
724
+ auto calleeTy = apply.getOrigCalleeType ();
696
725
SILFunctionConventions calleeConv (calleeTy, *getModule ());
697
726
698
- for (Operand &oper : site .getArgumentOperands ()) {
727
+ for (Operand &oper : apply .getArgumentOperands ()) {
699
728
AddressCapture capture (oper);
700
729
if (!capture.isValid ())
701
730
continue ;
702
731
703
- // This partial apply creates a non-escaping closure. Check if the closure
704
- // captures any Boxed variables from this scope. If so, check if the box
705
- // escapes before the access just as we do for normal accesses.
732
+ // This is a non-escaping closure argument. If the argument requires dynamic
733
+ // access, record that in dynamicCaptures.
706
734
auto sourceAccess = getSourceAccess (oper.get ());
707
735
switch (sourceAccess.kind ) {
708
736
case SourceAccess::StaticAccess:
@@ -714,8 +742,11 @@ void AccessEnforcementSelection::handlePartialApply(PartialApplyInst *PAI) {
714
742
break ;
715
743
}
716
744
case SourceAccess::BoxAccess:
717
- if (handledBoxes.insert (sourceAccess.allocBox ).second )
718
- SelectEnforcement (dynamicCaptures, sourceAccess.allocBox ).run ();
745
+ // Captures of box projections are handled during SelectEnforcement, which
746
+ // determines the access enforcement for all users of a box. Within
747
+ // SelectEnforcement, we know whether the box has escaped before the
748
+ // capture. Here there's just nothing to do.
749
+ assert (handledBoxes.count (sourceAccess.allocBox ));
719
750
break ;
720
751
}
721
752
}
@@ -734,10 +765,7 @@ void AccessEnforcementSelection::handleAccess(BeginAccessInst *access) {
734
765
setDynamicEnforcement (access);
735
766
break ;
736
767
case SourceAccess::BoxAccess:
737
- // If this box was handled, the access enforcement would already be set.
738
- assert (!handledBoxes.count (sourceAccess.allocBox ));
739
- SelectEnforcement (dynamicCaptures, sourceAccess.allocBox ).run ();
740
- break ;
768
+ llvm_unreachable (" All boxes must have already been selected." );
741
769
}
742
770
}
743
771
0 commit comments