@@ -34,6 +34,21 @@ static bool isNoPayloadEnum(SILValue V) {
34
34
return !EI->hasOperand ();
35
35
}
36
36
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
+
37
52
// / RC identity is more than a guarantee that references refer to the same
38
53
// / object. It also means that reference counting operations on those references
39
54
// / 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) {
42
57
// / necessarily preserve RC identity because it may cast from a
43
58
// / reference-counted type to a non-reference counted type, or from a larger to
44
59
// / 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 () ) {
47
62
case ValueKind::UpcastInst:
48
63
case ValueKind::UncheckedRefCastInst:
49
64
case ValueKind::UnconditionalCheckedCastInst:
50
65
case ValueKind::InitExistentialRefInst:
51
66
case ValueKind::OpenExistentialRefInst:
52
67
case ValueKind::RefToBridgeObjectInst:
53
68
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
+ }
56
76
default :
57
- return false ;
77
+ break ;
58
78
}
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 ();
74
80
}
75
81
76
82
// ===----------------------------------------------------------------------===//
@@ -79,10 +85,8 @@ static SILValue noTrivialType(SILValue V, SILFunction *F) {
79
85
80
86
static SILValue stripRCIdentityPreservingInsts (SILValue V) {
81
87
// 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;
86
90
87
91
// Then if we have a struct_extract that is extracting a non-trivial member
88
92
// from a struct with no other non-trivial members, a ref count operation on
@@ -133,9 +137,14 @@ static SILValue stripRCIdentityPreservingInsts(SILValue V) {
133
137
// since we will only visit it twice if we go around a back edge due to a
134
138
// different SILArgument that is actually being used for its phi node like
135
139
// 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
+ }
139
148
140
149
return SILValue ();
141
150
}
@@ -339,7 +348,7 @@ SILValue RCIdentityFunctionInfo::stripRCIdentityPreservingArgs(SILValue V,
339
348
340
349
unsigned IVListSize = IncomingValues.size ();
341
350
if (IVListSize == 1 &&
342
- !noTrivialType (IncomingValues[0 ].second , A->getFunction ()))
351
+ !isValidRCIdentityCastOperand (IncomingValues[0 ].second , A->getFunction ()))
343
352
return SILValue ();
344
353
345
354
assert (IVListSize != 1 && " Should have been handled in "
0 commit comments