4444// / 3. getAccessBase(): Find the ultimate base of any address corresponding to
4545// / the accessed object, regardless of whether the address is nested within
4646// / access scopes, and regardless of any storage casts. This returns either an
47- // / address type, pointer type, or box type, but never a reference type.
47+ // / address or pointer type, but never a reference or box type.
4848// / Each object's property or its tail storage is separately accessed.
4949// /
5050// / For better identification an access base, use
@@ -166,6 +166,11 @@ SILValue getAccessScope(SILValue address);
166166// / return the same base address, then they must also have the same storage.
167167SILValue getAccessBase (SILValue address);
168168
169+ // / Find the root of a reference, which may be a non-trivial type, box type, or
170+ // / BridgeObject. This is guaranteed to be consistent with
171+ // / AccessedStorage::getRoot() and AccessPath::getRoot().
172+ SILValue findReferenceRoot (SILValue ref);
173+
169174// / Return true if \p address points to a let-variable.
170175// /
171176// / let-variables are only written during let-variable initialization, which is
@@ -237,7 +242,8 @@ enum class AccessUseType { Exact, Inner, Overlapping };
237242// / represent any arbitrary base address--it must at least been proven not to
238243// / correspond to any class or global variable access, unless it's nested within
239244// / another access to the same object. So, Unidentified can overlap with
240- // / Class/Global access, but it cannot be the only formal access to that memory.
245+ // / Class/Global access because it was derived from another Class/Global access,
246+ // / but Unidentified can never be the only formal access to that memory.
241247// /
242248// / An *invalid* AccessedStorage object is Unidentified and associated with an
243249// / invalid SILValue. This signals that analysis has failed to recognize an
@@ -268,7 +274,7 @@ class AccessedStorage {
268274 Global,
269275 Class,
270276 Tail,
271- Argument,
277+ Argument, // Address or RawPointer argument
272278 Yield,
273279 Nested,
274280 Unidentified,
@@ -280,22 +286,11 @@ class AccessedStorage {
280286 // Give object tail storage a fake large property index for convenience.
281287 static constexpr unsigned TailIndex = std::numeric_limits<int >::max();
282288
283- // / Directly create an AccessedStorage for class or tail property access.
284- static AccessedStorage forClass (SILValue object, unsigned propertyIndex) {
285- AccessedStorage storage;
286- if (propertyIndex == TailIndex)
287- storage.initKind (Tail);
288- else
289- storage.initKind (Class, propertyIndex);
290- storage.value = object;
291- return storage;
292- }
293-
294289 // / Return an AccessedStorage value that best identifies a formally accessed
295290 // / variable pointed to by \p sourceAddress, looking through any nested
296291 // / formal accesses to find the underlying storage.
297292 // /
298- // / \p sourceAddress may be an address, pointer, or box type .
293+ // / \p sourceAddress may be an address type or Builtin.RawPointer .
299294 // /
300295 // / If \p sourceAddress is within a formal access scope, which does not have
301296 // / "Unsafe" enforcement, then this always returns valid storage.
@@ -308,7 +303,7 @@ class AccessedStorage {
308303 // / Return an AccessedStorage object that identifies formal access scope that
309304 // / immediately encloses \p sourceAddress.
310305 // /
311- // / \p sourceAddress may be an address, pointer, or box type .
306+ // / \p sourceAddress may be an address type or Builtin.RawPointer .
312307 // /
313308 // / If \p sourceAddress is within a formal access scope, this always returns a
314309 // / valid "Nested" storage value.
@@ -317,6 +312,14 @@ class AccessedStorage {
317312 // / the formal storage if possible, otherwise returning invalid storage.
318313 static AccessedStorage computeInScope (SILValue sourceAddress);
319314
315+ // / Create storage for the tail elements of \p object.
316+ static AccessedStorage forObjectTail (SILValue object) {
317+ AccessedStorage storage;
318+ storage.initKind (Tail, TailIndex);
319+ storage.value = findReferenceRoot (object);
320+ return storage;
321+ }
322+
320323protected:
321324 // Checking the storage kind is far more common than other fields. Make sure
322325 // it can be byte load with no shift.
@@ -389,7 +392,7 @@ class AccessedStorage {
389392 SILGlobalVariable *global;
390393 };
391394
392- void initKind (Kind k, unsigned elementIndex = InvalidElementIndex ) {
395+ void initKind (Kind k, unsigned elementIndex) {
393396 Bits.opaqueBits = 0 ;
394397 Bits.AccessedStorage .kind = k;
395398 Bits.AccessedStorage .elementIndex = elementIndex;
@@ -401,7 +404,7 @@ class AccessedStorage {
401404 }
402405
403406public:
404- AccessedStorage () : value() { initKind (Unidentified); }
407+ AccessedStorage () : value() { initKind (Unidentified, InvalidElementIndex ); }
405408
406409 AccessedStorage (SILValue base, Kind kind);
407410
@@ -418,6 +421,7 @@ class AccessedStorage {
418421
419422 SILValue getValue () const {
420423 assert (getKind () != Global && getKind () != Class && getKind () != Tail);
424+ assert (value && " Invalid storage has an invalid value" );
421425 return value;
422426 }
423427
@@ -436,7 +440,9 @@ class AccessedStorage {
436440 return global;
437441 }
438442
439- bool isReference () const { return getKind () == Class || getKind () == Tail; }
443+ bool isReference () const {
444+ return getKind () == Box || getKind () == Class || getKind () == Tail;
445+ }
440446
441447 SILValue getObject () const {
442448 assert (isReference ());
@@ -447,6 +453,15 @@ class AccessedStorage {
447453 return getElementIndex ();
448454 }
449455
456+ // / Return a new AccessedStorage for Class/Tail/Box access based on
457+ // / existing storage and a new object.
458+ AccessedStorage transformReference (SILValue object) const {
459+ AccessedStorage storage;
460+ storage.initKind (getKind (), getElementIndex ());
461+ storage.value = findReferenceRoot (object);
462+ return storage;
463+ }
464+
450465 // / Return the address or reference root that the storage was based
451466 // / on. Returns an invalid SILValue for globals or invalid storage.
452467 SILValue getRoot () const {
@@ -457,7 +472,7 @@ class AccessedStorage {
457472 case AccessedStorage::Argument:
458473 case AccessedStorage::Yield:
459474 case AccessedStorage::Unidentified:
460- return getValue (); // Can be invalid for Unidentified storage.
475+ return getValue ();
461476 case AccessedStorage::Global:
462477 return SILValue ();
463478 case AccessedStorage::Class:
@@ -511,6 +526,7 @@ class AccessedStorage {
511526 bool isLocal () const {
512527 switch (getKind ()) {
513528 case Box:
529+ return isa<AllocBoxInst>(value);
514530 case Stack:
515531 return true ;
516532 case Global:
@@ -538,6 +554,7 @@ class AccessedStorage {
538554 bool isUniquelyIdentified () const {
539555 switch (getKind ()) {
540556 case Box:
557+ return isa<AllocBoxInst>(value);
541558 case Stack:
542559 case Global:
543560 return true ;
@@ -686,11 +703,14 @@ template <> struct DenseMapInfo<swift::AccessedStorage> {
686703
687704 static unsigned getHashValue (swift::AccessedStorage storage) {
688705 switch (storage.getKind ()) {
706+ case swift::AccessedStorage::Unidentified:
707+ if (!storage)
708+ return DenseMapInfo<swift::SILValue>::getHashValue (swift::SILValue ());
709+ LLVM_FALLTHROUGH;
689710 case swift::AccessedStorage::Box:
690711 case swift::AccessedStorage::Stack:
691712 case swift::AccessedStorage::Nested:
692713 case swift::AccessedStorage::Yield:
693- case swift::AccessedStorage::Unidentified:
694714 return DenseMapInfo<swift::SILValue>::getHashValue (storage.getValue ());
695715 case swift::AccessedStorage::Argument:
696716 return storage.getParamIndex ();
@@ -1008,15 +1028,19 @@ class AccessPath {
10081028// recover the def-use chain for a specific global_addr or ref_element_addr.
10091029struct AccessPathWithBase {
10101030 AccessPath accessPath;
1011- // The address-type value that is the base of the formal access. For
1012- // class storage, it is the ref_element_addr. For global storage it is the
1013- // global_addr or initializer apply. For other storage, it is the same as
1014- // accessPath.getRoot().
1031+ // The address-type value that is the base of the formal access. For class
1032+ // storage, it is the ref_element_addr; for box storage, the project_box; for
1033+ // global storage the global_addr or initializer apply. For other
1034+ // storage, it is the same as accessPath.getRoot().
10151035 //
1016- // Note: base may be invalid for global_addr -> address_to_pointer -> phi
1017- // patterns, while the accessPath is still valid.
1036+ // Note: base may be invalid for phi patterns, even though the accessPath is
1037+ // valid because we don't currently keep track of multiple bases. Multiple
1038+ // bases for the same storage can happen with global_addr, ref_element_addr,
1039+ // ref_tail_addr, and project_box.
10181040 //
1019- // FIXME: add a structural requirement to SIL so base is always valid in OSSA.
1041+ // FIXME: add a structural requirement to SIL/OSSA so valid storage has
1042+ // a single base. For most cases, it is as simple by sinking the
1043+ // projection. For index_addr, it may require hoisting ref_tail_addr.
10201044 SILValue base;
10211045
10221046 // / Compute the access path at \p address, and record the access base. This
@@ -1309,14 +1333,7 @@ inline bool isAccessedStorageCast(SingleValueInstruction *svi) {
13091333 case SILInstructionKind::MarkUninitializedInst:
13101334 case SILInstructionKind::UncheckedAddrCastInst:
13111335 case SILInstructionKind::MarkDependenceInst:
1312- // Look through a project_box to identify the underlying alloc_box as the
1313- // accesed object. It must be possible to reach either the alloc_box or the
1314- // containing enum in this loop, only looking through simple value
1315- // propagation such as copy_value and begin_borrow.
1316- case SILInstructionKind::ProjectBoxInst:
1317- case SILInstructionKind::ProjectBlockStorageInst:
13181336 case SILInstructionKind::CopyValueInst:
1319- case SILInstructionKind::BeginBorrowInst:
13201337 // Casting to RawPointer does not affect the AccessPath. When converting
13211338 // between address types, they must be layout compatible (with truncation).
13221339 case SILInstructionKind::AddressToPointerInst:
@@ -1366,7 +1383,7 @@ class AccessUseDefChainVisitor {
13661383 Result visitArgumentAccess (SILFunctionArgument *arg) {
13671384 return asImpl ().visitBase (arg, AccessedStorage::Argument);
13681385 }
1369- Result visitBoxAccess (AllocBoxInst *box) {
1386+ Result visitBoxAccess (ProjectBoxInst *box) {
13701387 return asImpl ().visitBase (box, AccessedStorage::Box);
13711388 }
13721389 // / \p global may be either a GlobalAddrInst or the ApplyInst for a global
@@ -1414,9 +1431,8 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
14141431
14151432 // MARK: Handle immediately-identifiable instructions.
14161433
1417- // An AllocBox is a fully identified memory location.
1418- case ValueKind::AllocBoxInst:
1419- return asImpl ().visitBoxAccess (cast<AllocBoxInst>(sourceAddr));
1434+ case ValueKind::ProjectBoxInst:
1435+ return asImpl ().visitBoxAccess (cast<ProjectBoxInst>(sourceAddr));
14201436
14211437 // An AllocStack is a fully identified memory location, which may occur
14221438 // after inlining code already subjected to stack promotion.
0 commit comments