Skip to content

Commit 925d63c

Browse files
committed
Fix isRCIdentityPreservingCast to handle trivial-to-reference casts
And add assertions.
1 parent 0f49dba commit 925d63c

File tree

5 files changed

+48
-40
lines changed

5 files changed

+48
-40
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,8 +1201,8 @@ SILBasicBlock::iterator removeBeginAccess(BeginAccessInst *beginAccess);
12011201

12021202
namespace swift {
12031203

1204-
/// Return true if \p value is a cast that preserves the identity of the
1205-
/// reference at operand zero.
1204+
/// Return true if \p value is a cast that preserves the identity and
1205+
/// reference-counting equivalence of the reference at operand zero.
12061206
bool isRCIdentityPreservingCast(SingleValueInstruction *svi);
12071207

12081208
/// If \p svi is an access projection, return an address-type operand for the

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: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,14 @@ 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].
368376
bool swift::isRCIdentityPreservingCast(SingleValueInstruction *svi) {
369377
switch (svi->getKind()) {
370378
default:
@@ -375,11 +383,14 @@ bool swift::isRCIdentityPreservingCast(SingleValueInstruction *svi) {
375383
// Ignore class type casts
376384
case SILInstructionKind::UpcastInst:
377385
case SILInstructionKind::UncheckedRefCastInst:
378-
case SILInstructionKind::UnconditionalCheckedCastInst:
379-
case SILInstructionKind::UnconditionalCheckedCastValueInst:
380386
case SILInstructionKind::RefToBridgeObjectInst:
381387
case SILInstructionKind::BridgeObjectToRefInst:
382388
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());
383394
}
384395
}
385396

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)