@@ -630,69 +630,143 @@ isNonMutatingCapture(SILArgument *BoxArg) {
630
630
return true ;
631
631
}
632
632
633
- // / \brief Given a use of an alloc_box instruction, return true if the use
634
- // / definitely does not allow the box to escape; also, if the use is an
635
- // / instruction which possibly mutates the contents of the box, then add it to
636
- // / the Mutations vector.
637
- static bool
638
- isNonEscapingUse (Operand *O, SmallVectorImpl<SILInstruction*> &Mutations) {
639
- auto *U = O->getUser ();
640
- if (U->isTypeDependentOperand (*O))
633
+ namespace {
634
+
635
+ class NonEscapingUserVisitor
636
+ : public SILInstructionVisitor<NonEscapingUserVisitor, bool > {
637
+ llvm::SmallVector<Operand *, 32 > Worklist;
638
+ llvm::SmallVectorImpl<SILInstruction *> &Mutations;
639
+ NullablePtr<Operand> CurrentOp;
640
+
641
+ public:
642
+ NonEscapingUserVisitor (Operand *Op,
643
+ llvm::SmallVectorImpl<SILInstruction *> &Mutations)
644
+ : Worklist(), Mutations(Mutations), CurrentOp() {
645
+ Worklist.push_back (Op);
646
+ }
647
+
648
+ NonEscapingUserVisitor (const NonEscapingUserVisitor &) = delete ;
649
+ NonEscapingUserVisitor &operator =(const NonEscapingUserVisitor &) = delete ;
650
+ NonEscapingUserVisitor (NonEscapingUserVisitor &&) = delete ;
651
+ NonEscapingUserVisitor &operator =(NonEscapingUserVisitor &&) = delete ;
652
+
653
+ bool compute () {
654
+ while (!Worklist.empty ()) {
655
+ CurrentOp = Worklist.pop_back_val ();
656
+ SILInstruction *User = CurrentOp.get ()->getUser ();
657
+
658
+ // Ignore type dependent operands.
659
+ if (User->isTypeDependentOperand (*(CurrentOp.get ())))
660
+ continue ;
661
+
662
+ // Then visit the specific user. This routine returns true if the value
663
+ // does not escape. In such a case, continue.
664
+ if (visit (User)) {
665
+ continue ;
666
+ }
667
+
668
+ return false ;
669
+ }
670
+
641
671
return true ;
672
+ }
673
+
674
+ // / Visit a random value base.
675
+ // /
676
+ // / These are considered to be escapes.
677
+ bool visitValueBase (ValueBase *V) { return false ; }
678
+
679
+ #define ALWAYS_NON_ESCAPING_INST (INST ) \
680
+ bool visit##INST##Inst(INST##Inst *V) { return true ; }
642
681
// Marking the boxed value as escaping is OK. It's just a DI annotation.
643
- if (isa<MarkFunctionEscapeInst>(U))
682
+ ALWAYS_NON_ESCAPING_INST (MarkFunctionEscape)
683
+ // These remaining instructions are ok and don't count as mutations.
684
+ ALWAYS_NON_ESCAPING_INST (StrongRetain)
685
+ ALWAYS_NON_ESCAPING_INST (Load)
686
+ ALWAYS_NON_ESCAPING_INST (StrongRelease)
687
+ #undef ALWAYS_NON_ESCAPING_INST
688
+
689
+ bool visitDeallocBoxInst (DeallocBoxInst *DBI) {
690
+ Mutations.push_back (DBI);
644
691
return true ;
645
-
646
- // A store or assign is ok if the alloc_box is the destination.
647
- if (isa<StoreInst>(U) || isa<AssignInst>(U)) {
648
- if (O->getOperandNumber () != 1 )
692
+ }
693
+
694
+ bool visitApplyInst (ApplyInst *AI) {
695
+ auto argIndex = CurrentOp.get ()->getOperandNumber () - 1 ;
696
+ SILFunctionConventions substConv (AI->getSubstCalleeType (), AI->getModule ());
697
+ auto convention = substConv.getSILArgumentConvention (argIndex);
698
+ if (!convention.isIndirectConvention ()) {
649
699
return false ;
650
- Mutations.push_back (cast<SILInstruction>(U));
700
+ }
701
+ Mutations.push_back (AI);
651
702
return true ;
652
703
}
653
- // copy_addr is ok, but counts as a mutation if the use is as the
654
- // destination or the copy_addr is a take.
655
- if (auto *CAI = dyn_cast<CopyAddrInst>(U)) {
656
- if (O->getOperandNumber () == 1 || CAI->isTakeOfSrc ())
657
- Mutations.push_back (CAI);
704
+
705
+ // / Add the Operands of a transitive use instruction to the worklist.
706
+ void addUserOperandsToWorklist (SILInstruction *I) {
707
+ for (auto *User : I->getUses ()) {
708
+ Worklist.push_back (User);
709
+ }
710
+ }
711
+
712
+ bool visitStructElementAddrInst (StructElementAddrInst *I) {
713
+ addUserOperandsToWorklist (I);
714
+ return true ;
715
+ }
716
+
717
+ bool visitTupleElementAddrInst (TupleElementAddrInst *I) {
718
+ addUserOperandsToWorklist (I);
719
+ return true ;
720
+ }
721
+
722
+ bool visitInitEnumDataAddrInst (InitEnumDataAddrInst *I) {
723
+ addUserOperandsToWorklist (I);
724
+ return true ;
725
+ }
726
+
727
+ bool visitOpenExistentialAddrInst (OpenExistentialAddrInst *I) {
728
+ addUserOperandsToWorklist (I);
658
729
return true ;
659
730
}
660
- // Recursively see through struct_element_addr, tuple_element_addr, and
661
- // open_existential_addr instructions.
662
- if (isa<StructElementAddrInst>(U) || isa<TupleElementAddrInst>(U) ||
663
- isa<InitEnumDataAddrInst>(U) ||
664
- isa<OpenExistentialAddrInst>(U) || isa<UncheckedTakeEnumDataAddrInst>(U)) {
731
+
732
+ bool visitUncheckedTakeEnumDataAddrInst (UncheckedTakeEnumDataAddrInst *I) {
665
733
// UncheckedTakeEnumDataAddr is additionally a mutation.
666
- if (isa<UncheckedTakeEnumDataAddrInst>(U))
667
- Mutations.push_back (U);
668
-
669
- for (auto *UO : U->getUses ())
670
- if (!isNonEscapingUse (UO, Mutations))
671
- return false ;
734
+ Mutations.push_back (I);
735
+
736
+ addUserOperandsToWorklist (I);
672
737
return true ;
673
738
}
674
- // An apply is ok if the argument is used as an inout parameter or an
675
- // indirect return, but counts as a possible mutation in both cases.
676
- if (auto *AI = dyn_cast<ApplyInst>(U)) {
677
- auto argIndex = O->getOperandNumber ()-1 ;
678
- SILFunctionConventions substConv (AI->getSubstCalleeType (), AI->getModule ());
679
- auto convention = substConv.getSILArgumentConvention (argIndex);
680
- if (convention.isIndirectConvention ()) {
681
- Mutations.push_back (AI);
682
- return true ;
683
- }
684
- return false ;
739
+
740
+ bool visitCopyAddrInst (CopyAddrInst *CAI) {
741
+ if (CurrentOp.get ()->getOperandNumber () == 1 || CAI->isTakeOfSrc ())
742
+ Mutations.push_back (CAI);
743
+ return true ;
685
744
}
686
- // These instructions are ok but count as mutations.
687
- if (isa<DeallocBoxInst>(U)) {
688
- Mutations.push_back (cast<SILInstruction>(U));
745
+
746
+ bool visitStoreInst (StoreInst *SI) {
747
+ if (CurrentOp.get ()->getOperandNumber () != 1 )
748
+ return false ;
749
+ Mutations.push_back (SI);
689
750
return true ;
690
751
}
691
- // These remaining instructions are ok and don't count as mutations.
692
- if (isa<StrongRetainInst>(U) || isa<StrongReleaseInst>(U) ||
693
- isa<LoadInst>(U))
752
+
753
+ bool visitAssignInst (AssignInst *AI) {
754
+ if (CurrentOp.get ()->getOperandNumber () != 1 )
755
+ return false ;
756
+ Mutations.push_back (AI);
694
757
return true ;
695
- return false ;
758
+ }
759
+ };
760
+
761
+ } // end anonymous namespace
762
+
763
+ // / \brief Given a use of an alloc_box instruction, return true if the use
764
+ // / definitely does not allow the box to escape; also, if the use is an
765
+ // / instruction which possibly mutates the contents of the box, then add it to
766
+ // / the Mutations vector.
767
+ static bool isNonEscapingUse (Operand *InitialOp,
768
+ SmallVectorImpl<SILInstruction *> &Mutations) {
769
+ return NonEscapingUserVisitor (InitialOp, Mutations).compute ();
696
770
}
697
771
698
772
// / \brief Examine an alloc_box instruction, returning true if at least one
0 commit comments