Skip to content

Commit 7b982e9

Browse files
authored
Merge pull request #2049 from swiftwasm/main
[pull] swiftwasm from main
2 parents be3dce1 + 9671299 commit 7b982e9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+295
-88
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
///
5050
/// For better identification an access base, use
5151
/// AccessedStorage::compute(). It returns an AccessedStorage value
52-
/// that identifies the storage location of a memory access. It provides APIs
52+
/// that identifies the storage of a memory access. It provides APIs
5353
/// for inspecting type of accessed storage and allows for disambiguation
5454
/// between different types of storage and different properties within a class.
5555
///
@@ -64,7 +64,7 @@
6464
/// from an enforced begin_access or from any memory operation that is part of a
6565
/// formal access, then it returns a valid AccessedStorage value. If the memory
6666
/// operation is not part of a formal access, then it still identifies the
67-
/// accessed location as a best effort, but the result may be invalid storage.
67+
/// accessed storage as a best effort, but the result may be invalid storage.
6868
///
6969
/// An active goal is to require compute() to always return a
7070
/// valid AccessedStorage value even for operations that aren't part of a
@@ -77,13 +77,30 @@
7777
/// make incorrect assumptions about the absence of access to globals or class
7878
/// properties.
7979
///
80-
/// identifyFormalAccess() is similar to AccessedStorage::compute(), but returns
81-
/// the formally accessed storage of a begin_access instruction. This must
82-
/// return a valid AccessedStorage value unless the access has "Unsafe"
83-
/// enforcement. The formal access location may be nested within an outer
84-
/// begin_access. For the purpose of exclusivity, nested accesses are considered
85-
/// distinct formal accesses so they return distinct AccessedStorage values even
86-
/// though they may access the same memory.
80+
/// AccessedStorage::computeInScope() returns an AccessedStorage value for the
81+
/// immediately enclosing access scope. Within a formal access, it always
82+
/// returns a Nested storage kind, which provides the begin_access marker.
83+
///
84+
/// identifyFormalAccess() works like AccessedStorage::computeInScope(), but
85+
/// finds the storage corresponding to a begin_access marker, rather than an
86+
/// arbitrary address. This must return a valid AccessedStorage value unless the
87+
/// access has "Unsafe" enforcement. The given begin_access marker may be nested
88+
/// within another, outer access scope. For the purpose of exclusivity, nested
89+
/// accesses are considered distinct formal accesses so they return distinct
90+
/// AccessedStorage values even though they may access the same memory. This
91+
/// way, nested accesses do not appear to conflict.
92+
///
93+
/// AccessPath identifies both the accessed storage and the path to a specific
94+
/// storage location within that storage object. See ProgrammersGuide.md and the
95+
/// class comments below for details. AccessPath::compute() and
96+
/// AccessPath::computeInScope() mirror the AccessedStorage API.
97+
/// AccessPath::contains() and AccessPath::mayOverlap() provide efficient
98+
/// comparison of access paths.
99+
///
100+
/// AccessPath::collectUses() provides all reachable uses of the accessed
101+
/// storage, allowing the selection of Exact, Inner, or Overlapping uses.
102+
/// visitAccessedStorageUses() and visitAccessPathUses() generalize
103+
/// handling of all reachable uses for a given storage location.
87104
///
88105
//===----------------------------------------------------------------------===//
89106

@@ -1201,6 +1218,10 @@ SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);
12011218

12021219
namespace swift {
12031220

1221+
/// Return true if \p svi is a cast that preserves the identity and
1222+
/// reference-counting equivalence of the reference at operand zero.
1223+
bool isRCIdentityPreservingCast(SingleValueInstruction *svi);
1224+
12041225
/// If \p svi is an access projection, return an address-type operand for the
12051226
/// incoming address.
12061227
///

lib/SIL/IR/SILType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ bool SILType::isPointerSizeAndAligned() {
129129
//
130130
// TODO: handle casting to a loadable existential by generating
131131
// init_existential_ref. Until then, only promote to a heap object dest.
132+
//
133+
// This cannot allow trivial-to-reference casts, as required by
134+
// isRCIdentityPreservingCast.
132135
bool SILType::canRefCast(SILType operTy, SILType resultTy, SILModule &M) {
133136
auto fromTy = operTy.unwrapOptionalType();
134137
auto toTy = resultTy.unwrapOptionalType();

lib/SIL/Utils/InstructionUtils.cpp

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#define DEBUG_TYPE "sil-inst-utils"
1414
#include "swift/SIL/InstructionUtils.h"
15+
#include "swift/SIL/MemAccessUtils.h"
1516
#include "swift/AST/SubstitutionMap.h"
1617
#include "swift/Basic/NullablePtr.h"
1718
#include "swift/Basic/STLExtras.h"
@@ -64,20 +65,6 @@ SILValue swift::getUnderlyingObjectStopAtMarkDependence(SILValue v) {
6465
}
6566
}
6667

67-
static bool isRCIdentityPreservingCast(ValueKind Kind) {
68-
switch (Kind) {
69-
case ValueKind::UpcastInst:
70-
case ValueKind::UncheckedRefCastInst:
71-
case ValueKind::UnconditionalCheckedCastInst:
72-
case ValueKind::UnconditionalCheckedCastValueInst:
73-
case ValueKind::RefToBridgeObjectInst:
74-
case ValueKind::BridgeObjectToRefInst:
75-
return true;
76-
default:
77-
return false;
78-
}
79-
}
80-
8168
/// Return the underlying SILValue after stripping off identity SILArguments if
8269
/// we belong to a BB with one predecessor.
8370
SILValue swift::stripSinglePredecessorArgs(SILValue V) {
@@ -122,42 +109,39 @@ SILValue swift::stripSinglePredecessorArgs(SILValue V) {
122109
}
123110
}
124111

125-
SILValue swift::stripCastsWithoutMarkDependence(SILValue V) {
112+
SILValue swift::stripCastsWithoutMarkDependence(SILValue v) {
126113
while (true) {
127-
V = stripSinglePredecessorArgs(V);
128-
129-
auto K = V->getKind();
130-
if (isRCIdentityPreservingCast(K)
131-
|| K == ValueKind::UncheckedTrivialBitCastInst
132-
|| K == ValueKind::BeginAccessInst
133-
|| K == ValueKind::EndCOWMutationInst) {
134-
V = cast<SingleValueInstruction>(V)->getOperand(0);
135-
continue;
114+
v = stripSinglePredecessorArgs(v);
115+
if (auto *svi = dyn_cast<SingleValueInstruction>(v)) {
116+
if (isRCIdentityPreservingCast(svi)
117+
|| isa<UncheckedTrivialBitCastInst>(v)
118+
|| isa<BeginAccessInst>(v)
119+
|| isa<EndCOWMutationInst>(v)) {
120+
v = svi->getOperand(0);
121+
continue;
122+
}
136123
}
137-
138-
return V;
124+
return v;
139125
}
140126
}
141127

142128
SILValue swift::stripCasts(SILValue v) {
143129
while (true) {
144130
v = stripSinglePredecessorArgs(v);
145-
146-
auto k = v->getKind();
147-
if (isRCIdentityPreservingCast(k)
148-
|| k == ValueKind::UncheckedTrivialBitCastInst
149-
|| k == ValueKind::MarkDependenceInst
150-
|| k == ValueKind::BeginAccessInst) {
151-
v = cast<SingleValueInstruction>(v)->getOperand(0);
152-
continue;
131+
if (auto *svi = dyn_cast<SingleValueInstruction>(v)) {
132+
if (isRCIdentityPreservingCast(svi)
133+
|| isa<UncheckedTrivialBitCastInst>(v)
134+
|| isa<MarkDependenceInst>(v)
135+
|| isa<BeginAccessInst>(v)) {
136+
v = cast<SingleValueInstruction>(v)->getOperand(0);
137+
continue;
138+
}
153139
}
154-
155140
SILValue v2 = stripOwnershipInsts(v);
156141
if (v2 != v) {
157142
v = v2;
158143
continue;
159144
}
160-
161145
return v;
162146
}
163147
}

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,38 @@ bool swift::isLetAddress(SILValue address) {
365365
// MARK: FindReferenceRoot
366366
//===----------------------------------------------------------------------===//
367367

368+
// On some platforms, casting from a metatype to a reference type dynamically
369+
// allocates a ref-counted box for the metatype. Naturally that is the place
370+
// where RC-identity begins. Considering the source of such a casts to be
371+
// RC-identical would confuse ARC optimization, which might eliminate a retain
372+
// of such an object completely.
373+
//
374+
// The SILVerifier checks that none of these operations cast a nontrivial value
375+
// to a reference except unconditional_checked_cast[_value].
376+
bool swift::isRCIdentityPreservingCast(SingleValueInstruction *svi) {
377+
switch (svi->getKind()) {
378+
default:
379+
return false;
380+
// Ignore ownership casts
381+
case SILInstructionKind::CopyValueInst:
382+
case SILInstructionKind::BeginBorrowInst:
383+
// Ignore class type casts
384+
case SILInstructionKind::UpcastInst:
385+
case SILInstructionKind::UncheckedRefCastInst:
386+
case SILInstructionKind::RefToBridgeObjectInst:
387+
case SILInstructionKind::BridgeObjectToRefInst:
388+
return true;
389+
case SILInstructionKind::UnconditionalCheckedCastInst:
390+
case SILInstructionKind::UnconditionalCheckedCastValueInst:
391+
// If the source is nontrivial, then this checked cast may actually create a
392+
// new object, so its source is not ref-count equivalent.
393+
return !svi->getOperand(0)->getType().isTrivial(*svi->getFunction());
394+
}
395+
}
396+
368397
namespace {
369398

370399
// Essentially RC identity where the starting point is already a reference.
371-
//
372-
// FIXME: We cannot currently see through type casts for true RC identity,
373-
// because property indices are not unique within a class hierarchy. Either fix
374-
// RefElementAddr::getFieldNo so it returns a unique index, or figure out a
375-
// different way to encode the property's VarDecl. (Note that the lack of a
376-
// unique property index could be the source of bugs elsewhere).
377400
class FindReferenceRoot {
378401
SmallPtrSet<SILPhiArgument *, 4> visitedPhis;
379402

@@ -386,18 +409,13 @@ class FindReferenceRoot {
386409

387410
protected:
388411
// Return an invalid value for a phi with no resolved inputs.
389-
//
390-
// FIXME: We should be able to see through RC identity like this:
391-
// nextRoot = stripRCIdentityCasts(nextRoot);
392412
SILValue recursiveFindRoot(SILValue ref) {
393-
while (true) {
394-
SILValue nextRoot = ref;
395-
nextRoot = stripOwnershipInsts(nextRoot);
396-
if (nextRoot == ref)
413+
while (auto *svi = dyn_cast<SingleValueInstruction>(ref)) {
414+
if (!isRCIdentityPreservingCast(svi)) {
397415
break;
398-
ref = nextRoot;
399-
}
400-
416+
}
417+
ref = svi->getOperand(0);
418+
};
401419
auto *phi = dyn_cast<SILPhiArgument>(ref);
402420
if (!phi || !phi->isPhiArgument()) {
403421
return ref;
@@ -558,8 +576,16 @@ const ValueDecl *AccessedStorage::getDecl(SILValue base) const {
558576
return global->getDecl();
559577

560578
case Class: {
561-
auto *decl = getObject()->getType().getNominalOrBoundGenericNominal();
562-
return decl ? getIndexedField(decl, getPropertyIndex()) : nullptr;
579+
// The property index is relative to the VarDecl in ref_element_addr, and
580+
// can only be reliably determined when the base is avaiable. Otherwise, we
581+
// can only make a best effort to extract it from the object type, which
582+
// might not even be a class in the case of bridge objects.
583+
if (ClassDecl *classDecl =
584+
base ? cast<RefElementAddrInst>(base)->getClassDecl()
585+
: getObject()->getType().getClassOrBoundGenericClass()) {
586+
return getIndexedField(classDecl, getPropertyIndex());
587+
}
588+
return nullptr;
563589
}
564590
case Tail:
565591
return nullptr;
@@ -1297,7 +1323,14 @@ void AccessPathDefUseTraversal::followProjection(SingleValueInstruction *svi,
12971323
AccessPathDefUseTraversal::UseKind
12981324
AccessPathDefUseTraversal::visitSingleValueUser(SingleValueInstruction *svi,
12991325
DFSEntry dfs) {
1300-
if (isAccessedStorageCast(svi)) {
1326+
if (dfs.isRef()) {
1327+
if (isRCIdentityPreservingCast(svi)) {
1328+
pushUsers(svi, dfs);
1329+
return IgnoredUse;
1330+
}
1331+
// 'svi' will be processed below as either RefElementAddrInst,
1332+
// RefTailAddrInst, or some unknown LeafUse.
1333+
} else if (isAccessedStorageCast(svi)) {
13011334
pushUsers(svi, dfs);
13021335
return IgnoredUse;
13031336
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3591,6 +3591,15 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
35913591
verifyOpenedArchetype(CI, CI->getType().getASTType());
35923592
}
35933593

3594+
// Make sure that opcodes handled by isRCIdentityPreservingCast cannot cast
3595+
// from a trivial to a reference type. Such a cast may dynamically
3596+
// instantiate a new reference-counted object.
3597+
void checkNoTrivialToReferenceCast(SingleValueInstruction *svi) {
3598+
require(!svi->getOperand(0)->getType().isTrivial(*svi->getFunction())
3599+
|| svi->getType().isTrivial(*svi->getFunction()),
3600+
"Unexpected trivial-to-reference conversion: ");
3601+
}
3602+
35943603
/// Verify if a given type is or contains an opened archetype or dynamic self.
35953604
/// If this is the case, verify that the provided instruction has a type
35963605
/// dependent operand for it.
@@ -3753,6 +3762,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
37533762
void checkUpcastInst(UpcastInst *UI) {
37543763
require(UI->getType() != UI->getOperand()->getType(),
37553764
"can't upcast to same type");
3765+
checkNoTrivialToReferenceCast(UI);
37563766
if (UI->getType().is<MetatypeType>()) {
37573767
CanType instTy(UI->getType().castTo<MetatypeType>()->getInstanceType());
37583768
require(UI->getOperand()->getType().is<MetatypeType>(),

0 commit comments

Comments
 (0)