Skip to content

Commit b68cafb

Browse files
committed
SIL: allow casts to class-bound archetypes to be done as scalar-casts instead of address-casts
This allows such casts to be done in embedded swift. rdar://156302495
1 parent 3bacfa7 commit b68cafb

File tree

9 files changed

+131
-24
lines changed

9 files changed

+131
-24
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from,
210210

211211
// If the destination type is known to have a Swift-compatible
212212
// implementation, use the most specific entrypoint.
213-
if (destClass && destClass->hasKnownSwiftImplementation()) {
213+
if ((destClass && destClass->hasKnownSwiftImplementation()) ||
214+
IGF.IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
214215
metadataRef = IGF.emitTypeMetadataRef(toType);
215216

216217
switch (mode) {

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,23 +1378,26 @@ bool swift::canIRGenUseScalarCheckedCastInstructions(SILModule &M,
13781378
// bridging, unless we can statically see that the source type inherits
13791379
// NSError.
13801380

1381-
// A class-constrained archetype may be bound to NSError, unless it has a
1382-
// non-NSError superclass constraint. Casts to archetypes thus must always be
1383-
// indirect.
13841381
if (auto archetype = targetFormalType->getAs<ArchetypeType>()) {
13851382
// Only ever permit this if the source type is a reference type.
13861383
if (!objectType.isAnyClassReferenceType())
13871384
return false;
1388-
1389-
auto super = archetype->getSuperclass();
1390-
if (super.isNull())
1391-
return false;
13921385

1393-
// A base class constraint that isn't NSError rules out the archetype being
1394-
// bound to NSError.
13951386
if (M.getASTContext().LangOpts.EnableObjCInterop) {
1387+
// A class-constrained archetype may be bound to NSError, unless it has a
1388+
// non-NSError superclass constraint. Casts to archetypes thus must always be
1389+
// indirect.
1390+
auto super = archetype->getSuperclass();
1391+
if (super.isNull())
1392+
return false;
1393+
1394+
// A base class constraint that isn't NSError rules out the archetype being
1395+
// bound to NSError.
13961396
if (auto nserror = M.Types.getNSErrorType())
13971397
return !super->isEqual(nserror);
1398+
} else {
1399+
if (!archetype->requiresClass())
1400+
return false;
13981401
}
13991402

14001403
// If NSError wasn't loaded, any base class constraint must not be NSError.

test/IRGen/dynamic_self_cast.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class SelfCasts {
3535
}
3636

3737
// CHECK-LABEL: define {{(dllexport )?}}{{(protected )?}}swiftcc ptr @"$s17dynamic_self_cast9SelfCastsC016classGenericFromD0xyRlzClFZ"(ptr %T, ptr swiftself %0)
38-
// CHECK: call zeroext i1 @swift_dynamicCast(ptr {{%.*}}, ptr {{%.*}}, ptr %0, ptr %T, {{.*}})
38+
// CHECK: call ptr @swift_dynamicCastUnknownClassUnconditional(ptr {{%.*}}, ptr %T, ptr null, i32 0, i32 0) #4
3939
// CHECK: ret
4040
public static func classGenericFromSelf<T : AnyObject>() -> T {
4141
let s = Self()
@@ -72,7 +72,7 @@ public class SelfCasts {
7272
}
7373

7474
// CHECK-LABEL: define {{(dllexport )?}}{{(protected )?}}swiftcc {{i32|i64}} @"$s17dynamic_self_cast9SelfCastsC016classGenericFromD11ConditionalxSgyRlzClFZ"(ptr %T, ptr swiftself %0)
75-
// CHECK: call zeroext i1 @swift_dynamicCast(ptr {{%.*}}, ptr {{%.*}}, ptr %0, ptr %T, {{.*}})
75+
// CHECK: call ptr @swift_dynamicCastUnknownClass(ptr {{%.*}}, ptr %T)
7676
// CHECK: ret
7777
public static func classGenericFromSelfConditional<T : AnyObject>() -> T? {
7878
let s = Self()

test/SILGen/dynamic_self_cast.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -Xllvm -sil-print-types -emit-silgen %s | %FileCheck %s
1+
// RUN: %target-swift-frontend -Xllvm -sil-print-types -disable-objc-interop -emit-silgen %s | %FileCheck %s
22

33
public class SelfCasts {
44
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC02toD0yACXDACFZ : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned SelfCasts {
@@ -31,7 +31,7 @@ public class SelfCasts {
3131
}
3232

3333
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD0xyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned T
34-
// CHECK: unconditional_checked_cast_addr @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
34+
// CHECK: unconditional_checked_cast {{.*}} : $SelfCasts to T
3535
// CHECK: }
3636
public static func classGenericFromSelf<T : AnyObject>() -> T {
3737
let s = Self()
@@ -68,7 +68,7 @@ public class SelfCasts {
6868
}
6969

7070
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD11ConditionalxSgyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned Optional<T> {
71-
// CHECK: checked_cast_addr_br take_always @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
71+
// CHECK: checked_cast_br @dynamic_self SelfCasts in {{.*}} : $SelfCasts to T
7272
// CHECK: }
7373
public static func classGenericFromSelfConditional<T : AnyObject>() -> T? {
7474
let s = Self()
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// RUN: %target-swift-frontend -Xllvm -sil-print-types -module-name=dynamic_self_cast -emit-silgen %s | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
public class SelfCasts {
6+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC02toD0yACXDACFZ : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned SelfCasts {
7+
// CHECK: unconditional_checked_cast {{.*}} : $SelfCasts to @dynamic_self SelfCasts
8+
// CHECK: }
9+
public static func toSelf(_ s: SelfCasts) -> Self {
10+
return s as! Self
11+
}
12+
13+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC09genericToD0yACXDxlFZ : $@convention(method) <T> (@in_guaranteed T, @thick SelfCasts.Type) -> @owned SelfCasts {
14+
// CHECK: unconditional_checked_cast_addr T in {{.*}} : $*T to @dynamic_self SelfCasts in {{.*}} : $*SelfCasts
15+
// CHECK: }
16+
public static func genericToSelf<T>(_ s: T) -> Self {
17+
return s as! Self
18+
}
19+
20+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC014classGenericToD0yACXDxRlzClFZ : $@convention(method) <T where T : AnyObject> (@guaranteed T, @thick SelfCasts.Type) -> @owned SelfCasts {
21+
// CHECK: unconditional_checked_cast {{.*}} : $T to @dynamic_self SelfCasts
22+
// CHECK: }
23+
public static func classGenericToSelf<T : AnyObject>(_ s: T) -> Self {
24+
return s as! Self
25+
}
26+
27+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC011genericFromD0xylFZ : $@convention(method) <T> (@thick SelfCasts.Type) -> @out T {
28+
// CHECK: unconditional_checked_cast_addr @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
29+
// CHECK: }
30+
public static func genericFromSelf<T>() -> T {
31+
let s = Self()
32+
return s as! T
33+
}
34+
35+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD0xyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned T
36+
// CHECK: unconditional_checked_cast_addr @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
37+
// CHECK: }
38+
public static func classGenericFromSelf<T : AnyObject>() -> T {
39+
let s = Self()
40+
return s as! T
41+
}
42+
43+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC02toD11ConditionalyACXDSgACFZ : $@convention(method) (@guaranteed SelfCasts, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
44+
// CHECK: checked_cast_br SelfCasts in {{.*}} : $SelfCasts to @dynamic_self SelfCasts
45+
// CHECK: }
46+
public static func toSelfConditional(_ s: SelfCasts) -> Self? {
47+
return s as? Self
48+
}
49+
50+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC09genericToD11ConditionalyACXDSgxlFZ : $@convention(method) <T> (@in_guaranteed T, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
51+
// CHECK: checked_cast_addr_br take_always T in {{.*}} : $*T to @dynamic_self SelfCasts in {{.*}} : $*SelfCasts
52+
// CHECK: }
53+
public static func genericToSelfConditional<T>(_ s: T) -> Self? {
54+
return s as? Self
55+
}
56+
57+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC014classGenericToD11ConditionalyACXDSgxRlzClFZ : $@convention(method) <T where T : AnyObject> (@guaranteed T, @thick SelfCasts.Type) -> @owned Optional<SelfCasts> {
58+
// CHECK: checked_cast_br T in {{.*}} : $T to @dynamic_self SelfCasts
59+
// CHECK: }
60+
public static func classGenericToSelfConditional<T : AnyObject>(_ s: T) -> Self? {
61+
return s as? Self
62+
}
63+
64+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC011genericFromD11ConditionalxSgylFZ : $@convention(method) <T> (@thick SelfCasts.Type) -> @out Optional<T> {
65+
// CHECK: checked_cast_addr_br take_always @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
66+
// CHECK: }
67+
public static func genericFromSelfConditional<T>() -> T? {
68+
let s = Self()
69+
return s as? T
70+
}
71+
72+
// CHECK-LABEL: sil [ossa] @$s17dynamic_self_cast9SelfCastsC016classGenericFromD11ConditionalxSgyRlzClFZ : $@convention(method) <T where T : AnyObject> (@thick SelfCasts.Type) -> @owned Optional<T> {
73+
// CHECK: checked_cast_addr_br take_always @dynamic_self SelfCasts in {{.*}} : $*SelfCasts to T in {{.*}} : $*T
74+
// CHECK: }
75+
public static func classGenericFromSelfConditional<T : AnyObject>() -> T? {
76+
let s = Self()
77+
return s as? T
78+
}
79+
80+
public required init() {}
81+
}
82+

test/SILGen/generic_casts.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -swift-version 5 -module-name generic_casts -Xllvm -sil-full-demangle %s | %FileCheck %s
2+
// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -disable-objc-interop -swift-version 5 -module-name generic_casts -Xllvm -sil-full-demangle %s | %FileCheck %s
33

44
protocol ClassBound : class {}
55
protocol NotClassBound {}
@@ -59,8 +59,7 @@ func class_archetype_to_class_archetype
5959
<T:ClassBound, U:ClassBound>(_ t:T) -> U {
6060
return t as! U
6161
// Error bridging can change the identity of class-constrained archetypes.
62-
// CHECK: unconditional_checked_cast_addr T in {{%.*}} : $*T to U in [[DOWNCAST_ADDR:%.*]] : $*U
63-
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
62+
// CHECK: [[DOWNCAST:%.*]] = unconditional_checked_cast {{%.*}} : $T to U
6463
// CHECK: return [[DOWNCAST]] : $U
6564
}
6665

@@ -69,7 +68,7 @@ func class_archetype_is_class_archetype
6968
<T:ClassBound, U:ClassBound>(_ t:T, u:U.Type) -> Bool {
7069
return t is U
7170
// Error bridging can change the identity of class-constrained archetypes.
72-
// CHECK: checked_cast_addr_br {{.*}} T in {{%.*}} : $*T to U in {{%.*}} : $*U
71+
// CHECK: checked_cast_br T in {{%.*}} : $T to U
7372
}
7473

7574
// CHECK-LABEL: sil hidden [ossa] @$s13generic_casts38opaque_archetype_to_addr_only_concrete{{[_0-9a-zA-Z]*}}F
@@ -158,16 +157,15 @@ func opaque_existential_is_class_archetype
158157
func class_existential_to_class_archetype
159158
<T:ClassBound>(_ p:ClassBound) -> T {
160159
return p as! T
161-
// CHECK: unconditional_checked_cast_addr any ClassBound in {{%.*}} : $*any ClassBound to T in [[DOWNCAST_ADDR:%.*]] : $*T
162-
// CHECK: [[DOWNCAST:%.*]] = load [take] [[DOWNCAST_ADDR]]
160+
// CHECK: [[DOWNCAST:%.*]] = unconditional_checked_cast {{%.*}} : $any ClassBound to T
163161
// CHECK: return [[DOWNCAST]] : $T
164162
}
165163

166164
// CHECK-LABEL: sil hidden [ossa] @$s13generic_casts021class_existential_is_C10_archetype{{[_0-9a-zA-Z]*}}F
167165
func class_existential_is_class_archetype
168166
<T:ClassBound>(_ p:ClassBound, _: T) -> Bool {
169167
return p is T
170-
// CHECK: checked_cast_addr_br {{.*}} any ClassBound in {{%.*}} : $*any ClassBound to T in {{%.*}} : $*T
168+
// CHECK: checked_cast_br any ClassBound in {{%.*}} : $any ClassBound to T
171169
}
172170

173171
// CHECK-LABEL: sil hidden [ossa] @$s13generic_casts40opaque_existential_to_addr_only_concrete{{[_0-9a-zA-Z]*}}F

test/SILOptimizer/assemblyvision_remark/cast_remarks.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
// REQUIRES: optimized_stdlib
44
// REQUIRES: swift_stdlib_no_asserts
5+
// REQUIRES: OS=macosx
56

67
///////////////////
78
// Generic Casts //

test/SILOptimizer/rcidentity_opaque.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt -rc-id-dumper -enable-sil-opaque-values -module-name Swift %s -o /dev/null | %FileCheck %s
1+
// RUN: %target-sil-opt -rc-id-dumper -enable-sil-opaque-values -disable-objc-interop -module-name Swift %s -o /dev/null | %FileCheck %s
22

33
import Builtin
44

@@ -295,7 +295,7 @@ bb0(%0 : @owned $T):
295295
//
296296
// CHECK-LABEL: @testClassToClassArchetypeIsBridged
297297
// CHECK: RESULT #0: 0 = 0
298-
// CHECK: RESULT #1: 1 = 1
298+
// CHECK: RESULT #1: 1 = 0
299299
sil [ossa] @testClassToClassArchetypeIsBridged : $@convention(thin) <U : AnyObject>(@owned Base) -> @owned U {
300300
bb0(%0 : @owned $Base):
301301
%1 = unconditional_checked_cast %0 : $Base to U

test/embedded/existential-class-bound1.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
protocol ClassBound: AnyObject {
1111
func foo()
1212
func bar()
13+
func predicate() -> Bool
1314
}
1415

1516
class MyClass {}
@@ -230,6 +231,22 @@ func testP4() -> any P4 {
230231
return C4(t: K4(x: 437))
231232
}
232233

234+
var gg: any ClassBound = MyClass()
235+
236+
extension ClassBound {
237+
public func isSame(_ rhs: some ClassBound) -> Bool {
238+
if let rhs = rhs as? Self {
239+
return rhs.predicate()
240+
}
241+
return false
242+
}
243+
public func predicate() -> Bool { true }
244+
}
245+
246+
@inline(never)
247+
func testIsSame(_ p: any ClassBound) -> Bool {
248+
return p.isSame(gg)
249+
}
233250

234251

235252
@main
@@ -261,6 +278,11 @@ struct Main {
261278
// CHECK: 102
262279
testP4().foo()
263280
// CHECK: 437
281+
282+
print(testIsSame(MyClass()))
283+
// CHECK: true
284+
print(testIsSame(MyOtherClass()))
285+
// CHECK: false
264286
}
265287
}
266288

0 commit comments

Comments
 (0)