Skip to content

Commit 62b5110

Browse files
committed
[sil] Add a new CastConsumptionKind called BorrowAlways.
This means that: 1. SILGenPattern always borrows the object before it emits a case. 2. Any cast with this cast has a +0 result. NOTE: That one can not use this with address types (so we assert if you pass this checked_cast_addr_br). NOTE: Once we have opaque values, checked_cast_br of a guaranteed value will lower to a copy + checked_cast_addr_br (assuming the operation is a consuming cast). To make sure this does not become a problem in terms of performance, we will need a pass that can transform SILGenPattern +0 cases to +1 cases. This is something that we have talked about in the past and I think it is reasonable to implement. This is an incremental commit towards fixing SILGenPattern for ownership. rdar://29791263
1 parent 2a18ea7 commit 62b5110

File tree

12 files changed

+93
-19
lines changed

12 files changed

+93
-19
lines changed

include/swift/SIL/Consumption.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,41 @@ enum class CastConsumptionKind : uint8_t {
4343
/// The source value is always left in place, and the destination
4444
/// value is copied into on success.
4545
CopyOnSuccess,
46+
47+
/// The source value is never taken, regardless of whether the cast
48+
/// succeeds. Instead, we always borrow the source value and feed it through.
49+
///
50+
/// NOTE: This can only be used with objects. We do not support borrowing of
51+
/// addresses. If an address is needed for a cast operation, a BorrowAlways
52+
/// value must be copied into a temporary and operated upon. If the result of
53+
/// the cast is a loadable type then the value is loaded using a
54+
/// load_borrow. If an address only value is returned, we continue processing
55+
/// the value as an owned TakeAlways value.
56+
BorrowAlways,
4657
};
4758

4859
/// Should the source value be destroyed if the cast fails?
4960
inline bool shouldDestroyOnFailure(CastConsumptionKind kind) {
50-
return (kind == CastConsumptionKind::TakeAlways);
61+
switch (kind) {
62+
case CastConsumptionKind::TakeAlways:
63+
return true;
64+
case CastConsumptionKind::TakeOnSuccess:
65+
case CastConsumptionKind::CopyOnSuccess:
66+
case CastConsumptionKind::BorrowAlways:
67+
return false;
68+
}
5169
}
5270

5371
/// Should the source value be taken if the cast succeeds?
5472
inline IsTake_t shouldTakeOnSuccess(CastConsumptionKind kind) {
55-
return IsTake_t(kind != CastConsumptionKind::CopyOnSuccess);
73+
switch (kind) {
74+
case CastConsumptionKind::TakeAlways:
75+
case CastConsumptionKind::TakeOnSuccess:
76+
return IsTake;
77+
case CastConsumptionKind::CopyOnSuccess:
78+
case CastConsumptionKind::BorrowAlways:
79+
return IsNotTake;
80+
}
5681
}
5782

5883
} // end namespace swift

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7402,7 +7402,10 @@ class CheckedCastAddrBranchInst
74027402
: InstructionBase(DebugLoc), ConsumptionKind(consumptionKind),
74037403
Operands{this, src, dest}, DestBBs{{this, successBB, Target1Count},
74047404
{this, failureBB, Target2Count}},
7405-
SourceType(srcType), TargetType(targetType) {}
7405+
SourceType(srcType), TargetType(targetType) {
7406+
assert(ConsumptionKind != CastConsumptionKind::BorrowAlways &&
7407+
"BorrowAlways is not supported on addresses");
7408+
}
74067409

74077410
public:
74087411
enum {

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
5757
/// Don't worry about adhering to the 80-column limit for this line.
58-
const uint16_t VERSION_MINOR = 452; // Last change: nominal types for operators
58+
const uint16_t VERSION_MINOR = 453; // Last change: borrow always
5959

6060
using DeclIDField = BCFixed<31>;
6161

lib/ParseSIL/ParseSIL.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3155,6 +3155,8 @@ bool SILParser::parseSILInstruction(SILBuilder &B) {
31553155
"cast consumption kind")) {
31563156
return true;
31573157
}
3158+
// NOTE: BorrowAlways is not a supported cast kind for address types, so we
3159+
// purposely do not parse it here.
31583160
auto kind = llvm::StringSwitch<Optional<CastConsumptionKind>>(
31593161
consumptionKindToken.str())
31603162
.Case("take_always", CastConsumptionKind::TakeAlways)

lib/SIL/SILPrinter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ static StringRef getCastConsumptionKindName(CastConsumptionKind kind) {
398398
case CastConsumptionKind::TakeAlways: return "take_always";
399399
case CastConsumptionKind::TakeOnSuccess: return "take_on_success";
400400
case CastConsumptionKind::CopyOnSuccess: return "copy_on_success";
401+
case CastConsumptionKind::BorrowAlways: return "borrow_always";
401402
}
402403
llvm_unreachable("bad cast consumption kind");
403404
}

lib/SIL/SILVerifier.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2860,9 +2860,15 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
28602860
return true;
28612861
}
28622862
case SILInstructionKind::CheckedCastAddrBranchInst:
2863-
if (cast<CheckedCastAddrBranchInst>(inst)->getConsumptionKind() !=
2864-
CastConsumptionKind::CopyOnSuccess)
2863+
switch (cast<CheckedCastAddrBranchInst>(inst)->getConsumptionKind()) {
2864+
case CastConsumptionKind::BorrowAlways:
2865+
llvm_unreachable("checked_cast_addr_br cannot have BorrowAlways");
2866+
case CastConsumptionKind::CopyOnSuccess:
2867+
break;
2868+
case CastConsumptionKind::TakeAlways:
2869+
case CastConsumptionKind::TakeOnSuccess:
28652870
return true;
2871+
}
28662872
break;
28672873
case SILInstructionKind::LoadInst:
28682874
// A 'non-taking' value load is harmless.

lib/SILGen/SILGenDynamicCast.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,16 @@ namespace {
229229
return;
230230
}
231231

232-
if (consumption == CastConsumptionKind::CopyOnSuccess) {
232+
switch (consumption) {
233+
case CastConsumptionKind::BorrowAlways:
234+
case CastConsumptionKind::CopyOnSuccess:
233235
SGF.B.createGuaranteedPhiArgument(operandValue.getType());
234236
handleFalse(None);
235-
} else {
237+
break;
238+
case CastConsumptionKind::TakeAlways:
239+
case CastConsumptionKind::TakeOnSuccess:
236240
handleFalse(SGF.B.createOwnedPhiArgument(operandValue.getType()));
241+
break;
237242
}
238243

239244
assert(!SGF.B.hasValidInsertionPoint() && "handler did not end block");

lib/SILGen/SILGenPattern.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,7 @@ static bool shouldTake(ConsumableManagedValue value, bool isIrrefutable) {
11651165
case CastConsumptionKind::TakeAlways: return true;
11661166
case CastConsumptionKind::TakeOnSuccess: return isIrrefutable;
11671167
case CastConsumptionKind::CopyOnSuccess: return false;
1168+
case CastConsumptionKind::BorrowAlways: return false;
11681169
}
11691170
llvm_unreachable("bad consumption kind");
11701171
}
@@ -1349,14 +1350,17 @@ static ConsumableManagedValue
13491350
getManagedSubobject(SILGenFunction &SGF, SILValue value,
13501351
const TypeLowering &valueTL,
13511352
CastConsumptionKind consumption) {
1352-
if (consumption == CastConsumptionKind::CopyOnSuccess) {
1353+
switch (consumption) {
1354+
case CastConsumptionKind::BorrowAlways:
1355+
case CastConsumptionKind::CopyOnSuccess:
13531356
return {ManagedValue::forUnmanaged(value), consumption};
1357+
case CastConsumptionKind::TakeAlways:
1358+
case CastConsumptionKind::TakeOnSuccess:
1359+
assert((!SGF.F.getModule().getOptions().EnableSILOwnership ||
1360+
consumption != CastConsumptionKind::TakeOnSuccess) &&
1361+
"TakeOnSuccess should never be used when sil ownership is enabled");
1362+
return {SGF.emitManagedRValueWithCleanup(value, valueTL), consumption};
13541363
}
1355-
1356-
assert((!SGF.F.getModule().getOptions().EnableSILOwnership ||
1357-
consumption != CastConsumptionKind::TakeOnSuccess) &&
1358-
"TakeOnSuccess should never be used when sil ownership is enabled");
1359-
return {SGF.emitManagedRValueWithCleanup(value, valueTL), consumption};
13601364
}
13611365

13621366
static ConsumableManagedValue
@@ -1873,6 +1877,7 @@ void PatternMatchEmission::emitEnumElementDispatch(
18731877
switch (src.getFinalConsumption()) {
18741878
case CastConsumptionKind::TakeAlways:
18751879
case CastConsumptionKind::CopyOnSuccess:
1880+
case CastConsumptionKind::BorrowAlways:
18761881
// No change to src necessary.
18771882
break;
18781883

@@ -1977,7 +1982,13 @@ void PatternMatchEmission::emitEnumElementDispatch(
19771982
eltValue = SGF.B.createUncheckedTakeEnumDataAddr(loc, srcValue,
19781983
elt, eltTy);
19791984
break;
1980-
1985+
case CastConsumptionKind::BorrowAlways:
1986+
// If we reach this point, we know that we have a loadable
1987+
// element type from an enum with mixed address
1988+
// only/loadable cases. Since we had an address only type,
1989+
// we assume that we will not have BorrowAlways since
1990+
// address only types do not support BorrowAlways.
1991+
llvm_unreachable("not allowed");
19811992
case CastConsumptionKind::CopyOnSuccess: {
19821993
auto copy = SGF.emitTemporaryAllocation(loc, srcValue->getType());
19831994
SGF.B.createCopyAddr(loc, srcValue, copy,

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,19 @@ SILInstruction *CastOptimizer::optimizeBridgedObjCToSwiftCast(
242242
}
243243

244244
if (auto *CCABI = dyn_cast<CheckedCastAddrBranchInst>(Inst)) {
245-
if (CCABI->getConsumptionKind() == CastConsumptionKind::TakeAlways) {
245+
switch (CCABI->getConsumptionKind()) {
246+
case CastConsumptionKind::TakeAlways:
246247
Builder.createReleaseValue(Loc, SrcOp, Builder.getDefaultAtomicity());
247-
} else if (CCABI->getConsumptionKind() ==
248-
CastConsumptionKind::TakeOnSuccess) {
248+
break;
249+
case CastConsumptionKind::TakeOnSuccess:
249250
// Insert a release in the success BB.
250251
Builder.setInsertionPoint(SuccessBB->begin());
251252
Builder.createReleaseValue(Loc, SrcOp, Builder.getDefaultAtomicity());
253+
break;
254+
case CastConsumptionKind::BorrowAlways:
255+
llvm_unreachable("checked_cast_addr_br never has BorrowAlways");
256+
case CastConsumptionKind::CopyOnSuccess:
257+
break;
252258
}
253259
}
254260

@@ -442,6 +448,7 @@ SILInstruction *CastOptimizer::optimizeBridgedSwiftToObjCCast(
442448
case CastConsumptionKind::TakeOnSuccess:
443449
needReleaseInSuccess = true;
444450
break;
451+
case CastConsumptionKind::BorrowAlways:
445452
case CastConsumptionKind::CopyOnSuccess:
446453
// Conservatively insert a retain/release pair around the conversion
447454
// function because the conversion function could decrement the
@@ -771,12 +778,21 @@ SILInstruction *CastOptimizer::simplifyCheckedCastAddrBranchInst(
771778
if (!Src->getType().isAddress() || !Dest->getType().isAddress()) {
772779
return nullptr;
773780
}
781+
774782
// For CopyOnSuccess casts, we could insert an explicit copy here, but this
775783
// case does not happen in practice.
784+
//
776785
// Both TakeOnSuccess and TakeAlways can be reduced to an
777786
// UnconditionalCheckedCast, since the failure path is irrelevant.
778-
if (Inst->getConsumptionKind() == CastConsumptionKind::CopyOnSuccess)
787+
switch (Inst->getConsumptionKind()) {
788+
case CastConsumptionKind::BorrowAlways:
789+
llvm_unreachable("checked_cast_addr_br never has BorrowAlways");
790+
case CastConsumptionKind::CopyOnSuccess:
779791
return nullptr;
792+
case CastConsumptionKind::TakeAlways:
793+
case CastConsumptionKind::TakeOnSuccess:
794+
break;
795+
}
780796

781797
if (!emitSuccessfulIndirectUnconditionalCast(Builder, Mod.getSwiftModule(),
782798
Loc, Src, SourceType, Dest,

lib/Serialization/DeserializeSIL.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,8 @@ static CastConsumptionKind getCastConsumptionKind(unsigned attr) {
789789
return CastConsumptionKind::TakeOnSuccess;
790790
case SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS:
791791
return CastConsumptionKind::CopyOnSuccess;
792+
case SIL_CAST_CONSUMPTION_BORROW_ALWAYS:
793+
return CastConsumptionKind::BorrowAlways;
792794
default:
793795
llvm_unreachable("not a valid CastConsumptionKind for SIL");
794796
}

lib/Serialization/SILFormat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ enum CastConsumptionKindEncoding : uint8_t {
7676
SIL_CAST_CONSUMPTION_TAKE_ALWAYS,
7777
SIL_CAST_CONSUMPTION_TAKE_ON_SUCCESS,
7878
SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS,
79+
SIL_CAST_CONSUMPTION_BORROW_ALWAYS,
7980
};
8081

8182
enum class KeyPathComponentKindEncoding : uint8_t {

lib/Serialization/SerializeSIL.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ static unsigned toStableCastConsumptionKind(CastConsumptionKind kind) {
8585
return SIL_CAST_CONSUMPTION_TAKE_ON_SUCCESS;
8686
case CastConsumptionKind::CopyOnSuccess:
8787
return SIL_CAST_CONSUMPTION_COPY_ON_SUCCESS;
88+
case CastConsumptionKind::BorrowAlways:
89+
return SIL_CAST_CONSUMPTION_BORROW_ALWAYS;
8890
}
8991
llvm_unreachable("bad cast consumption kind");
9092
}

0 commit comments

Comments
 (0)