Skip to content

Commit a6cb545

Browse files
committed
Add a tiny BorrowedAddress utility.
Determines whether an address might be inside a borrowed scope. If so, then any address substitution needs to find that scope boundary to avoid violating its basic guarantee that all uses are within scope.
1 parent 1f64871 commit a6cb545

File tree

5 files changed

+73
-39
lines changed

5 files changed

+73
-39
lines changed

include/swift/SIL/InstructionUtils.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ SILValue getUnderlyingObject(SILValue V);
2727

2828
SILValue getUnderlyingObjectStopAtMarkDependence(SILValue V);
2929

30-
/// Given an address look through address to address projections and indexing
31-
/// insts.
32-
SILValue getUnderlyingObjectStoppingAtObjectToAddrProjections(SILValue v);
33-
3430
SILValue stripSinglePredecessorArgs(SILValue V);
3531

3632
/// Return the underlying SILValue after stripping off all casts from the

include/swift/SIL/OwnershipUtils.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,8 @@ struct InteriorPointerOperand {
727727
return kind != InteriorPointerOperandKind::Invalid && operand;
728728
}
729729

730+
SILInstruction *getUser() const { return operand->getUser(); }
731+
730732
/// If \p op has a user that is an interior pointer, return a valid
731733
/// value. Otherwise, return None.
732734
static InteriorPointerOperand get(Operand *op) {
@@ -835,6 +837,25 @@ struct InteriorPointerOperand {
835837
: operand(op), kind(kind) {}
836838
};
837839

840+
/// Utility to check if an address may originate from a borrowed value. If so,
841+
/// then uses of the address cannot be replaced without ensuring that they are
842+
/// also within the same scope.
843+
///
844+
/// If mayBeBorrowed is false, then there is no enclosing borrow scope and
845+
/// interiorPointerOp is irrelevant.
846+
///
847+
/// If mayBeBorrowed is true, then interiorPointerOp refers to the operand that
848+
/// converts a non-address value into the address from which the contructor's
849+
/// address is derived. If the best-effort to find an InteriorPointerOperand
850+
/// fails, then interiorPointerOp remains invalid, and clients must be
851+
/// conservative.
852+
struct BorrowedAddress {
853+
bool mayBeBorrowed = true;
854+
InteriorPointerOperand interiorPointerOp;
855+
856+
BorrowedAddress(SILValue address);
857+
};
858+
838859
class OwnedValueIntroducerKind {
839860
public:
840861
enum Kind : uint8_t {

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,6 @@ SILValue swift::getUnderlyingObject(SILValue v) {
6262
}
6363
}
6464

65-
SILValue
66-
swift::getUnderlyingObjectStoppingAtObjectToAddrProjections(SILValue v) {
67-
if (!v->getType().isAddress())
68-
return SILValue();
69-
70-
while (true) {
71-
auto v2 = lookThroughAddressToAddressProjections(v);
72-
v2 = stripIndexingInsts(v2);
73-
if (v2 == v)
74-
return v2;
75-
v = v2;
76-
}
77-
}
78-
7965
SILValue swift::getUnderlyingObjectStopAtMarkDependence(SILValue v) {
8066
while (true) {
8167
SILValue v2 = stripCastsWithoutMarkDependence(v);

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "swift/SIL/InstructionUtils.h"
1717
#include "swift/SIL/LinearLifetimeChecker.h"
1818
#include "swift/SIL/Projection.h"
19+
#include "swift/SIL/MemAccessUtils.h"
1920
#include "swift/SIL/SILArgument.h"
2021
#include "swift/SIL/SILInstruction.h"
2122

@@ -787,6 +788,46 @@ bool InteriorPointerOperand::findTransitiveUsesForAddress(
787788
return foundError;
788789
}
789790

791+
// Determine whether \p address may be in a borrow scope and if so record the
792+
// InteriorPointerOperand that produces the address from a guaranteed value.
793+
BorrowedAddress::BorrowedAddress(SILValue address) {
794+
assert(address->getType().isAddress());
795+
796+
auto storageWithBase = AccessedStorageWithBase::compute(address);
797+
switch (storageWithBase.storage.getKind()) {
798+
case AccessedStorage::Argument:
799+
case AccessedStorage::Stack:
800+
case AccessedStorage::Global:
801+
// Unidentified storage is from an "escaped pointer", so it need not be
802+
// restricted to a borrow scope.
803+
case AccessedStorage::Unidentified:
804+
this->mayBeBorrowed = false;
805+
return;
806+
case AccessedStorage::Box:
807+
case AccessedStorage::Yield:
808+
case AccessedStorage::Class:
809+
case AccessedStorage::Tail:
810+
// The base object might be within a borrow scope.
811+
break;
812+
case AccessedStorage::Nested:
813+
llvm_unreachable("unexpected storage");
814+
};
815+
auto base = storageWithBase.base;
816+
if (!base)
817+
return; // bail on unexpected patterns
818+
819+
auto intPtrOp = InteriorPointerOperand::inferFromResult(base);
820+
if (!intPtrOp)
821+
return;
822+
823+
SILValue nonAddressValue = intPtrOp.operand->get();
824+
if (nonAddressValue->getOwnershipKind() != OwnershipKind::Guaranteed) {
825+
this->mayBeBorrowed = false;
826+
return;
827+
}
828+
this->interiorPointerOp = intPtrOp;
829+
}
830+
790831
//===----------------------------------------------------------------------===//
791832
// Owned Value Introducers
792833
//===----------------------------------------------------------------------===//

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -903,41 +903,31 @@ OwnershipRAUWHelper::OwnershipRAUWHelper(OwnershipFixupContext &inputCtx,
903903
//
904904
// NOTE: We also need to handle this here since a pointer_to_address is not a
905905
// valid base value for an access path since it doesn't refer to any storage.
906-
{
907-
auto baseProj =
908-
getUnderlyingObjectStoppingAtObjectToAddrProjections(newValue);
909-
if (isa<PointerToAddressInst>(baseProj)) {
910-
return;
911-
}
912-
}
906+
BorrowedAddress borrowedAddress(newValue);
907+
if (!borrowedAddress.mayBeBorrowed)
908+
return;
913909

914-
auto accessPathWithBase = AccessPathWithBase::compute(newValue);
915-
if (!accessPathWithBase.base) {
910+
if (!borrowedAddress.interiorPointerOp) {
916911
// Invalidate!
917912
ctx = nullptr;
918913
return;
919914
}
920915

921-
auto &intPtr = ctx->extraAddressFixupInfo.intPtrOp;
922-
intPtr = InteriorPointerOperand::inferFromResult(accessPathWithBase.base);
923-
if (!intPtr) {
924-
// We can optimize! Do not invalidate!
925-
return;
926-
}
927-
928-
auto borrowedValue = intPtr.getSingleBaseValue();
916+
ctx->extraAddressFixupInfo.intPtrOp = borrowedAddress.interiorPointerOp;
917+
auto borrowedValue = borrowedAddress.interiorPointerOp.getSingleBaseValue();
929918
if (!borrowedValue) {
930919
// Invalidate!
931920
ctx = nullptr;
932921
return;
933922
}
934923

935-
// This cloner check must match the later cloner invocation in
936-
// replaceAddressUses()
937-
auto *intPtrUser = cast<SingleValueInstruction>(intPtr->getUser());
924+
auto *intPtrInst =
925+
cast<SingleValueInstruction>(borrowedAddress.interiorPointerOp.getUser());
938926
auto checkBase = [&](SILValue srcAddr) {
939-
return (srcAddr == intPtrUser) ? SILValue(intPtrUser) : SILValue();
927+
return (srcAddr == intPtrInst) ? SILValue(intPtrInst) : SILValue();
940928
};
929+
// This cloner check must match the later cloner invocation in
930+
// replaceAddressUses()
941931
if (!canCloneUseDefChain(newValue, checkBase)) {
942932
ctx = nullptr;
943933
return;

0 commit comments

Comments
 (0)