Merge pull request #7779 from slavapestov/devirt-gardening

Simplify devirtualization and fix a bug
This commit is contained in:
Slava Pestov
2017-02-27 10:48:35 -08:00
committed by GitHub
6 changed files with 67 additions and 358 deletions

View File

@@ -54,9 +54,7 @@ DevirtualizationResult devirtualizeClassMethod(FullApplySite AI,
SILValue ClassInstance);
DevirtualizationResult tryDevirtualizeClassMethod(FullApplySite AI,
SILValue ClassInstance);
DevirtualizationResult tryDevirtualizeWitnessMethod(ApplySite AI);
/// Check if an upcast is legal.
bool isLegalUpcast(SILType FromTy, SILType ToTy);
DevirtualizationResult tryDevirtualizeWitnessMethod(ApplySite AI);
}
#endif

View File

@@ -110,22 +110,10 @@ SILValue isPartialApplyOfReabstractionThunk(PartialApplyInst *PAI);
/// - a type of the return value is a subclass of the expected return type.
/// - actual return type and expected return type differ in optionality.
/// - both types are tuple-types and some of the elements need to be casted.
///
/// If CheckOnly flag is set, then this function only checks if the
/// required casting is possible. If it is not possible, then None
/// is returned.
/// If CheckOnly is not set, then a casting code is generated and the final
/// casted value is returned.
Optional<SILValue> castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
SILValue Value,
SILType SrcTy,
SILType DestTy,
bool CheckOnly = false);
/// Check if the optimizer can cast a value into the expected,
/// ABI compatible type if necessary.
bool canCastValueToABICompatibleType(SILModule &M,
SILType SrcTy, SILType DestTy);
SILValue castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
SILValue Value,
SILType SrcTy,
SILType DestTy);
/// Returns a project_box if it is the next instruction after \p ABI and
/// and has \p ABI as operand. Otherwise it creates a new project_box right

View File

@@ -1875,23 +1875,6 @@ static bool isTryApplyOfConvertFunction(TryApplyInst *TAI,
if (!TargetFnTy || !TargetFnTy->hasErrorResult())
return false;
// Check if the converted function type has the same number of arguments.
// Currently this is always the case, but who knows what convert_function can
// do in the future?
unsigned numParams = OrigFnTy->getParameters().size();
if (TargetFnTy->getParameters().size() != numParams)
return false;
// Check that the argument types are matching.
SILModuleConventions silConv(TAI->getModule());
for (unsigned Idx = 0; Idx < numParams; Idx++) {
if (!canCastValueToABICompatibleType(
TAI->getModule(),
silConv.getSILType(OrigFnTy->getParameters()[Idx]),
silConv.getSILType(TargetFnTy->getParameters()[Idx])))
return false;
}
// Look through the conversions and find the real callee.
Callee = getActualCallee(CFI->getConverted());
CalleeType = Callee->getType();
@@ -1936,12 +1919,6 @@ bool SimplifyCFG::simplifyTryApplyBlock(TryApplyInst *TAI) {
auto ResultTy = calleeConv.getSILResultType();
auto OrigResultTy = TAI->getNormalBB()->getArgument(0)->getType();
// Bail if the cast between the actual and expected return types cannot
// be handled.
if (!canCastValueToABICompatibleType(TAI->getModule(),
ResultTy, OrigResultTy))
return false;
SILBuilderWithScope Builder(TAI);
auto TargetFnTy = CalleeFnTy;
@@ -1959,28 +1936,14 @@ bool SimplifyCFG::simplifyTryApplyBlock(TryApplyInst *TAI) {
}
SILFunctionConventions origConv(OrigFnTy, TAI->getModule());
unsigned numArgs = TAI->getNumArguments();
// First check if it is possible to convert all arguments.
// Currently we believe that castValueToABICompatibleType can handle all
// cases, so this check should never fail. We just do it to be absolutely
// sure that we don't crash.
for (unsigned i = 0; i < numArgs; ++i) {
if (!canCastValueToABICompatibleType(TAI->getModule(),
origConv.getSILArgumentType(i),
targetConv.getSILArgumentType(i))) {
return false;
}
}
SmallVector<SILValue, 8> Args;
unsigned numArgs = TAI->getNumArguments();
for (unsigned i = 0; i < numArgs; ++i) {
auto Arg = TAI->getArgument(i);
// Cast argument if required.
Arg = castValueToABICompatibleType(&Builder, TAI->getLoc(), Arg,
origConv.getSILArgumentType(i),
targetConv.getSILArgumentType(i))
.getValue();
targetConv.getSILArgumentType(i));
Args.push_back(Arg);
}
@@ -1998,8 +1961,7 @@ bool SimplifyCFG::simplifyTryApplyBlock(TryApplyInst *TAI) {
auto *NormalBB = TAI->getNormalBB();
auto CastedResult = castValueToABICompatibleType(&Builder, Loc, NewAI,
ResultTy, OrigResultTy)
.getValue();
ResultTy, OrigResultTy);
Builder.createBranch(Loc, NormalBB, { CastedResult });
TAI->eraseFromParent();

View File

@@ -546,31 +546,6 @@ bool swift::canDevirtualizeClassMethod(FullApplySite AI,
return false;
}
// Type of the actual function to be called.
CanSILFunctionType GenCalleeType = F->getLoweredFunctionType();
// Type of the actual function to be called with substitutions applied.
CanSILFunctionType SubstCalleeType = GenCalleeType;
// For polymorphic functions, bail if the number of substitutions is
// not the same as the number of expected generic parameters.
if (GenCalleeType->isPolymorphic()) {
// First, find proper list of substitutions for the concrete
// method to be called.
SmallVector<Substitution, 4> Subs;
getSubstitutionsForCallee(Mod, GenCalleeType,
ClassOrMetatypeType.getSwiftRValueType(),
AI, Subs);
SubstCalleeType = GenCalleeType->substGenericArgs(Mod, Subs);
}
// Check if the optimizer knows how to cast the return type.
SILType ReturnType =
SILFunctionConventions(SubstCalleeType, Mod).getSILResultType();
if (!canCastValueToABICompatibleType(Mod, ReturnType, AI.getType()))
return false;
return true;
}
@@ -612,8 +587,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI,
for (auto ResultTy : substConv.getIndirectSILResultTypes()) {
NewArgs.push_back(
castValueToABICompatibleType(&B, AI.getLoc(), *IndirectResultArgIter,
IndirectResultArgIter->getType(), ResultTy)
.getValue());
IndirectResultArgIter->getType(), ResultTy));
++IndirectResultArgIter;
}
@@ -623,8 +597,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI,
auto paramType = substConv.getSILType(param);
NewArgs.push_back(
castValueToABICompatibleType(&B, AI.getLoc(), *ParamArgIter,
ParamArgIter->getType(), paramType)
.getValue());
ParamArgIter->getType(), paramType));
++ParamArgIter;
}
@@ -634,7 +607,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI,
NewArgs.push_back(castValueToABICompatibleType(&B, AI.getLoc(),
ClassOrMetatype,
ClassOrMetatypeType,
SelfParamTy).getValue());
SelfParamTy));
SILType ResultTy = substConv.getSILResultType();
@@ -707,7 +680,7 @@ DevirtualizationResult swift::devirtualizeClassMethod(FullApplySite AI,
// Check if any casting is required for the return value.
ResultValue = castValueToABICompatibleType(&B, NewAI.getLoc(), ResultValue,
ResultTy, AI.getType()).getValue();
ResultTy, AI.getType());
DEBUG(llvm::dbgs() << " SUCCESS: " << F->getName() << "\n");
NumClassDevirt++;
@@ -871,75 +844,6 @@ static void getWitnessMethodSubstitutions(ApplySite AI, SILFunction *F,
origSubs, isDefaultWitness, NewSubs);
}
/// Check if an upcast is legal.
/// The logic in this function is heavily based on the checks in
/// the SILVerifier.
bool swift::isLegalUpcast(SILType FromTy, SILType ToTy) {
if (ToTy.is<MetatypeType>()) {
CanType InstTy(ToTy.castTo<MetatypeType>()->getInstanceType());
if (!FromTy.is<MetatypeType>())
return false;
CanType OpInstTy(FromTy.castTo<MetatypeType>()->getInstanceType());
auto InstClass = InstTy->getClassOrBoundGenericClass();
if (!InstClass)
return false;
bool CanBeUpcasted =
InstClass->usesObjCGenericsModel()
? InstClass->getDeclaredTypeInContext()->isBindableToSuperclassOf(
OpInstTy, nullptr)
: InstTy->isExactSuperclassOf(OpInstTy, nullptr);
return CanBeUpcasted;
}
// Upcast from Optional<B> to Optional<A> is legal as long as B is a
// subclass of A.
if (ToTy.getSwiftRValueType().getAnyOptionalObjectType() &&
FromTy.getSwiftRValueType().getAnyOptionalObjectType()) {
ToTy = SILType::getPrimitiveObjectType(
ToTy.getSwiftRValueType().getAnyOptionalObjectType());
FromTy = SILType::getPrimitiveObjectType(
FromTy.getSwiftRValueType().getAnyOptionalObjectType());
}
auto ToClass = ToTy.getClassOrBoundGenericClass();
if (!ToClass)
return false;
bool CanBeUpcasted =
ToClass->usesObjCGenericsModel()
? ToClass->getDeclaredTypeInContext()->isBindableToSuperclassOf(
FromTy.getSwiftRValueType(), nullptr)
: ToTy.isExactSuperclassOf(FromTy);
return CanBeUpcasted;
}
/// Check if we can pass/convert all arguments of the original apply
/// as required by the found devirtualized method.
/// FIXME: This method was introduced as a workaround. We need to
/// revisit it and check if it is still needed.
static bool
canPassOrConvertAllArguments(ApplySite AI,
CanSILFunctionType SubstCalleeCanType) {
SILFunctionConventions substConv(SubstCalleeCanType, AI.getModule());
unsigned substArgIdx = AI.getCalleeArgIndexOfFirstAppliedArg();
for (auto arg : AI.getArguments()) {
// Check if we can cast the provided argument into the required
// parameter type.
auto FromTy = arg->getType();
auto ToTy = substConv.getSILArgumentType(substArgIdx++);
// If types are the same, no conversion will be required.
if (FromTy == ToTy)
continue;
// Otherwise, it should be possible to upcast the arguments.
if (!isLegalUpcast(FromTy, ToTy))
return false;
}
assert(substArgIdx == substConv.getNumSILArguments());
return true;
}
/// Generate a new apply of a function_ref to replace an apply of a
/// witness_method when we've determined the actual function we'll end
/// up calling.
@@ -963,11 +867,6 @@ static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F,
auto CalleeCanType = F->getLoweredFunctionType();
auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, NewSubs);
// Bail if some of the arguments cannot be converted into
// types required by the found devirtualized method.
if (!canPassOrConvertAllArguments(AI, SubstCalleeCanType))
return ApplySite();
// Collect arguments from the apply instruction.
auto Arguments = SmallVector<SILValue, 4>();
@@ -979,7 +878,8 @@ static ApplySite devirtualizeWitnessMethod(ApplySite AI, SILFunction *F,
for (auto arg : AI.getArguments()) {
auto paramType = substConv.getSILArgumentType(substArgIdx++);
if (arg->getType() != paramType)
arg = B.createUpcast(AI.getLoc(), arg, paramType);
arg = castValueToABICompatibleType(&B, AI.getLoc(), arg,
arg->getType(), paramType);
Arguments.push_back(arg);
}
assert(substArgIdx == substConv.getNumSILArguments());
@@ -1030,26 +930,6 @@ static bool canDevirtualizeWitnessMethod(ApplySite AI) {
return false;
}
// Collect all the required substitutions.
//
// The complete set of substitutions may be different, e.g. because the found
// witness thunk F may have been created by a specialization pass and have
// additional generic parameters.
SmallVector<Substitution, 4> NewSubs;
getWitnessMethodSubstitutions(AI, F, WMI->getConformance(), NewSubs);
// Figure out the exact bound type of the function to be called by
// applying all substitutions.
auto &Module = AI.getModule();
auto CalleeCanType = F->getLoweredFunctionType();
auto SubstCalleeCanType = CalleeCanType->substGenericArgs(Module, NewSubs);
// Bail if some of the arguments cannot be converted into
// types required by the found devirtualized method.
if (!canPassOrConvertAllArguments(AI, SubstCalleeCanType))
return false;
return true;
}

View File

@@ -475,80 +475,63 @@ void swift::removeDeadBlock(SILBasicBlock *BB) {
///
/// NOTE: The implementation of this function is very closely related to the
/// rules checked by SILVerifier::requireABICompatibleFunctionTypes.
Optional<SILValue> swift::castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
SILValue swift::castValueToABICompatibleType(SILBuilder *B, SILLocation Loc,
SILValue Value,
SILType SrcTy, SILType DestTy,
bool CheckOnly) {
SILType SrcTy, SILType DestTy) {
// No cast is required if types are the same.
if (SrcTy == DestTy)
return Value;
SILValue CastedValue;
assert(SrcTy.isAddress() == DestTy.isAddress() &&
"Addresses aren't compatible with values");
if (SrcTy.isAddress() && DestTy.isAddress()) {
// Cast between two addresses and that's it.
if (CheckOnly)
return Value;
CastedValue = B->createUncheckedAddrCast(Loc, Value, DestTy);
return CastedValue;
return B->createUncheckedAddrCast(Loc, Value, DestTy);
}
if (SrcTy.isAddress() != DestTy.isAddress()) {
// Addresses aren't compatible with values.
if (CheckOnly)
return None;
llvm_unreachable("Addresses aren't compatible with values");
return SILValue();
}
auto &M = B->getModule();
// Check if src and dest types are optional.
auto OptionalSrcTy = SrcTy.getSwiftRValueType()
.getAnyOptionalObjectType();
auto OptionalDestTy = DestTy.getSwiftRValueType()
.getAnyOptionalObjectType();
// If both types are classes and dest is the superclass of src,
// simply perform an upcast.
if (SrcTy.getSwiftRValueType()->mayHaveSuperclass() &&
DestTy.getSwiftRValueType()->mayHaveSuperclass() &&
DestTy.isExactSuperclassOf(SrcTy)) {
if (CheckOnly)
return Value;
CastedValue = B->createUpcast(Loc, Value, DestTy);
return CastedValue;
if (DestTy.isExactSuperclassOf(SrcTy)) {
return B->createUpcast(Loc, Value, DestTy);
}
SILType OptionalSrcLoweredTy;
SILType OptionalDestLoweredTy;
if (SrcTy.isHeapObjectReferenceType() &&
DestTy.isHeapObjectReferenceType()) {
return B->createUncheckedRefCast(Loc, Value, DestTy);
}
if (OptionalSrcTy)
OptionalSrcLoweredTy = M.Types.getLoweredType(OptionalSrcTy);
if (auto mt1 = dyn_cast<AnyMetatypeType>(SrcTy.getSwiftRValueType())) {
if (auto mt2 = dyn_cast<AnyMetatypeType>(DestTy.getSwiftRValueType())) {
if (mt1->getRepresentation() == mt2->getRepresentation()) {
// If B.Type needs to be casted to A.Type and
// A is a superclass of B, then it can be done by means
// of a simple upcast.
if (mt2.getInstanceType()->isExactSuperclassOf(
mt1.getInstanceType(), nullptr)) {
return B->createUpcast(Loc, Value, DestTy);
}
// Cast between two metatypes and that's it.
return B->createUncheckedBitCast(Loc, Value, DestTy);
}
}
}
if (OptionalDestTy)
OptionalDestLoweredTy = M.Types.getLoweredType(OptionalDestTy);
// Check if src and dest types are optional.
auto OptionalSrcTy = SrcTy.getAnyOptionalObjectType();
auto OptionalDestTy = DestTy.getAnyOptionalObjectType();
// Both types are optional.
if (OptionalDestTy && OptionalSrcTy) {
// If both wrapped types are classes and dest is the superclass of src,
// simply perform an upcast.
if (OptionalDestTy->mayHaveSuperclass() &&
OptionalSrcTy->mayHaveSuperclass() &&
OptionalDestLoweredTy.isExactSuperclassOf(OptionalSrcLoweredTy)) {
if (OptionalDestTy.isExactSuperclassOf(OptionalSrcTy)) {
// Insert upcast.
if (CheckOnly)
return Value;
CastedValue = B->createUpcast(Loc, Value, DestTy);
return CastedValue;
return B->createUpcast(Loc, Value, DestTy);
}
if (CheckOnly)
return castValueToABICompatibleType(B, Loc, Value,
OptionalSrcLoweredTy,
OptionalDestLoweredTy, CheckOnly);
// Unwrap the original optional value.
auto *SomeDecl = B->getASTContext().getOptionalSomeDecl();
auto *NoneBB = B->getFunction().createBasicBlock();
@@ -570,10 +553,10 @@ Optional<SILValue> swift::castValueToABICompatibleType(SILBuilder *B, SILLocatio
// Cast the unwrapped value.
auto CastedUnwrappedValue =
castValueToABICompatibleType(B, Loc, UnwrappedValue,
OptionalSrcLoweredTy,
OptionalDestLoweredTy).getValue();
OptionalSrcTy,
OptionalDestTy);
// Wrap into optional.
CastedValue = B->createOptionalSome(Loc, CastedUnwrappedValue, DestTy);
auto CastedValue = B->createOptionalSome(Loc, CastedUnwrappedValue, DestTy);
B->createBranch(Loc, ContBB, {CastedValue});
// Handle the None case.
@@ -582,19 +565,15 @@ Optional<SILValue> swift::castValueToABICompatibleType(SILBuilder *B, SILLocatio
B->createBranch(Loc, ContBB, {CastedValue});
B->setInsertionPoint(ContBB->begin());
CastedValue = ContBB->getArgument(0);
return CastedValue;
return ContBB->getArgument(0);
}
// Src is not optional, but dest is optional.
if (!OptionalSrcTy && OptionalDestTy) {
auto OptionalSrcCanTy =
OptionalType::get(SrcTy.getSwiftRValueType())->getCanonicalType();
auto LoweredOptionalSrcType = M.Types.getLoweredType(OptionalSrcCanTy);
if (CheckOnly)
return castValueToABICompatibleType(B, Loc, Value,
LoweredOptionalSrcType, DestTy,
CheckOnly);
auto OptionalSrcCanTy = OptionalType::get(SrcTy.getSwiftRValueType())
->getCanonicalType();
auto LoweredOptionalSrcType = SILType::getPrimitiveObjectType(
OptionalSrcCanTy);
// Wrap the source value into an optional first.
SILValue WrappedValue = B->createOptionalSome(Loc, Value,
@@ -605,127 +584,33 @@ Optional<SILValue> swift::castValueToABICompatibleType(SILBuilder *B, SILLocatio
DestTy);
}
// Both types are not optional.
if (SrcTy.getSwiftRValueType()->mayHaveSuperclass() &&
DestTy.getSwiftRValueType()->mayHaveSuperclass()) {
if (CheckOnly)
return Value;
if (DestTy.isExactSuperclassOf(SrcTy)) {
// Insert upcast.
CastedValue = B->createUpcast(Loc, Value, DestTy);
return CastedValue;
}
// Cast the reference.
CastedValue = B->createUncheckedBitCast(Loc, Value, DestTy);
return CastedValue;
}
// If B.Type needs to be casted to A.Type and
// A is a superclass of B, then it can be done by means
// of a simple upcast.
if (isa<AnyMetatypeType>(SrcTy.getSwiftRValueType()) &&
isa<AnyMetatypeType>(DestTy.getSwiftRValueType()) &&
SrcTy.isClassOrClassMetatype() && DestTy.isClassOrClassMetatype() &&
DestTy.getMetatypeInstanceType(M).isExactSuperclassOf(
SrcTy.getMetatypeInstanceType(M))) {
if (CheckOnly)
return Value;
CastedValue = B->createUpcast(Loc, Value, DestTy);
return CastedValue;
}
if (auto mt1 = dyn_cast<AnyMetatypeType>(SrcTy.getSwiftRValueType())) {
if (auto mt2 = dyn_cast<AnyMetatypeType>(DestTy.getSwiftRValueType())) {
if (mt1->getRepresentation() == mt2->getRepresentation()) {
// Cast between two metatypes and that's it.
if (CheckOnly)
return Value;
CastedValue = B->createUncheckedBitCast(Loc, Value, DestTy);
return CastedValue;
}
}
}
if (SrcTy.isAddress() && DestTy.isAddress()) {
if (CheckOnly)
return Value;
CastedValue = B->createUncheckedAddrCast(Loc, Value, DestTy);
return CastedValue;
}
if (SrcTy.isHeapObjectReferenceType() && DestTy.isHeapObjectReferenceType()) {
if (CheckOnly)
return Value;
CastedValue = B->createUncheckedRefCast(Loc, Value, DestTy);
return CastedValue;
}
// Handle tuple types.
// Extract elements, cast each of them, create a new tuple.
if (auto tup = SrcTy.getAs<TupleType>()) {
SmallVector<CanType, 1> aElements, bElements;
auto atypes = tup.getElementTypes();
aElements.append(atypes.begin(), atypes.end());
auto btypes = DestTy.getAs<TupleType>().getElementTypes();
bElements.append(btypes.begin(), btypes.end());
if (CheckOnly && aElements.size() != bElements.size())
return None;
assert (aElements.size() == bElements.size() &&
"Tuple types should have the same number of elements");
if (auto SrcTupleTy = SrcTy.getAs<TupleType>()) {
SmallVector<SILValue, 8> ExpectedTuple;
for (unsigned i : indices(aElements)) {
auto aa = M.Types.getLoweredType(aElements[i]),
bb = M.Types.getLoweredType(bElements[i]);
if (CheckOnly) {
if (!castValueToABICompatibleType(B, Loc, Value, aa, bb, CheckOnly).hasValue())
return None;
continue;
}
for (unsigned i = 0, e = SrcTupleTy->getNumElements(); i < e; i++) {
SILValue Element = B->createTupleExtract(Loc, Value, i);
// Cast the value if necessary.
Element = castValueToABICompatibleType(B, Loc, Element, aa, bb).getValue();
Element = castValueToABICompatibleType(B, Loc, Element,
SrcTy.getTupleElementType(i),
DestTy.getTupleElementType(i));
ExpectedTuple.push_back(Element);
}
if (CheckOnly)
return Value;
CastedValue = B->createTuple(Loc, DestTy, ExpectedTuple);
return CastedValue;
return B->createTuple(Loc, DestTy, ExpectedTuple);
}
// Function types are interchangeable if they're also ABI-compatible.
if (SrcTy.getAs<SILFunctionType>()) {
if (DestTy.getAs<SILFunctionType>()) {
if (CheckOnly)
return Value;
// Insert convert_function.
CastedValue = B->createConvertFunction(Loc, Value, DestTy);
return CastedValue;
return B->createConvertFunction(Loc, Value, DestTy);
}
}
if (CheckOnly)
return None;
llvm::errs() << "Source type: " << SrcTy << "\n";
llvm::errs() << "Destination type: " << DestTy << "\n";
llvm_unreachable("Unknown combination of types for casting");
return SILValue();
}
bool swift::canCastValueToABICompatibleType(SILModule &M,
SILType SrcTy, SILType DestTy) {
SILBuilder B(*M.begin());
SILLocation Loc = ArtificialUnreachableLocation();
auto Result = castValueToABICompatibleType(&B, Loc, SILValue(),
SrcTy, DestTy,
/* CheckOnly */ true);
return Result.hasValue();
}
ProjectBoxInst *swift::getOrCreateProjectBox(AllocBoxInst *ABI, unsigned Index){

View File

@@ -253,18 +253,17 @@ final class XXX : BBB {
// Check that sil-combine does not crash on this example and does not generate a wrong
// upcast.
// CHECK-LABEL: sil @silcombine_dont_generate_wrong_upcasts_during_devirt
// CHECK-NOT: upcast
// CHECK: witness_method $XXX, #PPP.foo!1 : {{.*}} : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
// CHECK-NOT: upcast
// CHECK: [[SELF:%.*]] = unchecked_ref_cast %0 : $BBB to $XXX
// CHECK: [[WITNESS_THUNK:%.*]] = function_ref @_TTWC4nix23XXXS_3PPPS_FS1_3foofT_T_ : $@convention(witness_method) (@guaranteed XXX) -> ()
// CHECK: apply [[WITNESS_THUNK]]([[SELF]])
// CHECK: return
sil @silcombine_dont_generate_wrong_upcasts_during_devirt: $@convention(thin) (@owned BBB) -> () {
bb0(%0 : $BBB):
strong_retain %0 : $BBB
%3 = init_existential_ref %0 : $BBB : $BBB, $PPP
%5 = open_existential_ref %3 : $PPP to $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP
%6 = witness_method $XXX, #PPP.foo!1, %5 : $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
%6 = witness_method $BBB, #PPP.foo!1, %5 : $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
%7 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
%8 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
strong_release %3 : $PPP
%9 = tuple ()
strong_release %0 : $BBB
@@ -279,8 +278,6 @@ bb0(%0 : $BBB):
// CHECK-NOT: witness_method
// CHECK: [[FR1:%.*]] = function_ref @_TTWC4nix23XXXS_3PPPS_FS1_3foofT_T_
// CHECK: apply [[FR1]](%0)
// CHECK: [[FR2:%.*]] = function_ref @_TTWC4nix23XXXS_3PPPS_FS1_3foofT_T_
// CHECK: apply [[FR2]](%0)
// CHECK: return
sil @silcombine_devirt_both_applies_of_witness_method : $@convention(thin) (@owned XXX) -> () {
bb0(%0 : $XXX):
@@ -289,7 +286,6 @@ bb0(%0 : $XXX):
%5 = open_existential_ref %3 : $PPP to $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP
%6 = witness_method $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP, #PPP.foo!1, %5 : $@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
%7 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
%8 = apply %6<@opened("0AC9A62E-926E-11E6-8BF5-685B35C48C83") PPP>(%5) : $@convention(witness_method) <τ_0_0 where τ_0_0 : PPP> (@guaranteed τ_0_0) -> ()
strong_release %3 : $PPP
%9 = tuple ()
strong_release %0 : $XXX