Skip to content

Commit fa9eb49

Browse files
Merge pull request #41806 from nate-chandler/mem_access_utils/two-new-utilities
[MemAccessUtils] Add two utilties.
2 parents 4435a37 + a1c1b32 commit fa9eb49

File tree

6 files changed

+175
-40
lines changed

6 files changed

+175
-40
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,16 @@ enum class NestedAccessType { StopAtAccessBegin, IgnoreAccessBegin };
260260
/// previous.
261261
enum 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+
12121256
inline 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))

include/swift/SIL/MemoryLocations.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,14 @@ class MemoryLocations {
238238
addr2LocIdx[projection] = locIdx;
239239
}
240240

241-
/// Sets the location bits os \p addr in \p bits, if \p addr is associated
241+
/// Sets the location bits of \p addr in \p bits, if \p addr is associated
242242
/// with a location.
243243
void setBits(Bits &bits, SILValue addr) const {
244244
if (auto *loc = getLocation(addr))
245245
bits |= loc->subLocations;
246246
}
247247

248-
/// Clears the location bits os \p addr in \p bits, if \p addr is associated
248+
/// Clears the location bits of \p addr in \p bits, if \p addr is associated
249249
/// with a location.
250250
void clearBits(Bits &bits, SILValue addr) const {
251251
if (auto *loc = getLocation(addr))
@@ -307,7 +307,7 @@ class MemoryLocations {
307307
SubLocationMap &subLocationMap);
308308

309309
/// Helper function called by analyzeLocation to create a sub-location for
310-
/// and address projection and check all of its uses.
310+
/// an address projection and check all of its uses.
311311
bool analyzeAddrProjection(
312312
SingleValueInstruction *projection, unsigned parentLocIdx,unsigned fieldNr,
313313
SmallVectorImpl<SILValue> &collectedVals, SubLocationMap &subLocationMap);

include/swift/SIL/Projection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ static_assert(sizeof(Projection) == sizeof(uintptr_t),
484484
/// The main purpose of this class is to enable one to reason about iterated
485485
/// chains of projections. Some example usages are:
486486
///
487-
/// 1. Converting value projections to aggregate projections or vis-a-versa.
487+
/// 1. Converting value projections to aggregate projections or vice versa.
488488
/// 2. Performing tuple operations on two paths (using the mathematical
489489
/// definition of tuples as ordered sets).
490490
class ProjectionPath {

lib/SIL/IR/SILInstructions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ static void buildTypeDependentOperands(
7575
bool hasDynamicSelf, SmallVectorImpl<SILValue> &TypeDependentOperands,
7676
SILFunction &F) {
7777

78-
for (const auto archetype : RootOpenedArchetypes) {
78+
for (const auto &archetype : RootOpenedArchetypes) {
7979
SILValue def = F.getModule().getRootOpenedArchetypeDef(archetype, &F);
8080
assert(def->getFunction() == &F &&
8181
"def of root opened archetype is in wrong function");

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ class AccessPhiVisitor
125125
phiArg->getIncomingPhiValues(pointerWorklist);
126126
}
127127

128-
void visitStorageCast(SingleValueInstruction *cast, Operand *sourceOper) {
128+
void visitStorageCast(SingleValueInstruction *cast, Operand *sourceOper,
129+
AccessStorageCast) {
129130
// Allow conversions to/from pointers and addresses on disjoint phi paths
130131
// only if the underlying useDefVisitor allows it.
131132
if (storageCastTy == IgnoreStorageCast)
@@ -209,7 +210,8 @@ class FindAccessVisitorImpl : public AccessUseDefChainVisitor<Impl, SILValue> {
209210
return this->asImpl().visitNonAccess(phiArg);
210211
}
211212

212-
SILValue visitStorageCast(SingleValueInstruction *, Operand *sourceAddr) {
213+
SILValue visitStorageCast(SingleValueInstruction *, Operand *sourceAddr,
214+
AccessStorageCast cast) {
213215
assert(storageCastTy == IgnoreStorageCast);
214216
return sourceAddr->get();
215217
}
@@ -331,11 +333,12 @@ class FindAccessBaseVisitor
331333
}
332334

333335
// Override visitStorageCast to avoid seeing through arbitrary address casts.
334-
SILValue visitStorageCast(SingleValueInstruction *cast, Operand *sourceAddr) {
336+
SILValue visitStorageCast(SingleValueInstruction *svi, Operand *sourceAddr,
337+
AccessStorageCast cast) {
335338
if (storageCastTy == StopAtStorageCast)
336-
return visitNonAccess(cast);
339+
return visitNonAccess(svi);
337340

338-
return SuperTy::visitStorageCast(cast, sourceAddr);
341+
return SuperTy::visitStorageCast(svi, sourceAddr, cast);
339342
}
340343
};
341344

@@ -1062,11 +1065,13 @@ namespace {
10621065
// AccessStorage object for all projection paths.
10631066
class FindAccessStorageVisitor
10641067
: public FindAccessVisitorImpl<FindAccessStorageVisitor> {
1068+
using SuperTy = FindAccessVisitorImpl<FindAccessStorageVisitor>;
10651069

10661070
public:
10671071
struct Result {
10681072
Optional<AccessStorage> storage;
10691073
SILValue base;
1074+
Optional<AccessStorageCast> seenCast;
10701075
};
10711076

10721077
private:
@@ -1102,6 +1107,8 @@ class FindAccessStorageVisitor
11021107
// may be multiple global_addr bases for identical storage.
11031108
SILValue getBase() const { return result.base; }
11041109

1110+
Optional<AccessStorageCast> getCast() const { return result.seenCast; }
1111+
11051112
// MARK: AccessPhiVisitor::UseDefVisitor implementation.
11061113

11071114
// A valid result requires valid storage, but not a valid base.
@@ -1128,22 +1135,41 @@ class FindAccessStorageVisitor
11281135
invalidateResult();
11291136
return SILValue();
11301137
}
1138+
1139+
SILValue visitStorageCast(SingleValueInstruction *svi, Operand *sourceOper,
1140+
AccessStorageCast cast) {
1141+
result.seenCast = result.seenCast ? std::max(*result.seenCast, cast) : cast;
1142+
return SuperTy::visitStorageCast(svi, sourceOper, cast);
1143+
}
11311144
};
11321145

11331146
} // end anonymous namespace
11341147

1148+
RelativeAccessStorageWithBase
1149+
RelativeAccessStorageWithBase::compute(SILValue address) {
1150+
FindAccessStorageVisitor visitor(NestedAccessType::IgnoreAccessBegin);
1151+
visitor.findStorage(address);
1152+
return {
1153+
address, {visitor.getStorage(), visitor.getBase()}, visitor.getCast()};
1154+
}
1155+
1156+
RelativeAccessStorageWithBase
1157+
RelativeAccessStorageWithBase::computeInScope(SILValue address) {
1158+
FindAccessStorageVisitor visitor(NestedAccessType::StopAtAccessBegin);
1159+
visitor.findStorage(address);
1160+
return {
1161+
address, {visitor.getStorage(), visitor.getBase()}, visitor.getCast()};
1162+
}
1163+
11351164
AccessStorageWithBase
11361165
AccessStorageWithBase::compute(SILValue sourceAddress) {
1137-
FindAccessStorageVisitor visitor(NestedAccessType::IgnoreAccessBegin);
1138-
visitor.findStorage(sourceAddress);
1139-
return {visitor.getStorage(), visitor.getBase()};
1166+
return RelativeAccessStorageWithBase::compute(sourceAddress).storageWithBase;
11401167
}
11411168

11421169
AccessStorageWithBase
11431170
AccessStorageWithBase::computeInScope(SILValue sourceAddress) {
1144-
FindAccessStorageVisitor visitor(NestedAccessType::StopAtAccessBegin);
1145-
visitor.findStorage(sourceAddress);
1146-
return {visitor.getStorage(), visitor.getBase()};
1171+
return RelativeAccessStorageWithBase::computeInScope(sourceAddress)
1172+
.storageWithBase;
11471173
}
11481174

11491175
AccessStorage AccessStorage::compute(SILValue sourceAddress) {
@@ -1357,6 +1383,36 @@ AccessPathWithBase AccessPathWithBase::computeInScope(SILValue address) {
13571383
.findAccessPath(address);
13581384
}
13591385

1386+
void swift::visitProductLeafAccessPathNodes(
1387+
SILValue address, TypeExpansionContext tec, SILModule &module,
1388+
std::function<void(AccessPath::PathNode, SILType)> visitor) {
1389+
SmallVector<std::pair<SILType, IndexTrieNode *>, 32> worklist;
1390+
auto rootPath = AccessPath::compute(address);
1391+
auto *node = rootPath.getPathNode().node;
1392+
worklist.push_back({address->getType(), node});
1393+
while (!worklist.empty()) {
1394+
auto pair = worklist.pop_back_val();
1395+
auto silType = pair.first;
1396+
auto *node = pair.second;
1397+
if (auto tupleType = silType.getAs<TupleType>()) {
1398+
for (unsigned index : indices(tupleType->getElements())) {
1399+
auto *elementNode = node->getChild(index);
1400+
worklist.push_back({silType.getTupleElementType(index), elementNode});
1401+
}
1402+
} else if (auto *decl = silType.getStructOrBoundGenericStruct()) {
1403+
unsigned index = 0;
1404+
for (auto *field : decl->getStoredProperties()) {
1405+
auto *fieldNode = node->getChild(index);
1406+
worklist.push_back(
1407+
{silType.getFieldType(field, module, tec), fieldNode});
1408+
++index;
1409+
}
1410+
} else {
1411+
visitor(AccessPath::PathNode(node), silType);
1412+
}
1413+
}
1414+
}
1415+
13601416
void AccessPath::Index::print(raw_ostream &os) const {
13611417
if (isSubObjectProjection())
13621418
os << '#' << getSubObjectIndex();

lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class StorageGuaranteesLoadVisitor
264264
}
265265

266266
void visitStorageCast(SingleValueInstruction *projectedAddr,
267-
Operand *parentAddr) {
267+
Operand *parentAddr, AccessStorageCast cast) {
268268
return next(parentAddr->get());
269269
}
270270

0 commit comments

Comments
 (0)