Skip to content

Commit 4512717

Browse files
authored
Merge pull request #34274 from eeckstein/rc-identity
RCIdentityAnalysis: some refactoring to improve clarity.
2 parents 34bfbe2 + 77f1647 commit 4512717

File tree

1 file changed

+37
-28
lines changed

1 file changed

+37
-28
lines changed

lib/SILOptimizer/Analysis/RCIdentityAnalysis.cpp

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ static bool isNoPayloadEnum(SILValue V) {
3434
return !EI->hasOperand();
3535
}
3636

37+
/// Returns true if V is a valid operand of a cast which preserves RC identity.
38+
///
39+
/// V is a valid operand if it has a non-trivial type.
40+
/// RCIdentityAnalysis must not look through casts which cast from a trivial
41+
/// type, like a metatype, to something which is retainable, like an AnyObject.
42+
/// On some platforms such casts dynamically allocate a ref-counted box for the
43+
/// metatype. Naturally that is the place where a new rc-identity begins.
44+
/// Therefore such a cast is introducing a new rc identical object.
45+
///
46+
/// If we would look through such a cast, ARC optimizations would get confused
47+
/// and might eliminate a retain of such an object completely.
48+
static bool isValidRCIdentityCastOperand(SILValue V, SILFunction *F) {
49+
return !V->getType().isTrivial(*F);
50+
}
51+
3752
/// RC identity is more than a guarantee that references refer to the same
3853
/// object. It also means that reference counting operations on those references
3954
/// have the same semantics. If the types on either side of a cast do not have
@@ -42,35 +57,26 @@ static bool isNoPayloadEnum(SILValue V) {
4257
/// necessarily preserve RC identity because it may cast from a
4358
/// reference-counted type to a non-reference counted type, or from a larger to
4459
/// a smaller struct with fewer references.
45-
static bool isRCIdentityPreservingCast(ValueKind Kind) {
46-
switch (Kind) {
60+
static SILValue getRCIdentityPreservingCastOperand(SILValue V) {
61+
switch (V->getKind()) {
4762
case ValueKind::UpcastInst:
4863
case ValueKind::UncheckedRefCastInst:
4964
case ValueKind::UnconditionalCheckedCastInst:
5065
case ValueKind::InitExistentialRefInst:
5166
case ValueKind::OpenExistentialRefInst:
5267
case ValueKind::RefToBridgeObjectInst:
5368
case ValueKind::BridgeObjectToRefInst:
54-
case ValueKind::ConvertFunctionInst:
55-
return true;
69+
case ValueKind::ConvertFunctionInst: {
70+
auto *inst = cast<SingleValueInstruction>(V);
71+
SILValue castOp = inst->getOperand(0);
72+
if (isValidRCIdentityCastOperand(castOp, inst->getFunction()))
73+
return castOp;
74+
break;
75+
}
5676
default:
57-
return false;
77+
break;
5878
}
59-
}
60-
61-
/// Returns a null SILValue if V has a trivial type, otherwise returns V.
62-
///
63-
/// RCIdentityAnalysis must not look through casts which cast from a trivial
64-
/// type, like a metatype, to something which is retainable, like an AnyObject.
65-
/// On some platforms such casts dynamically allocate a ref-counted box for the
66-
/// metatype.
67-
/// Now, if the RCRoot of such an AnyObject would be a trivial type, ARC
68-
/// optimizations get confused and might eliminate a retain of such an object
69-
/// completely.
70-
static SILValue noTrivialType(SILValue V, SILFunction *F) {
71-
if (V->getType().isTrivial(*F))
72-
return SILValue();
73-
return V;
79+
return SILValue();
7480
}
7581

7682
//===----------------------------------------------------------------------===//
@@ -79,10 +85,8 @@ static SILValue noTrivialType(SILValue V, SILFunction *F) {
7985

8086
static SILValue stripRCIdentityPreservingInsts(SILValue V) {
8187
// First strip off RC identity preserving casts.
82-
if (isRCIdentityPreservingCast(V->getKind())) {
83-
auto *inst = cast<SingleValueInstruction>(V);
84-
return noTrivialType(inst->getOperand(0), inst->getFunction());
85-
}
88+
if (SILValue castOp = getRCIdentityPreservingCastOperand(V))
89+
return castOp;
8690

8791
// Then if we have a struct_extract that is extracting a non-trivial member
8892
// from a struct with no other non-trivial members, a ref count operation on
@@ -133,9 +137,14 @@ static SILValue stripRCIdentityPreservingInsts(SILValue V) {
133137
// since we will only visit it twice if we go around a back edge due to a
134138
// different SILArgument that is actually being used for its phi node like
135139
// purposes.
136-
if (auto *A = dyn_cast<SILPhiArgument>(V))
137-
if (SILValue Result = A->getSingleTerminatorOperand())
138-
return noTrivialType(Result, A->getFunction());
140+
if (auto *A = dyn_cast<SILPhiArgument>(V)) {
141+
if (SILValue Result = A->getSingleTerminatorOperand()) {
142+
// In case the terminator is a conditional cast, Result is the source of
143+
// the cast.
144+
if (isValidRCIdentityCastOperand(Result, A->getFunction()))
145+
return Result;
146+
}
147+
}
139148

140149
return SILValue();
141150
}
@@ -339,7 +348,7 @@ SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingArgs(SILValue V,
339348

340349
unsigned IVListSize = IncomingValues.size();
341350
if (IVListSize == 1 &&
342-
!noTrivialType(IncomingValues[0].second, A->getFunction()))
351+
!isValidRCIdentityCastOperand(IncomingValues[0].second, A->getFunction()))
343352
return SILValue();
344353

345354
assert(IVListSize != 1 && "Should have been handled in "

0 commit comments

Comments
 (0)