@@ -630,88 +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 isNonEscapingUse (Operand *InitialOp,
638
- SmallVectorImpl<SILInstruction *> &Mutations) {
639
- llvm::SmallVector<Operand *, 32 > Worklist;
640
- Worklist.push_back (InitialOp);
633
+ namespace {
641
634
642
- while (!Worklist.empty ()) {
643
- auto *Op = Worklist.pop_back_val ();
644
- SILInstruction *User = Op->getUser ();
635
+ class NonEscapingUserVisitor
636
+ : public SILInstructionVisitor<NonEscapingUserVisitor, bool > {
637
+ llvm::SmallVector<Operand *, 32 > Worklist;
638
+ llvm::SmallVectorImpl<SILInstruction *> &Mutations;
639
+ NullablePtr<Operand> CurrentOp;
645
640
646
- if (User->isTypeDependentOperand (*Op))
647
- continue ;
641
+ public:
642
+ NonEscapingUserVisitor (Operand *Op,
643
+ llvm::SmallVectorImpl<SILInstruction *> &Mutations)
644
+ : Worklist(), Mutations(Mutations), CurrentOp() {
645
+ Worklist.push_back (Op);
646
+ }
648
647
649
- // Marking the boxed value as escaping is OK. It's just a DI annotation.
650
- if (isa<MarkFunctionEscapeInst>(User))
651
- continue ;
648
+ NonEscapingUserVisitor (const NonEscapingUserVisitor &) = delete ;
649
+ NonEscapingUserVisitor &operator =(const NonEscapingUserVisitor &) = delete ;
650
+ NonEscapingUserVisitor (NonEscapingUserVisitor &&) = delete ;
651
+ NonEscapingUserVisitor &operator =(NonEscapingUserVisitor &&) = delete ;
652
652
653
- // A store or assign is ok if the alloc_box is the destination.
654
- if (isa<StoreInst>(User) || isa<AssignInst>(User)) {
655
- if (Op->getOperandNumber () != 1 )
656
- return false ;
657
- Mutations.push_back (User);
658
- continue ;
659
- }
653
+ bool compute () {
654
+ while (!Worklist.empty ()) {
655
+ CurrentOp = Worklist.pop_back_val ();
656
+ SILInstruction *User = CurrentOp.get ()->getUser ();
660
657
661
- // copy_addr is ok, but counts as a mutation if the use is as the
662
- // destination or the copy_addr is a take.
663
- if (auto *CAI = dyn_cast<CopyAddrInst>(User)) {
664
- if (Op->getOperandNumber () == 1 || CAI->isTakeOfSrc ())
665
- Mutations.push_back (CAI);
666
- continue ;
667
- }
658
+ // Ignore type dependent operands.
659
+ if (User->isTypeDependentOperand (*(CurrentOp.get ())))
660
+ continue ;
668
661
669
- // Recursively see through struct_element_addr, tuple_element_addr, and
670
- // open_existential_addr instructions.
671
- if (isa<StructElementAddrInst>(User) || isa<TupleElementAddrInst>(User) ||
672
- isa<InitEnumDataAddrInst>(User) || isa<OpenExistentialAddrInst>(User) ||
673
- isa<UncheckedTakeEnumDataAddrInst>(User)) {
674
- // UncheckedTakeEnumDataAddr is additionally a mutation.
675
- if (isa<UncheckedTakeEnumDataAddrInst>(User))
676
- Mutations.push_back (User);
677
-
678
- for (auto *UserOperand : User->getUses ()) {
679
- Worklist.push_back (UserOperand);
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 ;
680
666
}
681
667
682
- continue ;
668
+ return false ;
683
669
}
684
670
685
- // An apply is ok if the argument is used as an inout parameter or an
686
- // indirect return, but counts as a possible mutation in both cases.
687
- if (auto *AI = dyn_cast<ApplyInst>(User)) {
688
- auto argIndex = Op->getOperandNumber () - 1 ;
689
- SILFunctionConventions substConv (AI->getSubstCalleeType (),
690
- AI->getModule ());
691
- auto convention = substConv.getSILArgumentConvention (argIndex);
692
- if (!convention.isIndirectConvention ()) {
693
- return false ;
694
- }
695
- Mutations.push_back (AI);
696
- continue ;
697
- }
671
+ return true ;
672
+ }
698
673
699
- // These instructions are ok but count as mutations.
700
- if (isa<DeallocBoxInst>(User)) {
701
- Mutations.push_back (User);
702
- continue ;
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 ; }
681
+ // Marking the boxed value as escaping is OK. It's just a DI annotation.
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);
691
+ return true ;
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 ()) {
699
+ return false ;
703
700
}
701
+ Mutations.push_back (AI);
702
+ return true ;
703
+ }
704
704
705
- // These remaining instructions are ok and don't count as mutations .
706
- if (isa<StrongRetainInst>(User) || isa<StrongReleaseInst>(User) ||
707
- isa<LoadInst>(User )) {
708
- continue ;
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
709
}
710
+ }
710
711
711
- return false ;
712
+ bool visitStructElementAddrInst (StructElementAddrInst *I) {
713
+ addUserOperandsToWorklist (I);
714
+ return true ;
712
715
}
713
716
714
- return true ;
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);
729
+ return true ;
730
+ }
731
+
732
+ bool visitUncheckedTakeEnumDataAddrInst (UncheckedTakeEnumDataAddrInst *I) {
733
+ // UncheckedTakeEnumDataAddr is additionally a mutation.
734
+ Mutations.push_back (I);
735
+
736
+ addUserOperandsToWorklist (I);
737
+ return true ;
738
+ }
739
+
740
+ bool visitCopyAddrInst (CopyAddrInst *CAI) {
741
+ if (CurrentOp.get ()->getOperandNumber () == 1 || CAI->isTakeOfSrc ())
742
+ Mutations.push_back (CAI);
743
+ return true ;
744
+ }
745
+
746
+ bool visitStoreInst (StoreInst *SI) {
747
+ if (CurrentOp.get ()->getOperandNumber () != 1 )
748
+ return false ;
749
+ Mutations.push_back (SI);
750
+ return true ;
751
+ }
752
+
753
+ bool visitAssignInst (AssignInst *AI) {
754
+ if (CurrentOp.get ()->getOperandNumber () != 1 )
755
+ return false ;
756
+ Mutations.push_back (AI);
757
+ return true ;
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 ();
715
770
}
716
771
717
772
// / \brief Examine an alloc_box instruction, returning true if at least one
0 commit comments