Skip to content
This repository was archived by the owner on Jan 10, 2023. It is now read-only.

Commit a5700a7

Browse files
committed
Merge branch 'main' of github.com:apple/swift into tensorflow-stage
* 'main' of github.com:apple/swift: [DynamicCast] Rely on runtime when casts can't be optimized (swiftlang#33761)
2 parents fe8f184 + b0675c0 commit a5700a7

File tree

4 files changed

+61
-27
lines changed

4 files changed

+61
-27
lines changed

lib/IRGen/GenCast.cpp

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,8 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
478478
CheckedCastMode mode) {
479479
// If ObjC interop is enabled, casting a metatype to AnyObject succeeds
480480
// if the metatype is for a class.
481-
482-
auto triviallyFail = [&]() -> llvm::Value* {
483-
return llvm::ConstantPointerNull::get(IGF.IGM.ObjCPtrTy);
484-
};
485-
486481
if (!IGF.IGM.ObjCInterop)
487-
return triviallyFail();
482+
return nullptr;
488483

489484
switch (type->getRepresentation()) {
490485
case MetatypeRepresentation::ObjC:
@@ -496,7 +491,7 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
496491
// TODO: Final class metatypes could in principle be thin.
497492
assert(!type.getInstanceType()->mayHaveSuperclass()
498493
&& "classes should not have thin metatypes (yet)");
499-
return triviallyFail();
494+
return nullptr;
500495

501496
case MetatypeRepresentation::Thick: {
502497
auto instanceTy = type.getInstanceType();
@@ -508,10 +503,10 @@ llvm::Value *irgen::emitMetatypeToAnyObjectDowncast(IRGenFunction &IGF,
508503
return IGF.Builder.CreateBitCast(heapMetadata, IGF.IGM.ObjCPtrTy);
509504
}
510505

511-
// Is the type obviously not a class?
512-
if (!isa<ArchetypeType>(instanceTy)
513-
&& !isa<ExistentialMetatypeType>(type))
514-
return triviallyFail();
506+
// If it's not a class, we can't handle it here
507+
if (!isa<ArchetypeType>(instanceTy) && !isa<ExistentialMetatypeType>(type)) {
508+
return nullptr;
509+
}
515510

516511
// Ask the runtime whether this is class metadata.
517512
llvm::Constant *castFn;
@@ -966,10 +961,43 @@ void irgen::emitScalarCheckedCast(IRGenFunction &IGF,
966961
// Otherwise, this is a metatype-to-object cast.
967962
assert(targetLoweredType.isAnyClassReferenceType());
968963

969-
// Convert the metatype value to AnyObject.
964+
// Can we convert the metatype value to AnyObject using Obj-C machinery?
970965
llvm::Value *object =
971966
emitMetatypeToAnyObjectDowncast(IGF, metatypeVal, sourceMetatype, mode);
972967

968+
if (object == nullptr) {
969+
// Obj-C cast routine failed, use swift_dynamicCast instead
970+
971+
if (sourceMetatype->getRepresentation() == MetatypeRepresentation::Thin
972+
|| metatypeVal == nullptr) {
973+
// Earlier stages *should* never generate a checked cast with a thin metatype argument.
974+
// TODO: Move this assertion up to apply to all checked cast operations.
975+
// In assert builds, enforce this by failing here:
976+
assert(false && "Invalid SIL: General checked_cast_br cannot have thin argument");
977+
// In non-assert builds, stay compatible with previous behavior by emitting a null load.
978+
object = llvm::ConstantPointerNull::get(IGF.IGM.ObjCPtrTy);
979+
} else {
980+
Address src = IGF.createAlloca(metatypeVal->getType(),
981+
IGF.IGM.getPointerAlignment(),
982+
"castSrc");
983+
IGF.Builder.CreateStore(metatypeVal, src);
984+
llvm::PointerType *destPtrType = IGF.IGM.getStoragePointerType(targetLoweredType);
985+
Address dest = IGF.createAlloca(destPtrType,
986+
IGF.IGM.getPointerAlignment(),
987+
"castDest");
988+
IGF.Builder.CreateStore(llvm::ConstantPointerNull::get(destPtrType), dest);
989+
llvm::Value *success = emitCheckedCast(IGF,
990+
src, sourceFormalType,
991+
dest, targetFormalType,
992+
CastConsumptionKind::TakeAlways,
993+
mode);
994+
llvm::Value *successResult = IGF.Builder.CreateLoad(dest);
995+
llvm::Value *failureResult = llvm::ConstantPointerNull::get(destPtrType);
996+
llvm::Value *result = IGF.Builder.CreateSelect(success, successResult, failureResult);
997+
object = std::move(result);
998+
}
999+
}
1000+
9731001
sourceFormalType = IGF.IGM.Context.getAnyObjectType();
9741002
sourceLoweredType = SILType::getPrimitiveObjectType(sourceFormalType);
9751003

test/Casting/Casts.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,12 +522,7 @@ class ClassInt: Equatable, Hashable {
522522
static func == (lhs: ClassInt, rhs: ClassInt) -> Bool {return true}
523523
func hash(into hasher: inout Hasher) {}
524524
}
525-
CastsTests.test("AnyHashable(Class) -> Obj-C -> Class")
526-
.skip(.custom({
527-
!_isDebugAssertConfiguration()
528-
},
529-
reason: "Cast optimizer breaks this test"))
530-
.code {
525+
CastsTests.test("AnyHashable(Class) -> Obj-C -> Class") {
531526
let a = ClassInt()
532527
let b = runtimeCast(a, to: AnyHashable.self)!
533528
let c = _bridgeAnythingToObjectiveC(b)

test/IRGen/casts.sil

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,9 @@ bb3(%9 : $Optional<CP>):
298298
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @checked_metatype_to_object_casts
299299
sil @checked_metatype_to_object_casts : $@convention(thin) <T> (@thick Any.Type) -> () {
300300
entry(%e : $@thick Any.Type):
301-
%a = metatype $@thin NotClass.Type
302-
// CHECK: br i1 false
303-
checked_cast_br %a : $@thin NotClass.Type to AnyObject, a_yea, a_nay
301+
%a = metatype $@thick NotClass.Type
302+
// CHECK: call i1 @swift_dynamicCast({{.*}})
303+
checked_cast_br %a : $@thick NotClass.Type to AnyObject, a_yea, a_nay
304304
a_yea(%1 : $AnyObject):
305305
%b = metatype $@thick A.Type
306306
// CHECK: bitcast %swift.type* {{%.*}} to %objc_object*

validation-test/Casting/BoxingCasts.swift.gyb

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,27 @@
1616
// RUN: %empty-directory(%t)
1717
//
1818
// RUN: %gyb %s -o %t/BoxingCasts.swift
19-
// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -module-name a -swift-version 5 -Onone %t/BoxingCasts.swift -o %t/a.swift5.Onone.out
19+
//
20+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -module-name a -Onone -swift-version 5 %t/BoxingCasts.swift -o %t/a.swift5.Onone.out
2021
// RUN: %target-codesign %t/a.swift5.Onone.out
2122
// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift5.Onone.out
2223
//
23-
// Note: The RUN directives above override the default test optimizations.
24-
// This test is deliberately run non-optimized in order to verify the
25-
// behavior of runtime methods that may not be called for optimized casts.
24+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -O -module-name a -O -swift-version 5 %t/BoxingCasts.swift -o %t/a.swift5.O.out
25+
// RUN: %target-codesign %t/a.swift5.O.out
26+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift5.O.out
27+
//
28+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -module-name a -Onone -swift-version 4 %t/BoxingCasts.swift -o %t/a.swift4.Onone.out
29+
// RUN: %target-codesign %t/a.swift4.Onone.out
30+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift4.Onone.out
2631
//
27-
// XXX FIXME XXX TODO XXX _Also_ build this with optimizations in order to
28-
// verify compiler behaviors.
32+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-build-swift -g -O -module-name a -O -swift-version 4 %t/BoxingCasts.swift -o %t/a.swift4.O.out
33+
// RUN: %target-codesign %t/a.swift4.O.out
34+
// RUN: %line-directive %t/BoxingCasts.swift -- %target-run %t/a.swift4.O.out
35+
//
36+
// Note: The RUN directives above override the default test optimizations.
37+
// This test is deliberately run both ways:
38+
// * optimized to verify compiler cast optimizations, and
39+
// * non-optimized to verify the runtime methods used for non-optimized casts.
2940
//
3041
// REQUIRES: executable_test
3142

0 commit comments

Comments
 (0)