@@ -260,6 +260,16 @@ enum class NestedAccessType { StopAtAccessBegin, IgnoreAccessBegin };
260260// / previous.
261261enum class AccessUseType { Exact, Inner, Overlapping };
262262
263+ // / When walking from a value to its storage, casts may be encountered. The
264+ // / cases describe variety of encountered casts, categorized by the kind of
265+ // / transformation that the casts perform.
266+ // /
267+ // / The enum values are ordered. Each successive cast kind is more
268+ // / transformative than the last.
269+ // /
270+ // / TODO: Distinguish between LayoutEquivalent and LayoutCompatibile.
271+ enum class AccessStorageCast { Identity, Type };
272+
263273// / The physical representation used to identify access information and common
264274// / API used by both AccessBase and AccessStorage.
265275// /
@@ -898,6 +908,30 @@ struct AccessStorageWithBase {
898908 void dump () const ;
899909};
900910
911+ // / Extends AccessStorageWithBase by adding information that was obtained while
912+ // / visiting from a particular address, to which an instance of this is
913+ // / relative.
914+ struct RelativeAccessStorageWithBase {
915+
916+ // / Identical to AccessStorageWithBase::compute but preserves information
917+ // / specific to the walk from address;
918+ static RelativeAccessStorageWithBase compute (SILValue address);
919+
920+ // / Identical to AccessStorageWithBase::computeInScope but preserves
921+ // / information specific to the walk from address;
922+ static RelativeAccessStorageWithBase computeInScope (SILValue address);
923+
924+ // / The address to which this RelativeAccessStorageWithBase is relative.
925+ SILValue address;
926+ // / The underlying access storage and base.
927+ AccessStorageWithBase storageWithBase;
928+ // / The most transformative cast that was seen between when walking from
929+ // / address to storage.base;
930+ Optional<AccessStorageCast> cast;
931+
932+ AccessStorage getStorage () const { return storageWithBase.storage ; }
933+ };
934+
901935// / Return an AccessStorage value that identifies formally accessed storage
902936// / for \p beginAccess, considering any outer access scope as having distinct
903937// / storage from this access scope. This is useful for exclusivity checking
@@ -1209,6 +1243,16 @@ struct AccessPathWithBase {
12091243 void dump () const ;
12101244};
12111245
1246+ // Visits all the "product leaves" of the type tree of the specified value and
1247+ // invokes provided visitor, identifying the leaf by its path node and
1248+ // providing its type.
1249+ //
1250+ // The "product leaves" are the leaves obtained by only looking through type
1251+ // products (structs and tuples) and NOT type sums (enums).
1252+ void visitProductLeafAccessPathNodes (
1253+ SILValue address, TypeExpansionContext tec, SILModule &module ,
1254+ std::function<void (AccessPath::PathNode, SILType)> visitor);
1255+
12121256inline AccessPath AccessPath::compute (SILValue address) {
12131257 return AccessPathWithBase::compute (address).accessPath ;
12141258}
@@ -1267,6 +1311,18 @@ template <> struct DenseMapInfo<swift::AccessPathWithBase> {
12671311 }
12681312};
12691313
1314+ // Allow AccessPath::PathNode to be used as a pointer-like template argument.
1315+ template <>
1316+ struct PointerLikeTypeTraits <swift::AccessPath::PathNode> {
1317+ static inline void *getAsVoidPointer (swift::AccessPath::PathNode node) {
1318+ return (void *)node.node ;
1319+ }
1320+ static inline swift::AccessPath::PathNode getFromVoidPointer (void *pointer) {
1321+ return swift::AccessPath::PathNode ((swift::IndexTrieNode *)pointer);
1322+ }
1323+ enum { NumLowBitsAvailable =
1324+ PointerLikeTypeTraits<swift::IndexTrieNode *>::NumLowBitsAvailable };
1325+ };
12701326} // end namespace llvm
12711327
12721328// ===----------------------------------------------------------------------===//
@@ -1501,28 +1557,14 @@ inline Operand *getAccessProjectionOperand(SingleValueInstruction *svi) {
15011557 };
15021558}
15031559
1504- // / An address, pointer, or box cast that occurs outside of the formal
1505- // / access. These convert the base of accessed storage without affecting the
1506- // / AccessPath. Useful for both use-def and def-use traversal. The source
1507- // / address must be at operand(0).
1508- // /
1509- // / Some of these casts, such as address_to_pointer, may also occur inside of a
1510- // / formal access.
1511- // /
1512- // / TODO: Add stricter structural guarantee such that these never
1513- // / occur within an access. It's important to be able to get the accessed
1514- // / address without looking though type casts or pointer_to_address [strict],
1515- // / which we can't do if those operations are behind access projections.
1516- inline bool isAccessStorageCast (SingleValueInstruction *svi) {
1560+ // / A cast for the purposes of AccessStorage which may change the
1561+ // / underlying type but doesn't affect the AccessPath. See isAccessStorageCast.
1562+ inline bool isAccessStorageTypeCast (SingleValueInstruction *svi) {
15171563 switch (svi->getKind ()) {
15181564 default :
15191565 return false ;
1520-
1521- // Simply pass-thru the incoming address.
1522- case SILInstructionKind::MarkUninitializedInst:
1566+ // Simply pass-thru the incoming address. But change its type!
15231567 case SILInstructionKind::UncheckedAddrCastInst:
1524- case SILInstructionKind::MarkDependenceInst:
1525- case SILInstructionKind::CopyValueInst:
15261568 // Casting to RawPointer does not affect the AccessPath. When converting
15271569 // between address types, they must be layout compatible (with truncation).
15281570 case SILInstructionKind::AddressToPointerInst:
@@ -1552,6 +1594,37 @@ inline bool isAccessStorageCast(SingleValueInstruction *svi) {
15521594 }
15531595}
15541596
1597+ // / A cast for the purposes of AccessStorage which doesn't change the
1598+ // / underlying type and doesn't affect the AccessPath. See isAccessStorageCast.
1599+ inline bool isAccessStorageIdentityCast (SingleValueInstruction *svi) {
1600+ switch (svi->getKind ()) {
1601+ default :
1602+ return false ;
1603+
1604+ // Simply pass-thru the incoming address.
1605+ case SILInstructionKind::MarkUninitializedInst:
1606+ case SILInstructionKind::MarkDependenceInst:
1607+ case SILInstructionKind::CopyValueInst:
1608+ return true ;
1609+ }
1610+ }
1611+
1612+ // / An address, pointer, or box cast that occurs outside of the formal
1613+ // / access. These convert the base of accessed storage without affecting the
1614+ // / AccessPath. Useful for both use-def and def-use traversal. The source
1615+ // / address must be at operand(0).
1616+ // /
1617+ // / Some of these casts, such as address_to_pointer, may also occur inside of a
1618+ // / formal access.
1619+ // /
1620+ // / TODO: Add stricter structural guarantee such that these never
1621+ // / occur within an access. It's important to be able to get the accessed
1622+ // / address without looking though type casts or pointer_to_address [strict],
1623+ // / which we can't do if those operations are behind access projections.
1624+ inline bool isAccessStorageCast (SingleValueInstruction *svi) {
1625+ return isAccessStorageTypeCast (svi) || isAccessStorageIdentityCast (svi);
1626+ }
1627+
15551628// / Abstract CRTP class for a visiting instructions that are part of the use-def
15561629// / chain from an accessed address up to the storage base.
15571630// /
@@ -1598,8 +1671,9 @@ class AccessUseDefChainVisitor {
15981671 // Result visitBase(SILValue base, AccessStorage::Kind kind);
15991672 // Result visitNonAccess(SILValue base);
16001673 // Result visitPhi(SILPhiArgument *phi);
1601- // Result visitStorageCast(SingleValueInstruction *cast, Operand *sourceOper);
1602- // Result visitAccessProjection(SingleValueInstruction *projectedAddr,
1674+ // Result visitStorageCast(SingleValueInstruction *cast, Operand *sourceOper,
1675+ // AccessStorageCast cast); Result
1676+ // visitAccessProjection(SingleValueInstruction *projectedAddr,
16031677 // Operand *sourceOper);
16041678
16051679 Result visit (SILValue sourceAddr);
@@ -1611,8 +1685,12 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
16111685 if (auto *projOper = getAccessProjectionOperand (svi))
16121686 return asImpl ().visitAccessProjection (svi, projOper);
16131687
1614- if (isAccessStorageCast (svi))
1615- return asImpl ().visitStorageCast (svi, &svi->getAllOperands ()[0 ]);
1688+ if (isAccessStorageTypeCast (svi))
1689+ return asImpl ().visitStorageCast (svi, &svi->getAllOperands ()[0 ],
1690+ AccessStorageCast::Type);
1691+ if (isAccessStorageIdentityCast (svi))
1692+ return asImpl ().visitStorageCast (svi, &svi->getAllOperands ()[0 ],
1693+ AccessStorageCast::Identity);
16161694 }
16171695 switch (sourceAddr->getKind ()) {
16181696 default :
@@ -1787,7 +1865,8 @@ class AccessUseDefChainCloner
17871865 return SILValue ();
17881866 }
17891867
1790- SILValue visitStorageCast (SingleValueInstruction *cast, Operand *sourceOper) {
1868+ SILValue visitStorageCast (SingleValueInstruction *cast, Operand *sourceOper,
1869+ AccessStorageCast) {
17911870 // The cloner does not currently know how to create compensating
17921871 // end_borrows or fix mark_dependence operands.
17931872 if (isa<BeginBorrowInst>(cast) || isa<MarkDependenceInst>(cast))
0 commit comments