15
15
16
16
#include " swift/Basic/Debug.h"
17
17
#include " swift/Basic/LLVM.h"
18
+ #include " swift/SIL/MemAccessUtils.h"
18
19
#include " swift/SIL/SILArgument.h"
19
- #include " swift/SIL/SILInstruction.h"
20
20
#include " swift/SIL/SILBasicBlock.h"
21
+ #include " swift/SIL/SILInstruction.h"
21
22
#include " swift/SIL/SILValue.h"
22
23
#include " llvm/ADT/SmallPtrSet.h"
23
24
#include " llvm/ADT/SmallVector.h"
@@ -29,6 +30,7 @@ class SILInstruction;
29
30
class SILModule ;
30
31
class SILValue ;
31
32
class DeadEndBlocks ;
33
+ class PrunedLiveness ;
32
34
33
35
// / Returns true if v is an address or trivial.
34
36
bool isValueAddressOrTrivial (SILValue v);
@@ -148,7 +150,7 @@ bool findTransitiveGuaranteedUses(SILValue guaranteedValue,
148
150
// / 1. If \p guaranteedValue introduces a borrow scope (begin_borrow,
149
151
// / load_borrow, or phi), then its only use points are the extended scope-ending
150
152
// / uses, and this function returns true. This is, in fact, equivalent to
151
- // / calling BorrowedValue::visitExtendedLocalScopeEndingUses ().
153
+ // / calling BorrowedValue::visitExtendedScopeEndingUses ().
152
154
// /
153
155
// / 2. If \p guaranteedValue does not introduce a borrow scope (it is not a
154
156
// / valid BorrowedValue), then its uses are discovered transitively by looking
@@ -172,8 +174,8 @@ class ForwardingOperand {
172
174
return use->getOwnershipConstraint ();
173
175
}
174
176
175
- ValueOwnershipKind getOwnershipKind () const ;
176
- void setOwnershipKind (ValueOwnershipKind newKind) const ;
177
+ ValueOwnershipKind getForwardingOwnershipKind () const ;
178
+ void setForwardingOwnershipKind (ValueOwnershipKind newKind) const ;
177
179
void replaceOwnershipKind (ValueOwnershipKind oldKind,
178
180
ValueOwnershipKind newKind) const ;
179
181
@@ -304,13 +306,20 @@ struct BorrowingOperand {
304
306
// / visits the end of the introduced borrow scope.
305
307
bool visitScopeEndingUses (function_ref<bool (Operand *)> func) const ;
306
308
309
+ // / Returns true for borrows that create a local borrow scope but have no
310
+ // / scope-ending uses (presumably all paths are dead-end blocks). This does
311
+ // / not include instantaneous borrows, which don't require explicit scope
312
+ // / ending uses.
313
+ // /
314
+ // / FIXME: Borrow scopes should have scope-ending uses on all paths, even to
315
+ // / dead end blocks. When the verifier enforces this, remove this check.
316
+ bool hasEmptyRequiredEndingUses () const ;
317
+
307
318
// / Visit the scope ending operands of the extended scope, after transitively
308
319
// / searching through reborrows. These uses might not be dominated by this
309
320
// / BorrowingOperand.
310
321
// /
311
322
// / Returns false and early exits if the visitor \p func returns false.
312
- // /
313
- // / Note: this does not visit the intermediate reborrows.
314
323
bool visitExtendedScopeEndingUses (function_ref<bool (Operand *)> func) const ;
315
324
316
325
// / Returns true if this borrow scope operand consumes guaranteed
@@ -493,7 +502,7 @@ struct InteriorPointerOperand;
493
502
// / jointly post-dominate this value (see visitLocalScopeEndingUses()). The
494
503
// / extended scope, including reborrows has end points that are not dominated by
495
504
// / this value but still jointly post-dominate (see
496
- // / visitExtendedLocalScopeEndingUses ()).
505
+ // / visitExtendedScopeEndingUses ()).
497
506
struct BorrowedValue {
498
507
SILValue value;
499
508
BorrowedValueKind kind = BorrowedValueKind::Invalid;
@@ -535,20 +544,25 @@ struct BorrowedValue {
535
544
536
545
bool isLocalScope () const { return kind.isLocalScope (); }
537
546
538
- // / Returns true if the passed in set of uses is completely within
539
- // / the lifetime of this borrow introducer.
547
+ // / Add this scopes live blocks into the PrunedLiveness result.
548
+ void computeLiveness (PrunedLiveness &liveness) const ;
549
+
550
+ // / Returns true if \p uses are completely within this borrow introducer's
551
+ // / local scope.
540
552
// /
541
- // / NOTE: Scratch space is used internally to this method to store the end
542
- // / borrow scopes if needed.
543
- bool areUsesWithinScope (ArrayRef<Operand *> uses,
544
- SmallVectorImpl<Operand *> &scratchSpace,
545
- DeadEndBlocks &deadEndBlocks) const ;
553
+ // / Precondition: \p uses are dominated by the local borrow introducer.
554
+ // /
555
+ // / This ignores reborrows. The assumption is that, since \p uses are
556
+ // / dominated by this local scope, checking the extended borrow scope should
557
+ // / not be necessary to determine they are within the scope.
558
+ bool areUsesWithinLocalScope (ArrayRef<Operand *> uses,
559
+ DeadEndBlocks &deadEndBlocks) const ;
546
560
547
561
// / Given a local borrow scope introducer, visit all non-forwarding consuming
548
562
// / users. This means that this looks through guaranteed block arguments. \p
549
563
// / visitor is *not* called on Reborrows, only on final scope ending uses.
550
- bool visitExtendedLocalScopeEndingUses (
551
- function_ref<bool (Operand *)> visitor) const ;
564
+ bool
565
+ visitExtendedScopeEndingUses ( function_ref<bool (Operand *)> visitor) const ;
552
566
553
567
void print (llvm::raw_ostream &os) const ;
554
568
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
@@ -583,6 +597,14 @@ struct BorrowedValue {
583
597
func, InteriorPointerOperandVisitorKind::YesNestedYesReborrows);
584
598
}
585
599
600
+ bool hasReborrow () const {
601
+ for (auto *op : value->getUses ()) {
602
+ if (op->getOperandOwnership () == OperandOwnership::Reborrow)
603
+ return true ;
604
+ }
605
+ return false ;
606
+ }
607
+
586
608
// / Visit all immediate uses of this borrowed value and if any of them are
587
609
// / reborrows, place them in BorrowingOperand form into \p
588
610
// / foundReborrows. Returns true if we appended any such reborrows to
@@ -591,12 +613,10 @@ struct BorrowedValue {
591
613
&foundReborrows) const {
592
614
bool foundAnyReborrows = false ;
593
615
for (auto *op : value->getUses ()) {
594
- if (auto borrowingOperand = BorrowingOperand (op)) {
595
- if (borrowingOperand.isReborrow ()) {
596
- foundReborrows.push_back (
597
- {value->getParentBlock (), op->getOperandNumber ()});
598
- foundAnyReborrows = true ;
599
- }
616
+ if (op->getOperandOwnership () == OperandOwnership::Reborrow) {
617
+ foundReborrows.push_back (
618
+ {value->getParentBlock (), op->getOperandNumber ()});
619
+ foundAnyReborrows = true ;
600
620
}
601
621
}
602
622
return foundAnyReborrows;
@@ -642,6 +662,13 @@ bool getAllBorrowIntroducingValues(SILValue value,
642
662
// / introducer, then we return a .some(BorrowScopeIntroducingValue).
643
663
BorrowedValue getSingleBorrowIntroducingValue (SILValue inputValue);
644
664
665
+ // / The algorithm that is used to determine what the verifier will consider to
666
+ // / be transitive uses of the given address. Used to implement \see
667
+ // / findTransitiveUses.
668
+ bool findTransitiveUsesForAddress (
669
+ SILValue address, SmallVectorImpl<Operand *> &foundUses,
670
+ std::function<void (Operand *)> *onError = nullptr);
671
+
645
672
class InteriorPointerOperandKind {
646
673
public:
647
674
enum Kind : uint8_t {
@@ -785,7 +812,7 @@ struct InteriorPointerOperand {
785
812
}
786
813
787
814
// / Return the base BorrowedValue of the incoming value's operand.
788
- BorrowedValue getSingleBaseValue () const {
815
+ BorrowedValue getSingleBorrowedValue () const {
789
816
return getSingleBorrowIntroducingValue (operand->get ());
790
817
}
791
818
@@ -820,14 +847,6 @@ struct InteriorPointerOperand {
820
847
onError);
821
848
}
822
849
823
- // / The algorithm that is used to determine what the verifier will consider to
824
- // / be transitive uses of the given address. Used to implement \see
825
- // / findTransitiveUses.
826
- static bool
827
- findTransitiveUsesForAddress (SILValue address,
828
- SmallVectorImpl<Operand *> &foundUses,
829
- std::function<void (Operand *)> *onError = nullptr );
830
-
831
850
Operand *operator ->() { return operand; }
832
851
const Operand *operator ->() const { return operand; }
833
852
Operand *operator *() { return operand; }
@@ -840,23 +859,70 @@ struct InteriorPointerOperand {
840
859
: operand(op), kind(kind) {}
841
860
};
842
861
843
- // / Utility to check if an address may originate from a borrowed value. If so,
862
+ // / Utility to check if an address may originate from an OSSA value. If so,
844
863
// / then uses of the address cannot be replaced without ensuring that they are
845
- // / also within the same scope.
864
+ // / also within the same owned lifetime or borrow scope.
846
865
// /
847
- // / If mayBeBorrowed is false, then there is no enclosing borrow scope and
848
- // / interiorPointerOp is irrelevant.
866
+ // / If hasOwnership() is false, then there is no enclosing lifetime or borrow
867
+ // / scope and interiorPointerOp is irrelevant.
849
868
// /
850
- // / If mayBeBorrowed is true, then interiorPointerOp refers to the operand that
869
+ // / If hasOwnership() is true, then interiorPointerOp refers to the operand that
851
870
// / converts a non-address value into the address from which the contructor's
852
871
// / address is derived. If the best-effort to find an InteriorPointerOperand
853
872
// / fails, then interiorPointerOp remains invalid, and clients must be
854
873
// / conservative.
855
- struct BorrowedAddress {
856
- bool mayBeBorrowed = true ;
857
- InteriorPointerOperand interiorPointerOp;
874
+ // /
875
+ // / TODO: Handle implicit borrow scopes once they are legal in SIL. The operand
876
+ // / of the base will be owned but mayBeBorrowed will remain true.
877
+ struct AddressOwnership {
878
+ AccessBase base;
879
+
880
+ AddressOwnership () = default ;
881
+
882
+ AddressOwnership (SILValue address) : base(AccessBase::compute(address)) {
883
+ assert (address->getType ().isAddress ());
884
+ }
885
+
886
+ AddressOwnership (AccessBase base) : base(base) {}
887
+
888
+ operator bool () const { return bool (base); }
889
+
890
+ bool operator ==(const AddressOwnership &other) const {
891
+ return base.hasIdenticalAccessInfo (other.base );
892
+ }
893
+
894
+ bool operator !=(const AddressOwnership &other) const {
895
+ return !(*this == other);
896
+ }
858
897
859
- BorrowedAddress (SILValue address);
898
+ // / Return true if this address may be derived from a value with a local OSSA
899
+ // / lifetime or borrow scope.
900
+ bool hasLocalOwnershipLifetime () const {
901
+ return base.hasLocalOwnershipLifetime ();
902
+ }
903
+
904
+ // / Return the OSSA value from which this address is derived. This may be
905
+ // / invalid even if hasOSSALifetime() is true in cases where the
906
+ // / InteriorPointerOperand is unrecognized.
907
+ SILValue getOwnershipReferenceRoot () const {
908
+ if (base.isReference ())
909
+ return base.getOwnershipReferenceRoot ();
910
+
911
+ return SILValue ();
912
+ }
913
+
914
+ // / Transitively compute uses of this base address.
915
+ bool findTransitiveUses (SmallVectorImpl<Operand *> &foundUses) {
916
+ return findTransitiveUsesForAddress (base.getBaseAddress (), foundUses);
917
+ }
918
+
919
+ // / Return true of all \p uses occur before the end of the address' lifetime
920
+ // / or borrow scope.
921
+ // /
922
+ // / Precondition: all \p uses are dominated by the beginning of the address'
923
+ // / lifetime or borrow scope.
924
+ bool areUsesWithinLifetime (ArrayRef<Operand *> uses,
925
+ DeadEndBlocks &deadEndBlocks) const ;
860
926
};
861
927
862
928
class OwnedValueIntroducerKind {
0 commit comments