Skip to content

Commit b272dc5

Browse files
committed
Cache 'isLet' within AccessedStorage.
Compute 'isLet' from the VarDecl that is available when constructing AccessedStorage so we don't need to recover the VarDecl for the base later. This generally makes more sense and is more efficient, but it will be necessary when we look past class casts when finding the reference root.
1 parent 6f2cda1 commit b272dc5

File tree

6 files changed

+57
-39
lines changed

6 files changed

+57
-39
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,11 @@ class AccessedStorage {
303303
protected:
304304
// Checking the storage kind is far more common than other fields. Make sure
305305
// it can be byte load with no shift.
306-
static const int ReservedKindBits = 8;
306+
static const int ReservedKindBits = 7;
307307
static_assert(ReservedKindBits >= NumKindBits, "Too many storage kinds.");
308308

309309
static const unsigned InvalidElementIndex =
310-
(1 << (32 - ReservedKindBits)) - 1;
310+
(1 << (32 - (ReservedKindBits + 1))) - 1;
311311

312312
// Form a bitfield that is effectively a union over any pass-specific data
313313
// with the fields used within this class as a common prefix.
@@ -327,9 +327,10 @@ class AccessedStorage {
327327
// elementIndex can overflow while gracefully degrading analysis. For now,
328328
// reserve an absurd number of bits at a nice alignment boundary, but this
329329
// can be reduced.
330-
SWIFT_INLINE_BITFIELD_BASE(AccessedStorage, 32, kind
331-
: ReservedKindBits,
332-
elementIndex : 32 - ReservedKindBits);
330+
SWIFT_INLINE_BITFIELD_BASE(AccessedStorage, 32,
331+
kind : ReservedKindBits,
332+
isLet : 1,
333+
elementIndex : 32 - (ReservedKindBits + 1));
333334

334335
// Define bits for use in AccessedStorageAnalysis. Each identified storage
335336
// object is mapped to one instance of this subclass.
@@ -512,7 +513,7 @@ class AccessedStorage {
512513
}
513514

514515
/// Return true if the given access is on a 'let' lvalue.
515-
bool isLetAccess(SILFunction *F) const;
516+
bool isLetAccess() const { return Bits.AccessedStorage.isLet; }
516517

517518
/// If this is a uniquely identified formal access, then it cannot
518519
/// alias with any other uniquely identified access to different storage.
@@ -555,9 +556,12 @@ class AccessedStorage {
555556
/// Returns the ValueDecl for the underlying storage, if it can be
556557
/// determined. Otherwise returns null.
557558
///
558-
/// WARNING: This is not a constant-time operation. It is for diagnostics and
559-
/// checking via the ValueDecl if we are processing a `let` variable.
560-
const ValueDecl *getDecl() const;
559+
/// If \p base is provided, then it must be the accessed base for this
560+
/// storage, as passed to the AccessedStorage constructor. What \p base is
561+
/// provided, this is guaranteed to return a valid decl for class properties;
562+
/// otherwise it is only a best effort based on the type of the object root
563+
/// *before* the object is cast to the final accessed reference type.
564+
const ValueDecl *getDecl(SILValue base = SILValue()) const;
561565

562566
/// Get all leaf uses of all address, pointer, or box values that have a this
563567
/// AccessedStorage in common. Return true if all uses were found before
@@ -629,6 +633,8 @@ class AccessedStorage {
629633
// nested/argument access.
630634
return false;
631635
}
636+
637+
void setLetAccess(SILValue base);
632638
};
633639

634640
} // end namespace swift

include/swift/SIL/SILInstruction.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5822,13 +5822,11 @@ class TupleElementAddrInst
58225822
/// object, including properties declared in a superclass.
58235823
unsigned getFieldIndex(NominalTypeDecl *decl, VarDecl *property);
58245824

5825-
/// Get the property for a struct or class by its unique index.
5825+
/// Get the property for a struct or class by its unique index, or nullptr if
5826+
/// the index does not match a property declared in this struct or class or
5827+
/// one its superclasses.
58265828
///
58275829
/// Precondition: \p decl must be a non-resilient struct or class.
5828-
///
5829-
/// Precondition: \p index must be the index of a stored property
5830-
/// (as returned by getFieldIndex()) which is declared
5831-
/// in \p decl, not in a superclass.
58325830
VarDecl *getIndexedField(NominalTypeDecl *decl, unsigned index);
58335831

58345832
/// A common base for instructions that require a cached field index.

lib/SIL/IR/SILInstructions.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,15 +1345,23 @@ unsigned swift::getFieldIndex(NominalTypeDecl *decl, VarDecl *field) {
13451345

13461346
/// Get the property for a struct or class by its unique index.
13471347
VarDecl *swift::getIndexedField(NominalTypeDecl *decl, unsigned index) {
1348-
if (auto *classDecl = dyn_cast<ClassDecl>(decl)) {
1349-
for (auto *superDecl = classDecl->getSuperclassDecl(); superDecl != nullptr;
1350-
superDecl = superDecl->getSuperclassDecl()) {
1351-
assert(index >= superDecl->getStoredProperties().size()
1352-
&& "field index cannot refer to a superclass field");
1353-
index -= superDecl->getStoredProperties().size();
1348+
if (auto *structDecl = dyn_cast<StructDecl>(decl)) {
1349+
return structDecl->getStoredProperties()[index];
1350+
}
1351+
auto *classDecl = cast<ClassDecl>(decl);
1352+
SmallVector<ClassDecl *, 3> superclasses;
1353+
for (auto *superDecl = classDecl; superDecl != nullptr;
1354+
superDecl = superDecl->getSuperclassDecl()) {
1355+
superclasses.push_back(superDecl);
1356+
}
1357+
std::reverse(superclasses.begin(), superclasses.end());
1358+
for (auto *superDecl : superclasses) {
1359+
if (index < superDecl->getStoredProperties().size()) {
1360+
return superDecl->getStoredProperties()[index];
13541361
}
1362+
index -= superDecl->getStoredProperties().size();
13551363
}
1356-
return decl->getStoredProperties()[index];
1364+
return nullptr;
13571365
}
13581366

13591367
unsigned FieldIndexCacheBase::cacheFieldIndex() {

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,9 @@ SILGlobalVariable *getReferencedGlobal(SILInstruction *inst) {
452452
constexpr unsigned AccessedStorage::TailIndex;
453453

454454
AccessedStorage::AccessedStorage(SILValue base, Kind kind) {
455+
// For kind==Unidentified, base may be an invalid empty or tombstone value.
455456
assert(base && "invalid storage base");
456457
initKind(kind);
457-
458458
switch (kind) {
459459
case Box:
460460
assert(isa<AllocBoxInst>(base));
@@ -505,6 +505,7 @@ AccessedStorage::AccessedStorage(SILValue base, Kind kind) {
505505
break;
506506
}
507507
}
508+
setLetAccess(base);
508509
}
509510

510511
void AccessedStorage::visitRoots(
@@ -528,21 +529,24 @@ void AccessedStorage::visitRoots(
528529
}
529530
}
530531

531-
// Return true if the given access is on a 'let' lvalue.
532-
bool AccessedStorage::isLetAccess(SILFunction *F) const {
533-
if (auto *decl = dyn_cast_or_null<VarDecl>(getDecl()))
534-
return decl->isLet();
535-
532+
// Set 'isLet' to true if this storage can be determined to be a 'let' variable.
533+
//
534+
// \p base must be the access base for this storage, as passed to the
535+
// AccessedStorage constructor.
536+
void AccessedStorage::setLetAccess(SILValue base) {
536537
// It's unclear whether a global will ever be missing it's varDecl, but
537538
// technically we only preserve it for debug info. So if we don't have a decl,
538539
// check the flag on SILGlobalVariable, which is guaranteed valid,
539-
if (getKind() == AccessedStorage::Global)
540-
return getGlobal()->isLet();
541-
542-
return false;
540+
if (getKind() == AccessedStorage::Global) {
541+
Bits.AccessedStorage.isLet = getGlobal()->isLet();
542+
return;
543+
}
544+
if (auto *decl = dyn_cast_or_null<VarDecl>(getDecl(base))) {
545+
Bits.AccessedStorage.isLet = decl->isLet();
546+
}
543547
}
544548

545-
const ValueDecl *AccessedStorage::getDecl() const {
549+
const ValueDecl *AccessedStorage::getDecl(SILValue base) const {
546550
switch (getKind()) {
547551
case Box:
548552
return cast<AllocBoxInst>(value)->getLoc().getAsASTNode<VarDecl>();
@@ -555,7 +559,7 @@ const ValueDecl *AccessedStorage::getDecl() const {
555559

556560
case Class: {
557561
auto *decl = getObject()->getType().getNominalOrBoundGenericNominal();
558-
return getIndexedField(decl, getPropertyIndex());
562+
return decl ? getIndexedField(decl, getPropertyIndex()) : nullptr;
559563
}
560564
case Tail:
561565
return nullptr;
@@ -621,8 +625,10 @@ void AccessedStorage::print(raw_ostream &os) const {
621625
break;
622626
case Class:
623627
os << getObject();
624-
os << " Field: ";
625-
getDecl()->print(os);
628+
if (auto *decl = getDecl()) {
629+
os << " Field: ";
630+
decl->print(os);
631+
}
626632
os << " Index: " << getPropertyIndex() << "\n";
627633
break;
628634
case Tail:
@@ -1655,7 +1661,7 @@ bool swift::isPossibleFormalAccessBase(const AccessedStorage &storage,
16551661
// Additional checks that apply to anything that may fall through.
16561662

16571663
// Immutable values are only accessed for initialization.
1658-
if (storage.isLetAccess(F))
1664+
if (storage.isLetAccess())
16591665
return false;
16601666

16611667
return true;

lib/SIL/Verifier/LoadBorrowInvalidationChecker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,9 @@ bool LoadBorrowNeverInvalidatedAnalysis::isNeverInvalidated(
466466
}
467467

468468
// If we have a let address, then we are already done.
469-
if (storage.isLetAccess(lbi->getFunction()))
469+
if (storage.isLetAccess()) {
470470
return true;
471-
471+
}
472472
// At this point, we know that we /may/ have writes. Now we go through various
473473
// cases to try and exhaustively identify if those writes overlap with our
474474
// load_borrow.

lib/SILOptimizer/SemanticARC/LoadCopyToLoadBorrowOpt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class StorageGuaranteesLoadVisitor
193193

194194
void visitGlobalAccess(SILValue global) {
195195
return answer(
196-
!AccessedStorage(global, AccessedStorage::Global).isLetAccess(&ctx.fn));
196+
!AccessedStorage(global, AccessedStorage::Global).isLetAccess());
197197
}
198198

199199
void visitClassAccess(RefElementAddrInst *field) {

0 commit comments

Comments
 (0)