mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Cast Optimizer: optimizeBridgedSwiftToObjCCast - should never reach an unreachable code path: if the Destination does not have the same type, is not a bridgeable CF type and isn't a superclass/subclass of the source operand then bail before going through with the code generation.
This commit makes sure we bail early + adds a test case wherein we did not do that until now.
This commit is contained in:
@@ -1571,6 +1571,40 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst,
|
|||||||
return (NewI) ? NewI : AI;
|
return (NewI) ? NewI : AI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool canOptimizeCast(const swift::Type &BridgedTargetTy,
|
||||||
|
swift::SILModule &M,
|
||||||
|
swift::SILFunctionConventions &substConv) {
|
||||||
|
// DestTy is the type which we want to convert to
|
||||||
|
SILType DestTy =
|
||||||
|
SILType::getPrimitiveObjectType(BridgedTargetTy->getCanonicalType());
|
||||||
|
// ConvTy is the return type of the _bridgeToObjectiveCImpl()
|
||||||
|
auto ConvTy = substConv.getSILResultType().getObjectType();
|
||||||
|
if (ConvTy == DestTy) {
|
||||||
|
// Destination is the same type
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Check if a superclass/subclass of the source operand
|
||||||
|
if (DestTy.isExactSuperclassOf(ConvTy)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ConvTy.isExactSuperclassOf(DestTy)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// check if it is a bridgeable CF type
|
||||||
|
if (ConvTy.getSwiftRValueType() ==
|
||||||
|
getNSBridgedClassOfCFClass(M.getSwiftModule(),
|
||||||
|
DestTy.getSwiftRValueType())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (DestTy.getSwiftRValueType() ==
|
||||||
|
getNSBridgedClassOfCFClass(M.getSwiftModule(),
|
||||||
|
ConvTy.getSwiftRValueType())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// All else failed - can't optimize this case
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a call of _bridgeToObjectiveC which converts an _ObjectiveCBridgeable
|
/// Create a call of _bridgeToObjectiveC which converts an _ObjectiveCBridgeable
|
||||||
/// instance into a bridged ObjC type.
|
/// instance into a bridged ObjC type.
|
||||||
SILInstruction *
|
SILInstruction *
|
||||||
@@ -1646,7 +1680,8 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
|
|||||||
if (ResultsRef.size() != 1)
|
if (ResultsRef.size() != 1)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto MemberDeclRef = SILDeclRef(Results.front());
|
auto *resultDecl = Results.front();
|
||||||
|
auto MemberDeclRef = SILDeclRef(resultDecl);
|
||||||
auto *BridgedFunc = M.getOrCreateFunction(Loc, MemberDeclRef,
|
auto *BridgedFunc = M.getOrCreateFunction(Loc, MemberDeclRef,
|
||||||
ForDefinition_t::NotForDefinition);
|
ForDefinition_t::NotForDefinition);
|
||||||
|
|
||||||
@@ -1677,6 +1712,11 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
|
|||||||
SILType SubstFnTy = SILFnTy.substGenericArgs(M, SubMap);
|
SILType SubstFnTy = SILFnTy.substGenericArgs(M, SubMap);
|
||||||
SILFunctionConventions substConv(SubstFnTy.castTo<SILFunctionType>(), M);
|
SILFunctionConventions substConv(SubstFnTy.castTo<SILFunctionType>(), M);
|
||||||
|
|
||||||
|
// check that we can go through with the optimization
|
||||||
|
if (!canOptimizeCast(BridgedTargetTy, M, substConv)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
auto FnRef = Builder.createFunctionRef(Loc, BridgedFunc);
|
auto FnRef = Builder.createFunctionRef(Loc, BridgedFunc);
|
||||||
if (Src->getType().isAddress() && !substConv.isSILIndirect(ParamTypes[0])) {
|
if (Src->getType().isAddress() && !substConv.isSILIndirect(ParamTypes[0])) {
|
||||||
// Create load
|
// Create load
|
||||||
@@ -1811,6 +1851,9 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
|
|||||||
// If it is addr cast then store the result.
|
// If it is addr cast then store the result.
|
||||||
auto ConvTy = NewAI->getType();
|
auto ConvTy = NewAI->getType();
|
||||||
auto DestTy = Dest->getType().getObjectType();
|
auto DestTy = Dest->getType().getObjectType();
|
||||||
|
assert(DestTy == SILType::getPrimitiveObjectType(
|
||||||
|
BridgedTargetTy->getCanonicalType()) &&
|
||||||
|
"Expected Dest Type to be the same as BridgedTargetTy");
|
||||||
SILValue CastedValue;
|
SILValue CastedValue;
|
||||||
if (ConvTy == DestTy) {
|
if (ConvTy == DestTy) {
|
||||||
CastedValue = NewAI;
|
CastedValue = NewAI;
|
||||||
@@ -1842,9 +1885,11 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
|
|||||||
CastedValue =
|
CastedValue =
|
||||||
SILValue(Builder.createUncheckedRefCast(Loc, NewAI, DestTy));
|
SILValue(Builder.createUncheckedRefCast(Loc, NewAI, DestTy));
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable(
|
llvm_unreachable("optimizeBridgedSwiftToObjCCast: should never reach "
|
||||||
"Destination should have the same type, be bridgeable CF "
|
"this condition: if the Destination does not have the "
|
||||||
"type or be a superclass/subclass of the source operand");
|
"same type, is not a bridgeable CF type and isn't a "
|
||||||
|
"superclass/subclass of the source operand we should "
|
||||||
|
"have bailed earlier");
|
||||||
}
|
}
|
||||||
NewI = Builder.createStore(Loc, CastedValue, Dest,
|
NewI = Builder.createStore(Loc, CastedValue, Dest,
|
||||||
StoreOwnershipQualifier::Unqualified);
|
StoreOwnershipQualifier::Unqualified);
|
||||||
|
|||||||
@@ -911,3 +911,36 @@ var anyHashable: AnyHashable = 0
|
|||||||
public func testUncondCastSwiftToSubclass() -> NSObjectSubclass {
|
public func testUncondCastSwiftToSubclass() -> NSObjectSubclass {
|
||||||
return anyHashable as! NSObjectSubclass
|
return anyHashable as! NSObjectSubclass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MyThing: Hashable {
|
||||||
|
let name: String
|
||||||
|
|
||||||
|
init(name: String) {
|
||||||
|
self.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
Swift.print("Deinit \(name)")
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashValue: Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: MyThing, rhs: MyThing) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil hidden [noinline] @_T021bridged_casts_folding26doSomethingWithAnyHashableys0gH0VF : $@convention(thin) (@in AnyHashable) -> ()
|
||||||
|
// CHECK: checked_cast_addr_br take_always AnyHashable in %0 : $*AnyHashable to MyThing
|
||||||
|
@inline(never)
|
||||||
|
func doSomethingWithAnyHashable(_ item: AnyHashable) {
|
||||||
|
_ = item as? MyThing
|
||||||
|
}
|
||||||
|
|
||||||
|
@inline(never)
|
||||||
|
public func testMyThing() {
|
||||||
|
let x = MyThing(name: "B")
|
||||||
|
doSomethingWithAnyHashable(x)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user