mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #7779 from slavapestov/devirt-gardening
Simplify devirtualization and fix a bug
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user