Skip to content

Commit a7c6a94

Browse files
committed
CheckedBranchInst now uses doesCastPreserveOwnership.
Use the new API that determines whether a cast preserves ownership. Remove an old hack.
1 parent 64ec981 commit a7c6a94

File tree

5 files changed

+121
-48
lines changed

5 files changed

+121
-48
lines changed

include/swift/SIL/SILInstruction.h

+10-24
Original file line numberDiff line numberDiff line change
@@ -1129,24 +1129,14 @@ class OwnershipForwardingMixin {
11291129
}
11301130

11311131
public:
1132-
/// If an instruction is directly forwarding, then any operand op whose
1133-
/// ownership it forwards into a result r must have the property that op and r
1134-
/// are "rc identical". This means that they are representing the same set of
1135-
/// 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.
11361135
///
1137-
/// An instruction that is not directly forwarding, can not have guaranteed
1138-
/// ownership since without direct forwarding, there isn't necessarily any
1139-
/// connection in between the operand's lifetime and the value's lifetime.
1140-
///
1141-
/// An example of this is checked_cast_br where when performing the following:
1142-
///
1143-
/// __SwiftValue(AnyHashable(Klass())) to OtherKlass()
1144-
///
1145-
/// we will look through the __SwiftValue(AnyHashable(X)) any just cast Klass
1146-
/// to OtherKlass. This means that the result argument would no longer be
1147-
/// rc-identical to the operand and default case and thus we can not propagate
1148-
/// forward any form of guaranteed ownership.
1149-
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; }
11501140

11511141
/// Forwarding ownership is determined by the forwarding instruction's
11521142
/// constant ownership attribute. If forwarding ownership is owned, then the
@@ -9064,16 +9054,12 @@ class CheckedCastBranchInst final
90649054
SILBasicBlock *SuccessBB, SILBasicBlock *FailureBB,
90659055
ProfileCounter Target1Count,
90669056
ProfileCounter Target2Count,
9067-
ValueOwnershipKind forwardingOwnershipKind)
9057+
ValueOwnershipKind forwardingOwnershipKind,
9058+
bool preservesOwnership)
90689059
: UnaryInstructionWithTypeDependentOperandsBase(
90699060
DebugLoc, Operand, TypeDependentOperands, SuccessBB, FailureBB,
90709061
Target1Count, Target2Count, forwardingOwnershipKind,
9071-
// We are always directly forwarding unless we are casting an
9072-
// AnyObject. This is b/c an AnyObject could contain a boxed
9073-
// AnyObject(Class()) that we unwrap as part of the cast. In such a
9074-
// case, we would return a different value and potentially end the
9075-
// lifetime of the operand value.
9076-
!Operand->getType().isAnyObject()),
9062+
preservesOwnership),
90779063
DestLoweredTy(DestLoweredTy), DestFormalTy(DestFormalTy),
90789064
IsExact(IsExact) {}
90799065

lib/SIL/IR/SILInstructions.cpp

+6-3
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/SILGen/SILGenBuilder.cpp

+4-4
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),

test/SILGen/opaque_values_silgen.swift

+49
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
// FIXME: "HECK" lines all need to be updated for OSSA.
66

7+
class C {}
8+
79
func genericInout<T>(_: inout T) {}
810

911
func hasVarArg(_ args: Any...) {}
@@ -384,3 +386,50 @@ func testEmptyReturnClosure() {
384386
let b = nil ?? { bar() }
385387
}
386388

389+
// Test that PatternMatchEmission::emitIsDispatch can emit a
390+
// class-to-AnyObject cast as a guaranteed scalar cast
391+
// (doesCastPreserveOwnershipForTypes returns true).
392+
//
393+
// CHECK-LABEL: sil hidden [ossa] @$s20opaque_values_silgen24testCastClassToAnyObjectyyXlAA1CCF : $@convention(thin) (@guaranteed C) -> @owned AnyObject {
394+
// CHECK: bb0(%0 : @guaranteed $C):
395+
// CHECK: checked_cast_br %0 : $C to AnyObject, bb2, bb1
396+
// CHECK: bb1(%{{.*}} : @guaranteed $C):
397+
// CHECK: bb2(%{{.*}} : @guaranteed $AnyObject):
398+
// CHECK-LABEL: } // end sil function
399+
func testCastClassToAnyObject(_ c: C) -> AnyObject {
400+
switch (c) {
401+
case let x as AnyObject:
402+
_ = x
403+
break
404+
}
405+
}
406+
407+
// CHECK-LABEL: sil hidden [ossa] @$s20opaque_values_silgen24testCastAnyObjectToClassyAA1CCyXlF : $@convention(thin) (@guaranteed AnyObject) -> @owned C {
408+
// CHECK: bb0(%0 : @guaranteed $AnyObject):
409+
// CHECK: [[CP:%.*]] = copy_value %0 : $AnyObject
410+
// CHECK: checked_cast_br [[CP]] : $AnyObject to C, bb1, bb2
411+
// CHECK-LABEL: } // end sil function '$s20opaque_values_silgen24testCastAnyObjectToClassyAA1CCyXlF'
412+
func testCastAnyObjectToClass(_ o: AnyObject) -> C {
413+
switch (o) {
414+
case let x as C:
415+
_ = x
416+
break
417+
default:
418+
break
419+
}
420+
}
421+
422+
// CHECK-LABEL: sil hidden [ossa] @$s20opaque_values_silgen024testCastClassArchetypeToF0yAA1CCxRlzClF : $@convention(thin) <T where T : AnyObject> (@guaranteed T) -> @owned C {
423+
// CHECK: bb0(%0 : @guaranteed $T):
424+
// CHECK: [[CP:%.*]] = copy_value %0 : $T
425+
// CHECK: checked_cast_br [[CP]] : $T to C, bb1, bb2
426+
// CHECK-LABEL: } // end sil function '$s20opaque_values_silgen024testCastClassArchetypeToF0yAA1CCxRlzClF'
427+
func testCastClassArchetypeToClass<T : AnyObject>(_ o: T) -> C {
428+
switch (o) {
429+
case let x as C:
430+
_ = x
431+
break
432+
default:
433+
break
434+
}
435+
}

test/SILOptimizer/rcidentity_opaque.sil

+52-17
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,24 @@ class Base {}
1010

1111
class Sub : Base {}
1212

13+
struct Bool {
14+
var value : Builtin.Int1
15+
}
16+
1317
protocol P {}
1418

1519
protocol PClass : AnyObject {}
1620

1721
protocol PBase : Base {}
1822

23+
public protocol Hashable {}
24+
25+
public struct AnyHashable: Hashable {
26+
internal var base: Any
27+
28+
public init<H: Hashable>(_ base: H)
29+
}
30+
1931
// Test dynamic casts that preserve ownership. See DynamicCasts.cpp
2032
// swift::doesCastPreserveOwnershipForTypes.
2133
//
@@ -24,6 +36,7 @@ protocol PBase : Base {}
2436
// (A) one type is a bridged value and the other is an object:
2537
// (A1) Boxing: <trivial> as! Object
2638
// (A2) Unboxing: Object as! <trivial>
39+
// (A3) Class-bridging: Error as! NSError
2740
//
2841
// (B) one type is transparently wrapped in __SwiftValue, while the other is
2942
// unwrapped. Given:
@@ -270,33 +283,46 @@ bb0(%0 : @owned $T):
270283
}
271284

272285
// =============================================================================
273-
// (B1) Wrapped casts - may forward through a wrapper object
274-
//
275-
// Note: the AnyHashable-to-AnyObject cases are currently covered
276-
// by the potentially bridged casts.
286+
// (A3) Class bridging
277287

278-
// TODO: The compiler could recognize this case as forwarded. Casting
279-
// *from* a class to AnyObject will not wrap the class.
288+
// Casting to NSError is indirect since it may conform to Error and
289+
// require Error-to-NSError bridging, unless we can statically see
290+
// that the source type inherits NSError.
291+
//
292+
// A class-constrained archetype may be bound to NSError, unless it has a
293+
// non-NSError superclass constraint. Casts to archetypes thus must always be
294+
// indirect.
280295
//
281-
// CHECK-LABEL: @testClassToClassArchetypeIsWrapped
296+
// CHECK-LABEL: @testClassToClassArchetypeIsBridged
282297
// CHECK: RESULT #0: 0 = 0
283298
// CHECK: RESULT #1: 1 = 1
284-
sil [ossa] @testClassToClassArchetypeIsWrapped : $@convention(thin) <U : AnyObject>(@owned Base) -> @owned U {
299+
sil [ossa] @testClassToClassArchetypeIsBridged : $@convention(thin) <U : AnyObject>(@owned Base) -> @owned U {
285300
bb0(%0 : @owned $Base):
286301
%1 = unconditional_checked_cast %0 : $Base to U
287302
return %1 : $U
288303
}
289304

290305
// =============================================================================
291-
// (B2) Wrapped casts - may forward through a wrapper object
306+
// (B1) __SwiftValue Wrapping
292307
//
293-
// Note: (B1) the AnyHashable-to-AnyObject cases are currently covered
294-
// by the potentially bridged casts.
308+
// Note: the AnyHashable-to-AnyObject cases are currently covered by
309+
// the same logic that checks for potentially bridged casts. We
310+
// include it here for completeness.
311+
312+
// CHECK-LABEL: @testNonClassToClassArchetypeIsWrapped
313+
// CHECK: RESULT #0: 0 = 0
314+
// CHECK: RESULT #1: 1 = 1
315+
sil [ossa] @testNonClassToClassArchetypeIsWrapped : $@convention(thin) <U : AnyObject>(@owned AnyHashable) -> @owned U {
316+
bb0(%0 : @owned $AnyHashable):
317+
%1 = unconditional_checked_cast %0 : $AnyHashable to U
318+
return %1 : $U
319+
}
320+
321+
// =============================================================================
322+
// (B2) __SwiftValue Unwrapping
295323
//
296324
// TODO: In the future, when the runtime stops wrapping nontrivial types inside
297-
// __SwiftValue, cases (B1) and (B2) above will no longer apply. At that time,
298-
// expand ownership preserving cast types to AnyObject. Then remove the
299-
// isPotentiallyAnyObject() check.
325+
// __SwiftValue, cases (B1) and (B2) will no longer apply.
300326

301327
// CHECK-LABEL: @testAnyObjectToClassIsWrapped
302328
// CHECK: RESULT #0: 0 = 0
@@ -310,9 +336,9 @@ bb0(%0 : @owned $AnyObject):
310336
// CHECK-LABEL: @testClassArchetypeToClassIsWrapped
311337
// CHECK: RESULT #0: 0 = 0
312338
// CHECK: RESULT #1: 1 = 1
313-
sil [ossa] @testClassArchetypeToClassIsWrapped : $@convention(thin) <U : AnyObject>(@owned U) -> @owned Sub {
314-
bb0(%0 : @owned $U):
315-
%1 = unconditional_checked_cast %0 : $U to Sub
339+
sil [ossa] @testClassArchetypeToClassIsWrapped : $@convention(thin) <T : AnyObject>(@owned T) -> @owned Sub {
340+
bb0(%0 : @owned $T):
341+
%1 = unconditional_checked_cast %0 : $T to Sub
316342
return %1 : $Sub
317343
}
318344

@@ -402,3 +428,12 @@ bb0(%0 : @owned $Base):
402428
%1 = unconditional_checked_cast %0 : $Base to Sub
403429
return %1 : $Sub
404430
}
431+
432+
// CHECK-LABEL: @testClassToAnyObjectIsForwarded
433+
// CHECK: RESULT #0: 0 = 0
434+
// CHECK: RESULT #1: 1 = 0
435+
sil [ossa] @testClassToAnyObjectIsForwarded : $@convention(thin) (@owned Base) -> @owned AnyObject {
436+
bb0(%0 : @owned $Base):
437+
%1 = unconditional_checked_cast %0 : $Base to AnyObject
438+
return %1 : $AnyObject
439+
}

0 commit comments

Comments
 (0)