Skip to content

Commit c997596

Browse files
authored
Merge pull request swiftlang#39576 from atrick/access-base
2 parents bbd9b8f + 4779163 commit c997596

File tree

3 files changed

+163
-43
lines changed

3 files changed

+163
-43
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,11 @@ SILValue findReferenceRoot(SILValue ref);
204204
/// Find the first owned root of the reference.
205205
SILValue findOwnershipReferenceRoot(SILValue ref);
206206

207+
/// Find the aggregate containing the first owned root of the
208+
/// reference. Identical to findOwnershipReferenceRoot, but looks through
209+
/// struct_extract, tuple_extract, etc.
210+
SILValue findOwnershipReferenceAggregate(SILValue ref);
211+
207212
/// Return true if \p address points to a let-variable.
208213
///
209214
/// let-variables are only written during let-variable initialization, which is
@@ -546,6 +551,17 @@ class AccessRepresentation {
546551
/// require traversing phis.
547552
class AccessBase : public AccessRepresentation {
548553
public:
554+
/// Return an AccessBase for the formally accessed variable pointed to by \p
555+
/// sourceAddress.
556+
///
557+
/// \p sourceAddress may be an address type or Builtin.RawPointer.
558+
///
559+
/// If \p sourceAddress is within a formal access scope, which does not have
560+
/// "Unsafe" enforcement, then this always returns the valid base.
561+
///
562+
/// If \p sourceAddress is not within a formal access scope, or within an
563+
/// "Unsafe" scope, then this finds the formal base if possible,
564+
/// otherwise returning an invalid base.
549565
static AccessBase compute(SILValue sourceAddress);
550566

551567
// Do not add any members to this class. AccessBase can be copied as
@@ -576,6 +592,20 @@ class AccessBase : public AccessRepresentation {
576592
/// Precondition: isReference() is true.
577593
SILValue getReference() const;
578594

595+
/// Return the OSSA root of the reference being accessed.
596+
///
597+
/// Precondition: isReference() is true.
598+
SILValue getOwnershipReferenceRoot() const {
599+
return findOwnershipReferenceRoot(getReference());
600+
}
601+
602+
/// Return the storage root of the reference being accessed.
603+
///
604+
/// Precondition: isReference() is true.
605+
SILValue getStorageReferenceRoot() const {
606+
return findReferenceRoot(getReference());
607+
}
608+
579609
/// Return the global variable being accessed.
580610
///
581611
/// Precondition: getKind() == Global
@@ -585,6 +615,16 @@ class AccessBase : public AccessRepresentation {
585615
/// determined. Otherwise returns null.
586616
const ValueDecl *getDecl() const;
587617

618+
/// Return true if this base address may be derived from a reference that is
619+
/// only valid within a locally scoped OSSA lifetime. This is not true for
620+
/// scoped storage such as alloc_stack and @in argument. It can be
621+
/// independently assumed that addresses are only used within the scope of the
622+
/// storage object.
623+
///
624+
/// Useful to determine whether addresses with the same AccessStorage are in
625+
/// fact substitutable without fixing OSSA lifetime.
626+
bool hasLocalOwnershipLifetime() const;
627+
588628
void print(raw_ostream &os) const;
589629
void dump() const;
590630
};
@@ -720,10 +760,6 @@ class AccessStorage : public AccessRepresentation {
720760
return hasIdenticalAccessInfo(other);
721761
}
722762

723-
/// Return true if this storage is valid for all uses in a function without
724-
/// checking its lifetime.
725-
bool isGuaranteedForFunction() const;
726-
727763
/// Returns the ValueDecl for the underlying storage, if it can be
728764
/// determined. Otherwise returns null.
729765
const ValueDecl *getDecl() const;

include/swift/SIL/SILInstruction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4937,6 +4937,8 @@ class ConversionInst : public SingleValueInstruction {
49374937

49384938
/// A conversion inst that produces a static OwnershipKind set upon the
49394939
/// instruction's construction.
4940+
///
4941+
/// The first operand is the ownership equivalent source.
49404942
class OwnershipForwardingConversionInst : public ConversionInst,
49414943
public OwnershipForwardingMixin {
49424944
protected:
@@ -7877,6 +7879,8 @@ class TermInst : public NonValueInstruction {
78777879
TermKind getTermKind() const { return TermKind(getKind()); }
78787880

78797881
/// Returns true if this is a transformation terminator.
7882+
///
7883+
/// The first operand is the transformed source.
78807884
bool isTransformationTerminator() const {
78817885
switch (getTermKind()) {
78827886
case TermKind::UnwindInst:
@@ -9396,6 +9400,7 @@ SILFunction *ApplyInstBase<Impl, Base, false>::getCalleeFunction() const {
93969400
}
93979401
}
93989402

9403+
/// The first operand is the ownership equivalent source.
93999404
class OwnershipForwardingMultipleValueInstruction
94009405
: public MultipleValueInstruction,
94019406
public OwnershipForwardingMixin {

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 118 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -258,47 +258,74 @@ class FindAccessBaseVisitor
258258
using SuperTy = FindAccessVisitorImpl<FindAccessBaseVisitor>;
259259

260260
protected:
261-
Optional<SILValue> base;
261+
// If the optional baseVal is set, then a result was found. If the SILValue
262+
// within the optional is invalid, then there are multiple inconsistent base
263+
// addresses (this may currently happen with RawPointer phis).
264+
Optional<SILValue> baseVal;
265+
// If the kind optional is set, then 'baseVal' is a valid
266+
// AccessBase. 'baseVal' may be a valid SILValue while kind optional has no
267+
// value if an invalid address producer was detected, via a call to
268+
// visitNonAccess.
269+
Optional<AccessBase::Kind> kindVal;
262270

263271
public:
264272
FindAccessBaseVisitor(NestedAccessType nestedAccessTy,
265273
StorageCastTy storageCastTy)
266274
: FindAccessVisitorImpl(nestedAccessTy, storageCastTy) {}
267275

268276
// Returns the accessed address or an invalid SILValue.
269-
SILValue findBase(SILValue sourceAddr) && {
277+
SILValue findPossibleBaseAddress(SILValue sourceAddr) && {
270278
reenterUseDef(sourceAddr);
271-
return base.getValueOr(SILValue());
279+
return baseVal.getValueOr(SILValue());
280+
}
281+
282+
AccessBase findBase(SILValue sourceAddr) && {
283+
reenterUseDef(sourceAddr);
284+
if (!baseVal || !kindVal)
285+
return AccessBase();
286+
287+
return AccessBase(baseVal.getValue(), kindVal.getValue());
272288
}
273289

274290
void setResult(SILValue foundBase) {
275-
if (!base)
276-
base = foundBase;
277-
else if (base.getValue() != foundBase)
278-
base = SILValue();
291+
if (!baseVal)
292+
baseVal = foundBase;
293+
else if (baseVal.getValue() != foundBase)
294+
baseVal = SILValue();
279295
}
280296

281297
// MARK: AccessPhiVisitor::UseDefVisitor implementation.
282298

283-
bool isResultValid() const { return base && bool(base.getValue()); }
299+
// Keep going as long as baseVal is valid regardless of kindVal.
300+
bool isResultValid() const { return baseVal && bool(baseVal.getValue()); }
284301

285-
void invalidateResult() { base = SILValue(); }
302+
void invalidateResult() {
303+
baseVal = SILValue();
304+
kindVal = None;
305+
}
286306

287-
Optional<SILValue> saveResult() const { return base; }
307+
Optional<SILValue> saveResult() const { return baseVal; }
288308

289-
void restoreResult(Optional<SILValue> result) { base = result; }
309+
void restoreResult(Optional<SILValue> result) { baseVal = result; }
290310

291311
void addUnknownOffset() { return; }
292312

293313
// MARK: visitor implementation.
294314

295315
SILValue visitBase(SILValue base, AccessStorage::Kind kind) {
296316
setResult(base);
317+
if (!baseVal.getValue()) {
318+
kindVal = None;
319+
} else {
320+
assert(!kindVal || kindVal.getValue() == kind);
321+
kindVal = kind;
322+
}
297323
return SILValue();
298324
}
299325

300326
SILValue visitNonAccess(SILValue value) {
301327
setResult(value);
328+
kindVal = None;
302329
return SILValue();
303330
}
304331

@@ -322,7 +349,7 @@ SILValue swift::getTypedAccessAddress(SILValue address) {
322349
SILValue accessAddress =
323350
FindAccessBaseVisitor(NestedAccessType::StopAtAccessBegin,
324351
StopAtStorageCast)
325-
.findBase(address);
352+
.findPossibleBaseAddress(address);
326353
assert(accessAddress->getType().isAddress());
327354
return accessAddress;
328355
}
@@ -334,14 +361,14 @@ SILValue swift::getAccessScope(SILValue address) {
334361
assert(address->getType().isAddress());
335362
return FindAccessBaseVisitor(NestedAccessType::StopAtAccessBegin,
336363
IgnoreStorageCast)
337-
.findBase(address);
364+
.findPossibleBaseAddress(address);
338365
}
339366

340367
// This is allowed to be called on a non-address pointer type.
341368
SILValue swift::getAccessBase(SILValue address) {
342369
return FindAccessBaseVisitor(NestedAccessType::IgnoreAccessBegin,
343370
IgnoreStorageCast)
344-
.findBase(address);
371+
.findPossibleBaseAddress(address);
345372
}
346373

347374
static bool isLetForBase(SILValue base) {
@@ -510,6 +537,12 @@ void AccessRepresentation::print(raw_ostream &os) const {
510537
// MARK: AccessBase
511538
//===----------------------------------------------------------------------===//
512539

540+
AccessBase AccessBase::compute(SILValue sourceAddress) {
541+
return FindAccessBaseVisitor(NestedAccessType::IgnoreAccessBegin,
542+
IgnoreStorageCast)
543+
.findBase(sourceAddress);
544+
}
545+
513546
AccessBase::AccessBase(SILValue base, Kind kind)
514547
: AccessRepresentation(base, kind)
515548
{
@@ -609,6 +642,30 @@ const ValueDecl *AccessBase::getDecl() const {
609642
}
610643
}
611644

645+
bool AccessBase::hasLocalOwnershipLifetime() const {
646+
switch (getKind()) {
647+
case AccessBase::Argument:
648+
case AccessBase::Stack:
649+
case AccessBase::Global:
650+
return false;
651+
case AccessBase::Unidentified:
652+
// Unidentified storage may be nested within object access, but this is an
653+
// "escaped pointer", so it is not restricted to the object's borrow scope.
654+
return false;
655+
case AccessBase::Yield:
656+
// Yielded values have a local apply scope, but they never have the same
657+
// storage as yielded values from a different scope, so there is no need to
658+
// consider their local scope during substitution.
659+
return false;
660+
case AccessBase::Box:
661+
case AccessBase::Class:
662+
case AccessBase::Tail:
663+
return getReference()->getOwnershipKind() != OwnershipKind::None;
664+
case AccessBase::Nested:
665+
llvm_unreachable("unexpected storage");
666+
};
667+
}
668+
612669
void AccessBase::print(raw_ostream &os) const {
613670
AccessRepresentation::print(os);
614671
switch (getKind()) {
@@ -675,12 +732,8 @@ namespace {
675732
// Essentially RC identity where the starting point is already a reference.
676733
class FindReferenceRoot {
677734
SmallPtrSet<SILPhiArgument *, 4> visitedPhis;
678-
bool preserveOwnership;
679735

680736
public:
681-
FindReferenceRoot(bool preserveOwnership)
682-
: preserveOwnership(preserveOwnership) {}
683-
684737
SILValue findRoot(SILValue ref) && {
685738
SILValue root = recursiveFindRoot(ref);
686739
assert(root && "all phi inputs must be reachable");
@@ -692,14 +745,8 @@ class FindReferenceRoot {
692745
SILValue recursiveFindRoot(SILValue ref) {
693746
while (auto *svi = dyn_cast<SingleValueInstruction>(ref)) {
694747
// If preserveOwnership is true, stop at the first owned root
695-
if (preserveOwnership) {
696-
if (!isIdentityAndOwnershipPreservingRefCast(svi)) {
697-
break;
698-
}
699-
} else {
700-
if (!isIdentityPreservingRefCast(svi)) {
701-
break;
702-
}
748+
if (!isIdentityPreservingRefCast(svi)) {
749+
break;
703750
}
704751
ref = svi->getOperand(0);
705752
};
@@ -735,11 +782,54 @@ class FindReferenceRoot {
735782
} // end anonymous namespace
736783

737784
SILValue swift::findReferenceRoot(SILValue ref) {
738-
return FindReferenceRoot(false /*preserveOwnership*/).findRoot(ref);
785+
return FindReferenceRoot().findRoot(ref);
739786
}
740787

788+
// This does not handle phis because a phis is either a consume or a
789+
// reborrow. In either case, the phi argument's ownership is independent from
790+
// the phi itself. The client assumes that the returned root is in the same
791+
// lifetime or borrow scope of the access.
741792
SILValue swift::findOwnershipReferenceRoot(SILValue ref) {
742-
return FindReferenceRoot(true /*preserveOwnership*/).findRoot(ref);
793+
while (auto *svi = dyn_cast<SingleValueInstruction>(ref)) {
794+
if (isIdentityAndOwnershipPreservingRefCast(svi)) {
795+
ref = svi->getOperand(0);
796+
continue;
797+
}
798+
break;
799+
}
800+
return ref;
801+
}
802+
803+
/// Find the first owned aggregate containing the reference, or simply the
804+
/// reference root if no aggregate is found.
805+
///
806+
/// TODO: Add a component path to a ReferenceRoot abstraction and handle
807+
/// that within FindReferenceRoot.
808+
SILValue swift::findOwnershipReferenceAggregate(SILValue ref) {
809+
SILValue root = ref;
810+
while(true) {
811+
root = findOwnershipReferenceRoot(root);
812+
if (!root)
813+
return root;
814+
if (isa<FirstArgOwnershipForwardingSingleValueInst>(root)
815+
|| isa<OwnershipForwardingConversionInst>(root)
816+
|| isa<OwnershipForwardingSelectEnumInstBase>(root)
817+
|| isa<OwnershipForwardingMultipleValueInstruction>(root)) {
818+
root = root->getDefiningInstruction()->getOperand(0);
819+
continue;
820+
}
821+
if (auto *arg = dyn_cast<SILArgument>(root)) {
822+
if (auto *term = arg->getSingleTerminator()) {
823+
if (term->isTransformationTerminator()) {
824+
assert(OwnershipForwardingTermInst::isa(term));
825+
root = term->getOperand(0);
826+
continue;
827+
}
828+
}
829+
}
830+
break;
831+
}
832+
return root;
743833
}
744834

745835
//===----------------------------------------------------------------------===//
@@ -802,17 +892,6 @@ void AccessStorage::visitRoots(
802892
}
803893
}
804894

805-
bool AccessStorage::isGuaranteedForFunction() const {
806-
if (getKind() == AccessStorage::Argument) {
807-
return getArgument()->getArgumentConvention().isGuaranteedConvention();
808-
}
809-
if (isObjectAccess()) {
810-
return getRoot().getOwnershipKind() == OwnershipKind::Guaranteed
811-
&& isa<SILFunctionArgument>(getRoot());
812-
}
813-
return false;
814-
}
815-
816895
const ValueDecl *AccessStorage::getDecl() const {
817896
switch (getKind()) {
818897
case Box:

0 commit comments

Comments
 (0)