Skip to content

Commit f35e5e8

Browse files
authored
Merge pull request #42333 from atrick/fix-cast-ownership
Fix cast ownership to use the new doesCastPreserveOwnership API
2 parents 2c1550c + a7c6a94 commit f35e5e8

File tree

12 files changed

+158
-73
lines changed

12 files changed

+158
-73
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ class ForwardingOperand {
189189
return use->getOwnershipConstraint();
190190
}
191191

192-
bool isDirectlyForwarding() const {
192+
bool preservesOwnership() const {
193193
auto &mixin = *OwnershipForwardingMixin::get(use->getUser());
194-
return mixin.isDirectlyForwarding();
194+
return mixin.preservesOwnership();
195195
}
196196

197197
ValueOwnershipKind getForwardingOwnershipKind() const;

include/swift/SIL/SILInstruction.h

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,39 +1112,31 @@ class CopyLikeInstruction {
11121112
/// initializes the kind field on our object is run before our constructor runs.
11131113
class OwnershipForwardingMixin {
11141114
ValueOwnershipKind ownershipKind;
1115-
bool directlyForwards;
1115+
bool preservesOwnershipFlag;
11161116

11171117
protected:
11181118
OwnershipForwardingMixin(SILInstructionKind kind,
11191119
ValueOwnershipKind ownershipKind,
1120-
bool isDirectlyForwarding = true)
1121-
: ownershipKind(ownershipKind), directlyForwards(isDirectlyForwarding) {
1120+
bool preservesOwnership = true)
1121+
: ownershipKind(ownershipKind),
1122+
preservesOwnershipFlag(preservesOwnership) {
11221123
assert(isa(kind) && "Invalid subclass?!");
11231124
assert(ownershipKind && "invalid forwarding ownership");
1124-
assert((directlyForwards || ownershipKind != OwnershipKind::Guaranteed) &&
1125+
assert((preservesOwnershipFlag
1126+
|| ownershipKind != OwnershipKind::Guaranteed) &&
11251127
"Non directly forwarding instructions can not forward guaranteed "
11261128
"ownership");
11271129
}
11281130

11291131
public:
1130-
/// If an instruction is directly forwarding, then any operand op whose
1131-
/// ownership it forwards into a result r must have the property that op and r
1132-
/// are "rc identical". This means that they are representing the same set of
1133-
/// underlying lifetimes (plural b/c of aggregates).
1132+
/// A forwarding instruction preserved ownership if it has a
1133+
/// dynamically non-trivial result in which all references are forwarded from
1134+
/// the operand.
11341135
///
1135-
/// An instruction that is not directly forwarding, can not have guaranteed
1136-
/// ownership since without direct forwarding, there isn't necessarily any
1137-
/// connection in between the operand's lifetime and the value's lifetime.
1138-
///
1139-
/// An example of this is checked_cast_br where when performing the following:
1140-
///
1141-
/// __SwiftValue(AnyHashable(Klass())) to OtherKlass()
1142-
///
1143-
/// we will look through the __SwiftValue(AnyHashable(X)) any just cast Klass
1144-
/// to OtherKlass. This means that the result argument would no longer be
1145-
/// rc-identical to the operand and default case and thus we can not propagate
1146-
/// forward any form of guaranteed ownership.
1147-
bool isDirectlyForwarding() const { return directlyForwards; }
1136+
/// A cast can only forward guaranteed values if it preserves ownership. Such
1137+
/// casts cannot release any references within their operand's value and
1138+
/// cannot retain any references owned by their result.
1139+
bool preservesOwnership() const { return preservesOwnershipFlag; }
11481140

11491141
/// Forwarding ownership is determined by the forwarding instruction's
11501142
/// constant ownership attribute. If forwarding ownership is owned, then the
@@ -1160,7 +1152,7 @@ class OwnershipForwardingMixin {
11601152
return ownershipKind;
11611153
}
11621154
void setForwardingOwnershipKind(ValueOwnershipKind newKind) {
1163-
assert((isDirectlyForwarding() || newKind != OwnershipKind::Guaranteed) &&
1155+
assert((preservesOwnership() || newKind != OwnershipKind::Guaranteed) &&
11641156
"Non directly forwarding instructions can not forward guaranteed "
11651157
"ownership");
11661158
ownershipKind = newKind;
@@ -8083,9 +8075,9 @@ class OwnershipForwardingTermInst : public TermInst,
80838075
OwnershipForwardingTermInst(SILInstructionKind kind,
80848076
SILDebugLocation debugLoc,
80858077
ValueOwnershipKind ownershipKind,
8086-
bool isDirectlyForwarding = true)
8078+
bool preservesOwnership = true)
80878079
: TermInst(kind, debugLoc),
8088-
OwnershipForwardingMixin(kind, ownershipKind, isDirectlyForwarding) {
8080+
OwnershipForwardingMixin(kind, ownershipKind, preservesOwnership) {
80898081
assert(classof(kind));
80908082
}
80918083

@@ -9062,16 +9054,12 @@ class CheckedCastBranchInst final
90629054
SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB,
90639055
ProfileCounter Target1Count,
90649056
ProfileCounter Target2Count,
9065-
ValueOwnershipKind forwardingOwnershipKind)
9057+
ValueOwnershipKind forwardingOwnershipKind,
9058+
bool preservesOwnership)
90669059
: UnaryInstructionWithTypeDependentOperandsBase(
90679060
DebugLoc, Operand, TypeDependentOperands, SuccessBB, FailureBB,
90689061
Target1Count, Target2Count, forwardingOwnershipKind,
9069-
// We are always directly forwarding unless we are casting an
9070-
// AnyObject. This is b/c an AnyObject could contain a boxed
9071-
// AnyObject(Class()) that we unwrap as part of the cast. In such a
9072-
// case, we would return a different value and potentially end the
9073-
// lifetime of the operand value.
9074-
!Operand->getType().isAnyObject()),
9062+
preservesOwnership),
90759063
DestLoweredTy(DestLoweredTy), DestFormalTy(DestFormalTy),
90769064
IsExact(IsExact) {}
90779065

lib/SIL/IR/SILInstructions.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/Basic/AssertImplements.h"
2020
#include "swift/Basic/Unicode.h"
2121
#include "swift/Basic/type_traits.h"
22+
#include "swift/SIL/DynamicCasts.h"
2223
#include "swift/SIL/FormalLinkage.h"
2324
#include "swift/SIL/Projection.h"
2425
#include "swift/SIL/SILBuilder.h"
@@ -2283,16 +2284,18 @@ CheckedCastBranchInst *CheckedCastBranchInst::create(
22832284
SILBasicBlock *FailureBB, SILFunction &F,
22842285
ProfileCounter Target1Count, ProfileCounter Target2Count,
22852286
ValueOwnershipKind forwardingOwnershipKind) {
2286-
SILModule &Mod = F.getModule();
2287+
SILModule &module = F.getModule();
2288+
bool preservesOwnership = doesCastPreserveOwnershipForTypes(
2289+
module, Operand->getType().getASTType(), DestFormalTy);
22872290
SmallVector<SILValue, 8> TypeDependentOperands;
22882291
collectTypeDependentOperands(TypeDependentOperands, F, DestFormalTy);
22892292
unsigned size =
22902293
totalSizeToAlloc<swift::Operand>(1 + TypeDependentOperands.size());
2291-
void *Buffer = Mod.allocateInst(size, alignof(CheckedCastBranchInst));
2294+
void *Buffer = module.allocateInst(size, alignof(CheckedCastBranchInst));
22922295
return ::new (Buffer) CheckedCastBranchInst(
22932296
DebugLoc, IsExact, Operand, TypeDependentOperands, DestLoweredTy,
22942297
DestFormalTy, SuccessBB, FailureBB, Target1Count, Target2Count,
2295-
forwardingOwnershipKind);
2298+
forwardingOwnershipKind, preservesOwnership);
22962299
}
22972300

22982301
MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty,

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,18 @@ bool swift::doesCastPreserveOwnershipForTypes(SILModule &module,
320320
if (!canIRGenUseScalarCheckedCastInstructions(module, sourceType, targetType))
321321
return false;
322322

323-
return !sourceType->isPotentiallyAnyObject()
324-
&& !targetType->isPotentiallyAnyObject();
323+
// (B2) unwrapping
324+
if (sourceType->isPotentiallyAnyObject())
325+
return false;
326+
327+
// (B1) wrapping
328+
if (targetType->isPotentiallyAnyObject()) {
329+
// A class type cannot be wrapped in __SwiftValue, so casting
330+
// from a class to AnyObject preserves ownership.
331+
return
332+
sourceType->mayHaveSuperclass() || sourceType->isClassExistentialType();
333+
}
334+
return true;
325335
}
326336

327337
bool SILDynamicCastInst::isRCIdentityPreserving() const {

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ SILValue swift::findOwnershipReferenceAggregate(SILValue ref) {
925925
if (auto *term = arg->getSingleTerminator()) {
926926
if (term->isTransformationTerminator()) {
927927
auto *ti = cast<OwnershipForwardingTermInst>(term);
928-
if (ti->isDirectlyForwarding()) {
928+
if (ti->preservesOwnership()) {
929929
root = term->getOperand(0);
930930
continue;
931931
}

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ bool swift::canOpcodeForwardGuaranteedValues(SILValue value) {
3535
if (auto *arg = dyn_cast<SILArgument>(value))
3636
if (auto *ti = arg->getSingleTerminator())
3737
if (ti->isTransformationTerminator())
38-
return OwnershipForwardingMixin::get(ti)->isDirectlyForwarding();
38+
return OwnershipForwardingMixin::get(ti)->preservesOwnership();
3939

4040
if (auto *inst = value->getDefiningInstruction())
4141
if (auto *mixin = OwnershipForwardingMixin::get(inst))
42-
return mixin->isDirectlyForwarding() &&
42+
return mixin->preservesOwnership() &&
4343
!isa<OwnedFirstArgForwardingSingleValueInst>(inst);
4444

4545
return false;
4646
}
4747

4848
bool swift::canOpcodeForwardGuaranteedValues(Operand *use) {
4949
if (auto *mixin = OwnershipForwardingMixin::get(use->getUser()))
50-
return mixin->isDirectlyForwarding() &&
50+
return mixin->preservesOwnership() &&
5151
!isa<OwnedFirstArgForwardingSingleValueInst>(use->getUser());
5252
return false;
5353
}
@@ -58,11 +58,11 @@ bool swift::canOpcodeForwardOwnedValues(SILValue value) {
5858
if (auto *arg = dyn_cast<SILPhiArgument>(value))
5959
if (auto *predTerm = arg->getSingleTerminator())
6060
if (predTerm->isTransformationTerminator())
61-
return OwnershipForwardingMixin::get(predTerm)->isDirectlyForwarding();
61+
return OwnershipForwardingMixin::get(predTerm)->preservesOwnership();
6262

6363
if (auto *inst = value->getDefiningInstruction())
6464
if (auto *mixin = OwnershipForwardingMixin::get(inst))
65-
return mixin->isDirectlyForwarding() &&
65+
return mixin->preservesOwnership() &&
6666
!isa<GuaranteedFirstArgForwardingSingleValueInst>(inst);
6767

6868
return false;
@@ -71,7 +71,7 @@ bool swift::canOpcodeForwardOwnedValues(SILValue value) {
7171
bool swift::canOpcodeForwardOwnedValues(Operand *use) {
7272
auto *user = use->getUser();
7373
if (auto *mixin = OwnershipForwardingMixin::get(user))
74-
return mixin->isDirectlyForwarding() &&
74+
return mixin->preservesOwnership() &&
7575
!isa<GuaranteedFirstArgForwardingSingleValueInst>(user);
7676
return false;
7777
}
@@ -1078,7 +1078,7 @@ bool swift::getAllBorrowIntroducingValues(SILValue inputValue,
10781078
auto *arg = cast<SILPhiArgument>(value);
10791079
auto *termInst = arg->getSingleTerminator();
10801080
assert(termInst && termInst->isTransformationTerminator() &&
1081-
OwnershipForwardingMixin::get(termInst)->isDirectlyForwarding());
1081+
OwnershipForwardingMixin::get(termInst)->preservesOwnership());
10821082
assert(termInst->getNumOperands() == 1 &&
10831083
"Transforming terminators should always have a single operand");
10841084
worklist.push_back(termInst->getAllOperands()[0].get());
@@ -1130,7 +1130,7 @@ BorrowedValue swift::getSingleBorrowIntroducingValue(SILValue inputValue) {
11301130
auto *arg = cast<SILPhiArgument>(currentValue);
11311131
auto *termInst = arg->getSingleTerminator();
11321132
assert(termInst && termInst->isTransformationTerminator() &&
1133-
OwnershipForwardingMixin::get(termInst)->isDirectlyForwarding());
1133+
OwnershipForwardingMixin::get(termInst)->preservesOwnership());
11341134
assert(termInst->getNumOperands() == 1 &&
11351135
"Transformation terminators should only have single operands");
11361136
currentValue = termInst->getAllOperands()[0].get();
@@ -1183,7 +1183,7 @@ bool swift::getAllOwnedValueIntroducers(
11831183
auto *arg = cast<SILPhiArgument>(value);
11841184
auto *termInst = arg->getSingleTerminator();
11851185
assert(termInst && termInst->isTransformationTerminator() &&
1186-
OwnershipForwardingMixin::get(termInst)->isDirectlyForwarding());
1186+
OwnershipForwardingMixin::get(termInst)->preservesOwnership());
11871187
assert(termInst->getNumOperands() == 1 &&
11881188
"Transforming terminators should always have a single operand");
11891189
worklist.push_back(termInst->getAllOperands()[0].get());
@@ -1231,7 +1231,7 @@ OwnedValueIntroducer swift::getSingleOwnedValueIntroducer(SILValue inputValue) {
12311231
auto *arg = cast<SILPhiArgument>(currentValue);
12321232
auto *termInst = arg->getSingleTerminator();
12331233
assert(termInst && termInst->isTransformationTerminator() &&
1234-
OwnershipForwardingMixin::get(termInst)->isDirectlyForwarding());
1234+
OwnershipForwardingMixin::get(termInst)->preservesOwnership());
12351235
assert(termInst->getNumOperands()
12361236
- termInst->getNumTypeDependentOperands() == 1 &&
12371237
"Transformation terminators should only have single operands");

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4139,7 +4139,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
41394139
OwnershipKind::Guaranteed,
41404140
"checked_cast_br with an AnyObject typed source cannot forward "
41414141
"guaranteed ownership");
4142-
require(CBI->isDirectlyForwarding() ||
4142+
require(CBI->preservesOwnership() ||
41434143
CBI->getOperand().getOwnershipKind() !=
41444144
OwnershipKind::Guaranteed,
41454145
"If checked_cast_br is not directly forwarding, it can not have "

lib/SILGen/SILGenBuilder.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "SwitchEnumBuilder.h"
1919
#include "swift/AST/GenericSignature.h"
2020
#include "swift/AST/SubstitutionMap.h"
21+
#include "swift/SIL/DynamicCasts.h"
2122

2223
using namespace swift;
2324
using namespace Lowering;
@@ -527,10 +528,9 @@ void SILGenBuilder::createCheckedCastBranch(SILLocation loc, bool isExact,
527528
SILBasicBlock *falseBlock,
528529
ProfileCounter Target1Count,
529530
ProfileCounter Target2Count) {
530-
// Check if our source type is AnyObject. In such a case, we need to ensure
531-
// plus one our operand since SIL does not support guaranteed casts from an
532-
// AnyObject.
533-
if (op.getType().isAnyObject()) {
531+
// Casting a guaranteed value requires ownership preservation.
532+
if (!doesCastPreserveOwnershipForTypes(SGF.SGM.M, op.getType().getASTType(),
533+
destFormalTy)) {
534534
op = op.ensurePlusOne(SGF, loc);
535535
}
536536
createCheckedCastBranch(loc, isExact, op.forward(SGF),

lib/SILOptimizer/Mandatory/MoveOnlyChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ bool CopyOfBorrowedProjectionChecker::check(SILValue markedValue) {
257257
if (auto op = ForwardingOperand(use)) {
258258
// If our user is not directly forwarding, we cannot convert its
259259
// ownership to be guaranteed, so we treat it as a true consuming use.
260-
if (!op.isDirectlyForwarding()) {
260+
if (!op.preservesOwnership()) {
261261
foundConsumesOfBorrowedSubValues.push_back(user);
262262
liveness.updateForUse(user, /*lifetimeEnding*/ true);
263263
break;

lib/SILOptimizer/SemanticARC/OwnershipLiveRange.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ OwnershipLiveRange::OwnershipLiveRange(SILValue value)
9191
// here), we could get back a different value. Thus we can not transform
9292
// such a thing from owned to guaranteed.
9393
if (auto *i = OwnershipForwardingMixin::get(op->getUser())) {
94-
if (!i->isDirectlyForwarding()) {
94+
if (!i->preservesOwnership()) {
9595
tmpUnknownConsumingUses.push_back(op);
9696
continue;
9797
}

0 commit comments

Comments
 (0)