@@ -260,6 +260,16 @@ enum class NestedAccessType { StopAtAccessBegin, IgnoreAccessBegin };
260
260
// / previous.
261
261
enum class AccessUseType { Exact, Inner, Overlapping };
262
262
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
+
263
273
// / The physical representation used to identify access information and common
264
274
// / API used by both AccessBase and AccessStorage.
265
275
// /
@@ -898,6 +908,30 @@ struct AccessStorageWithBase {
898
908
void dump () const ;
899
909
};
900
910
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
+
901
935
// / Return an AccessStorage value that identifies formally accessed storage
902
936
// / for \p beginAccess, considering any outer access scope as having distinct
903
937
// / storage from this access scope. This is useful for exclusivity checking
@@ -1209,6 +1243,16 @@ struct AccessPathWithBase {
1209
1243
void dump () const ;
1210
1244
};
1211
1245
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
+
1212
1256
inline AccessPath AccessPath::compute (SILValue address) {
1213
1257
return AccessPathWithBase::compute (address).accessPath ;
1214
1258
}
@@ -1267,6 +1311,18 @@ template <> struct DenseMapInfo<swift::AccessPathWithBase> {
1267
1311
}
1268
1312
};
1269
1313
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
+ };
1270
1326
} // end namespace llvm
1271
1327
1272
1328
// ===----------------------------------------------------------------------===//
@@ -1501,28 +1557,14 @@ inline Operand *getAccessProjectionOperand(SingleValueInstruction *svi) {
1501
1557
};
1502
1558
}
1503
1559
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) {
1517
1563
switch (svi->getKind ()) {
1518
1564
default :
1519
1565
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!
1523
1567
case SILInstructionKind::UncheckedAddrCastInst:
1524
- case SILInstructionKind::MarkDependenceInst:
1525
- case SILInstructionKind::CopyValueInst:
1526
1568
// Casting to RawPointer does not affect the AccessPath. When converting
1527
1569
// between address types, they must be layout compatible (with truncation).
1528
1570
case SILInstructionKind::AddressToPointerInst:
@@ -1552,6 +1594,37 @@ inline bool isAccessStorageCast(SingleValueInstruction *svi) {
1552
1594
}
1553
1595
}
1554
1596
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
+
1555
1628
// / Abstract CRTP class for a visiting instructions that are part of the use-def
1556
1629
// / chain from an accessed address up to the storage base.
1557
1630
// /
@@ -1598,8 +1671,9 @@ class AccessUseDefChainVisitor {
1598
1671
// Result visitBase(SILValue base, AccessStorage::Kind kind);
1599
1672
// Result visitNonAccess(SILValue base);
1600
1673
// 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,
1603
1677
// Operand *sourceOper);
1604
1678
1605
1679
Result visit (SILValue sourceAddr);
@@ -1611,8 +1685,12 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
1611
1685
if (auto *projOper = getAccessProjectionOperand (svi))
1612
1686
return asImpl ().visitAccessProjection (svi, projOper);
1613
1687
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);
1616
1694
}
1617
1695
switch (sourceAddr->getKind ()) {
1618
1696
default :
@@ -1787,7 +1865,8 @@ class AccessUseDefChainCloner
1787
1865
return SILValue ();
1788
1866
}
1789
1867
1790
- SILValue visitStorageCast (SingleValueInstruction *cast, Operand *sourceOper) {
1868
+ SILValue visitStorageCast (SingleValueInstruction *cast, Operand *sourceOper,
1869
+ AccessStorageCast) {
1791
1870
// The cloner does not currently know how to create compensating
1792
1871
// end_borrows or fix mark_dependence operands.
1793
1872
if (isa<BeginBorrowInst>(cast) || isa<MarkDependenceInst>(cast))
0 commit comments