Skip to content

Cast Optimizer: bail out when we can't do the cast #13401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions lib/SILOptimizer/Utils/Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,40 @@ optimizeBridgedObjCToSwiftCast(SILInstruction *Inst,
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
/// instance into a bridged ObjC type.
SILInstruction *
Expand Down Expand Up @@ -1646,7 +1680,8 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
if (ResultsRef.size() != 1)
return nullptr;

auto MemberDeclRef = SILDeclRef(Results.front());
auto *resultDecl = Results.front();
auto MemberDeclRef = SILDeclRef(resultDecl);
auto *BridgedFunc = M.getOrCreateFunction(Loc, MemberDeclRef,
ForDefinition_t::NotForDefinition);

Expand Down Expand Up @@ -1677,6 +1712,11 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
SILType SubstFnTy = SILFnTy.substGenericArgs(M, SubMap);
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);
if (Src->getType().isAddress() && !substConv.isSILIndirect(ParamTypes[0])) {
// Create load
Expand Down Expand Up @@ -1811,6 +1851,9 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
// If it is addr cast then store the result.
auto ConvTy = NewAI->getType();
auto DestTy = Dest->getType().getObjectType();
assert(DestTy == SILType::getPrimitiveObjectType(
BridgedTargetTy->getCanonicalType()) &&
"Expected Dest Type to be the same as BridgedTargetTy");
SILValue CastedValue;
if (ConvTy == DestTy) {
CastedValue = NewAI;
Expand Down Expand Up @@ -1842,9 +1885,11 @@ optimizeBridgedSwiftToObjCCast(SILInstruction *Inst,
CastedValue =
SILValue(Builder.createUncheckedRefCast(Loc, NewAI, DestTy));
} else {
llvm_unreachable(
"Destination should have the same type, be bridgeable CF "
"type or be a superclass/subclass of the source operand");
llvm_unreachable("optimizeBridgedSwiftToObjCCast: should never reach "
"this condition: 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 we should "
"have bailed earlier");
}
NewI = Builder.createStore(Loc, CastedValue, Dest,
StoreOwnershipQualifier::Unqualified);
Expand Down
33 changes: 33 additions & 0 deletions test/SILOptimizer/bridged_casts_folding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -911,3 +911,36 @@ var anyHashable: AnyHashable = 0
public func testUncondCastSwiftToSubclass() -> 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)
}