|
15 | 15 |
|
16 | 16 | #include "swift/Basic/Debug.h" |
17 | 17 | #include "swift/Basic/LLVM.h" |
| 18 | +#include "swift/Basic/NoDiscard.h" |
| 19 | +#include "swift/SIL/AddressWalker.h" |
18 | 20 | #include "swift/SIL/MemAccessUtils.h" |
19 | 21 | #include "swift/SIL/SILArgument.h" |
20 | 22 | #include "swift/SIL/SILBasicBlock.h" |
@@ -753,19 +755,65 @@ bool getAllBorrowIntroducingValues(SILValue value, |
753 | 755 | /// introducer, then we return a .some(BorrowScopeIntroducingValue). |
754 | 756 | BorrowedValue getSingleBorrowIntroducingValue(SILValue inputValue); |
755 | 757 |
|
756 | | -enum class AddressUseKind { NonEscaping, PointerEscape, Unknown }; |
757 | | - |
758 | | -inline AddressUseKind meet(AddressUseKind lhs, AddressUseKind rhs) { |
759 | | - return (lhs > rhs) ? lhs : rhs; |
760 | | -} |
761 | | - |
762 | 758 | /// The algorithm that is used to determine what the verifier will consider to |
763 | 759 | /// be transitive uses of the given address. Used to implement \see |
764 | 760 | /// findTransitiveUses. |
765 | | -AddressUseKind |
766 | | -findTransitiveUsesForAddress(SILValue address, |
767 | | - SmallVectorImpl<Operand *> *foundUses = nullptr, |
768 | | - std::function<void(Operand *)> *onError = nullptr); |
| 761 | +/// |
| 762 | +/// NOTE: Rather than return load_borrow as uses, this returns all of the |
| 763 | +/// transitive uses of the load_borrow as uses. This is important when working |
| 764 | +/// with this in OSSA. If one wishes to avoid this behavior, call find |
| 765 | +/// transitive uses for address with ones own visitor. |
| 766 | +inline AddressUseKind findTransitiveUsesForAddress( |
| 767 | + SILValue address, SmallVectorImpl<Operand *> *foundUses = nullptr, |
| 768 | + std::function<void(Operand *)> *onError = nullptr) { |
| 769 | + // This is a version of TransitiveUseVisitor that visits inner transitive |
| 770 | + // guaranteed uses to determine if a load_borrow is an escape in OSSA. This |
| 771 | + // is OSSA specific behavior and we should probably create a different API |
| 772 | + // for that. But for now, this lets this APIs users stay the same. |
| 773 | + struct BasicTransitiveAddressVisitor final : TransitiveAddressWalker { |
| 774 | + SmallVectorImpl<Operand *> *foundUses; |
| 775 | + std::function<void(Operand *)> *onErrorFunc; |
| 776 | + |
| 777 | + BasicTransitiveAddressVisitor(SmallVectorImpl<Operand *> *foundUses, |
| 778 | + std::function<void(Operand *)> *onErrorFunc) |
| 779 | + : foundUses(foundUses), onErrorFunc(onErrorFunc) {} |
| 780 | + |
| 781 | + bool visitUse(Operand *use) override { |
| 782 | + if (!foundUses) |
| 783 | + return true; |
| 784 | + |
| 785 | + if (auto *lbi = dyn_cast<LoadBorrowInst>(use->getUser())) { |
| 786 | + if (!findInnerTransitiveGuaranteedUses(lbi, foundUses)) { |
| 787 | + meet(AddressUseKind::PointerEscape); |
| 788 | + } |
| 789 | + return true; |
| 790 | + } |
| 791 | + |
| 792 | + // If we have a begin_apply, we want to use the token results if we have |
| 793 | + // any. If it doesn't have any token results, we just make our use the |
| 794 | + // begin_apply use itself below. |
| 795 | + if (auto *bai = dyn_cast<BeginApplyInst>(use->getUser())) { |
| 796 | + if (!bai->getTokenResult()->use_empty()) { |
| 797 | + for (auto *use : bai->getTokenResult()->getUses()) { |
| 798 | + foundUses->push_back(use); |
| 799 | + } |
| 800 | + return true; |
| 801 | + } |
| 802 | + } |
| 803 | + |
| 804 | + foundUses->push_back(use); |
| 805 | + return true; |
| 806 | + } |
| 807 | + |
| 808 | + void onError(Operand *use) override { |
| 809 | + if (onErrorFunc) |
| 810 | + (*onErrorFunc)(use); |
| 811 | + } |
| 812 | + }; |
| 813 | + |
| 814 | + BasicTransitiveAddressVisitor visitor(foundUses, onError); |
| 815 | + return std::move(visitor).walk(address); |
| 816 | +} |
769 | 817 |
|
770 | 818 | class InteriorPointerOperandKind { |
771 | 819 | public: |
|
0 commit comments