void ClassHierarchyAnalysis::init() { // Process all types implementing protocols. SmallVector<Decl *, 32> Decls; // TODO: It would be better if we could get all declarations // from a given module, not only the top-level ones. M->getSwiftModule()->getTopLevelDecls(Decls); NominalTypeWalker Walker(ProtocolImplementationsCache); for (auto *D: Decls) { D->walk(Walker); } // For each class declaration in our V-table list: for (auto &VT : M->getVTableList()) { ClassDecl *C = VT.getClass(); // Ignore classes that are at the top of the class hierarchy: if (!C->hasSuperclass()) continue; // Add the superclass to the list of inherited classes. ClassDecl *Super = C->getSuperclass()->getClassOrBoundGenericClass(); auto &K = DirectSubclassesCache[Super]; assert(std::find(K.begin(), K.end(), C) == K.end() && "Class vector must be unique"); K.push_back(C); } }
// Analyzing the body of this class destructor is valid because the object is // dead. This means that the object is never passed to objc_setAssociatedObject, // so its destructor cannot be extended at runtime. static SILFunction *getDestructor(AllocRefInst *ARI) { // We only support classes. ClassDecl *ClsDecl = ARI->getType().getClassOrBoundGenericClass(); if (!ClsDecl) return nullptr; // Look up the destructor of ClsDecl. DestructorDecl *Destructor = ClsDecl->getDestructor(); assert(Destructor && "getDestructor() should never return a nullptr."); // Find the destructor name via SILDeclRef. // FIXME: When destructors get moved into vtables, update this to use the // vtable for the class. SILDeclRef Ref(Destructor); SILFunction *Fn = ARI->getModule().lookUpFunction(Ref); if (!Fn || Fn->empty()) { DEBUG(llvm::dbgs() << " Could not find destructor.\n"); return nullptr; } DEBUG(llvm::dbgs() << " Found destructor!\n"); // If the destructor has an objc_method calling convention, we cannot // analyze it since it could be swapped out from under us at runtime. if (Fn->getRepresentation() == SILFunctionTypeRepresentation::ObjCMethod) { DEBUG(llvm::dbgs() << " Found objective-c destructor. Can't " "analyze!\n"); return nullptr; } return Fn; }
void SILGenFunction::emitDestroyingDestructor(DestructorDecl *dd) { MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation Loc(dd); if (dd->isImplicit()) Loc.markAutoGenerated(); auto cd = cast<ClassDecl>(dd->getDeclContext()); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(Loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(Loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(Loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(Loc); // If we have a superclass, invoke its destructor. SILValue resultSelfValue; SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext()); if (cd->hasSuperclass()) { Type superclassTy = ArchetypeBuilder::mapTypeIntoContext(dd, cd->getSuperclass()); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); SILDeclRef dtorConstant = SILDeclRef(superclassDtorDecl, SILDeclRef::Kind::Destroyer); SILType baseSILTy = getLoweredLoadableType(superclassTy); SILValue baseSelf = B.createUpcast(cleanupLoc, selfValue, baseSILTy); ManagedValue dtorValue; SILType dtorTy; ArrayRef<Substitution> subs = superclassTy->gatherAllSubstitutions(SGM.M.getSwiftModule(), nullptr); std::tie(dtorValue, dtorTy, subs) = emitSiblingMethodRef(cleanupLoc, baseSelf, dtorConstant, subs); resultSelfValue = B.createApply(cleanupLoc, dtorValue.forward(*this), dtorTy, objectPtrTy, subs, baseSelf); } else { resultSelfValue = B.createUncheckedRefCast(cleanupLoc, selfValue, objectPtrTy); } // Release our members. emitClassMemberDestruction(selfValue, cd, cleanupLoc); B.createReturn(returnLoc, resultSelfValue); }
// Wrapper function to findSoleConformingType that checks for additional // constraints for classes using ClassHierarchyAnalysis. bool ProtocolConformanceAnalysis::getSoleConformingType( ProtocolDecl *Protocol, ClassHierarchyAnalysis *CHA, CanType &ConcreteType) { // Determine the sole conforming type. auto *NTD = findSoleConformingType(Protocol); if (!NTD) return false; // Sole conforming class should not be open access or have any derived class. ClassDecl *CD; if ((CD = dyn_cast<ClassDecl>(NTD)) && (CD->getEffectiveAccess() == AccessLevel::Open || CHA->hasKnownDirectSubclasses(CD))) { return false; } // Save the concrete type. ConcreteType = NTD->getDeclaredType()->getCanonicalType(); return true; }
void addMethod(SILDeclRef method) { assert(method.getDecl()->getDeclContext() == CD); if (CD->hasResilientMetadata()) { if (FirstTime) { FirstTime = false; // If the class is itself resilient and has at least one vtable entry, // it has a method lookup function. TBD.addSymbol(LinkEntity::forMethodLookupFunction(CD)); } TBD.addDispatchThunk(method); } TBD.addMethodDescriptor(method); }
void layout() override { PrettyStackTraceDecl DebugStack("emitting superclass metadata", Class); auto *M = IGM.getSILModule().getSwiftModule(); addTypeRef(M, Class->getDeclaredType()->getCanonicalType()); auto anyObjectDecl = IGM.Context.getProtocol(KnownProtocolKind::AnyObject); addTypeRef(M, anyObjectDecl->getDeclaredType()->getCanonicalType()); addConstantInt32(1); addConstantInt32(AssociatedTypeRecordSize); auto NameGlobal = IGM.getAddrOfStringForTypeRef("super"); addRelativeAddress(NameGlobal); addTypeRef(M, Superclass); }
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast<DestructorDecl>(dtor.getDecl()); auto cd = cast<ClassDecl>(dd->getDeclContext()); MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation loc(dd); if (dd->isImplicit()) loc.markAutoGenerated(); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(loc)); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(loc); // Note: the ivar destroyer is responsible for destroying the // instance variables before the object is actually deallocated. // Form a reference to the superclass -dealloc. Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass()); assert(superclassTy && "Emitting Objective-C -dealloc without superclass?"); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); SILDeclRef superclassDtor(superclassDtorDecl, SILDeclRef::Kind::Deallocator, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isForeign=*/true); auto superclassDtorType = SGM.getConstantType(superclassDtor); SILValue superclassDtorValue = B.createSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); // Call the superclass's -dealloc. SILType superclassSILTy = getLoweredLoadableType(superclassTy); SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy); ArrayRef<Substitution> subs = superclassTy->gatherAllSubstitutions(SGM.M.getSwiftModule(), nullptr); auto substDtorType = superclassDtorType.castTo<SILFunctionType>() ->substGenericArgs(SGM.M, subs); SILFunctionConventions dtorConv(substDtorType, SGM.M); B.createApply(cleanupLoc, superclassDtorValue, SILType::getPrimitiveObjectType(substDtorType), dtorConv.getSILResultType(), subs, superSelf); // Return. B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc)); }
static void lookupVisibleMemberDeclsImpl( Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver, VisitedSet &Visited) { // Just look through l-valueness. It doesn't affect name lookup. assert(BaseTy && "lookup into null type"); BaseTy = BaseTy->getRValueType(); // Handle metatype references, as in "some_type.some_member". These are // special and can't have extensions. if (auto MTT = BaseTy->getAs<AnyMetatypeType>()) { // The metatype represents an arbitrary named type: dig through to the // declared type to see what we're dealing with. Type Ty = MTT->getInstanceType(); // Just perform normal dot lookup on the type see if we find extensions or // anything else. For example, type SomeTy.SomeMember can look up static // functions, and can even look up non-static functions as well (thus // getting the address of the member). lookupVisibleMemberDeclsImpl(Ty, Consumer, CurrDC, LookupState::makeQualified().withOnMetatype(), Reason, TypeResolver, Visited); return; } // Lookup module references, as on some_module.some_member. These are // special and can't have extensions. if (ModuleType *MT = BaseTy->getAs<ModuleType>()) { AccessFilteringDeclConsumer FilteringConsumer(CurrDC, Consumer, TypeResolver); MT->getModule()->lookupVisibleDecls(Module::AccessPathTy(), FilteringConsumer, NLKind::QualifiedLookup); return; } // If the base is a protocol, enumerate its members. if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) { lookupVisibleProtocolMemberDecls(BaseTy, PT, Consumer, CurrDC, LS, Reason, TypeResolver, Visited); return; } // If the base is a protocol composition, enumerate members of the protocols. if (auto PC = BaseTy->getAs<ProtocolCompositionType>()) { for (auto Proto : PC->getProtocols()) lookupVisibleMemberDeclsImpl(Proto, Consumer, CurrDC, LS, Reason, TypeResolver, Visited); return; } // Enumerate members of archetype's requirements. if (ArchetypeType *Archetype = BaseTy->getAs<ArchetypeType>()) { for (auto Proto : Archetype->getConformsTo()) lookupVisibleProtocolMemberDecls( BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS, getReasonForSuper(Reason), TypeResolver, Visited); if (auto superclass = Archetype->getSuperclass()) lookupVisibleMemberDeclsImpl(superclass, Consumer, CurrDC, LS, getReasonForSuper(Reason), TypeResolver, Visited); return; } do { NominalTypeDecl *CurNominal = BaseTy->getAnyNominal(); if (!CurNominal) break; // Look in for members of a nominal type. lookupTypeMembers(BaseTy, BaseTy, Consumer, CurrDC, LS, Reason, TypeResolver); lookupDeclsFromProtocolsBeingConformedTo(BaseTy, Consumer, LS, CurrDC, Reason, TypeResolver, Visited); // If we have a class type, look into its superclass. ClassDecl *CurClass = dyn_cast<ClassDecl>(CurNominal); if (CurClass && CurClass->hasSuperclass()) { assert(BaseTy.getPointer() != CurClass->getSuperclass().getPointer() && "type is its own superclass"); BaseTy = CurClass->getSuperclass(); Reason = getReasonForSuper(Reason); bool InheritsSuperclassInitializers = CurClass->inheritsSuperclassInitializers(TypeResolver); if (LS.isOnSuperclass() && !InheritsSuperclassInitializers) LS = LS.withoutInheritsSuperclassInitializers(); else if (!LS.isOnSuperclass()) { LS = LS.withOnSuperclass(); if (InheritsSuperclassInitializers) LS = LS.withInheritsSuperclassInitializers(); } } else { break; } } while (1); }
/// \brief Try to speculate the call target for the call \p AI. This function /// returns true if a change was made. static bool tryToSpeculateTarget(FullApplySite AI, ClassHierarchyAnalysis *CHA) { ClassMethodInst *CMI = cast<ClassMethodInst>(AI.getCallee()); // We cannot devirtualize in cases where dynamic calls are // semantically required. if (CMI->isVolatile()) return false; // Strip any upcasts off of our 'self' value, potentially leaving us // with a value whose type is closer (in the class hierarchy) to the // actual dynamic type. auto SubTypeValue = CMI->getOperand().stripUpCasts(); SILType SubType = SubTypeValue.getType(); // Bail if any generic types parameters of the class instance type are // unbound. // We cannot devirtualize unbound generic calls yet. if (isNominalTypeWithUnboundGenericParameters(SubType, AI.getModule())) return false; auto &M = CMI->getModule(); auto ClassType = SubType; if (SubType.is<MetatypeType>()) ClassType = SubType.getMetatypeInstanceType(M); CheckedCastBranchInst *LastCCBI = nullptr; ClassDecl *CD = ClassType.getClassOrBoundGenericClass(); assert(CD && "Expected decl for class type!"); if (!CHA->hasKnownDirectSubclasses(CD)) { // If there is only one possible alternative for this method, // try to devirtualize it completely. ClassHierarchyAnalysis::ClassList Subs; if (isDefaultCaseKnown(CHA, AI, CD, Subs)) { auto NewInstPair = tryDevirtualizeClassMethod(AI, SubTypeValue); if (NewInstPair.first) replaceDeadApply(AI, NewInstPair.first); return NewInstPair.second.getInstruction() != nullptr; } DEBUG(llvm::dbgs() << "Inserting monomorphic speculative call for class " << CD->getName() << "\n"); return !!speculateMonomorphicTarget(AI, SubType, LastCCBI); } // True if any instructions were changed or generated. bool Changed = false; // Collect the direct and indirect subclasses for the class. // Sort these subclasses in the order they should be tested by the // speculative devirtualization. Different strategies could be used, // E.g. breadth-first, depth-first, etc. // Currently, let's use the breadth-first strategy. // The exact static type of the instance should be tested first. auto &DirectSubs = CHA->getDirectSubClasses(CD); auto &IndirectSubs = CHA->getIndirectSubClasses(CD); SmallVector<ClassDecl *, 8> Subs(DirectSubs); Subs.append(IndirectSubs.begin(), IndirectSubs.end()); if (isa<BoundGenericClassType>(ClassType.getSwiftRValueType())) { // Filter out any subclassses that do not inherit from this // specific bound class. auto RemovedIt = std::remove_if(Subs.begin(), Subs.end(), [&ClassType, &M](ClassDecl *Sub){ auto SubCanTy = Sub->getDeclaredType()->getCanonicalType(); // Unbound generic type can override a method from // a bound generic class, but this unbound generic // class is not considered to be a subclass of a // bound generic class in a general case. if (isa<UnboundGenericType>(SubCanTy)) return false; // Handle the usual case here: the class in question // should be a real subclass of a bound generic class. return !ClassType.isSuperclassOf( SILType::getPrimitiveObjectType(SubCanTy)); }); Subs.erase(RemovedIt, Subs.end()); } // Number of subclasses which cannot be handled by checked_cast_br checks. int NotHandledSubsNum = 0; if (Subs.size() > MaxNumSpeculativeTargets) { DEBUG(llvm::dbgs() << "Class " << CD->getName() << " has too many (" << Subs.size() << ") subclasses. Performing speculative " "devirtualization only for the first " << MaxNumSpeculativeTargets << " of them.\n"); NotHandledSubsNum += (Subs.size() - MaxNumSpeculativeTargets); Subs.erase(&Subs[MaxNumSpeculativeTargets], Subs.end()); } DEBUG(llvm::dbgs() << "Class " << CD->getName() << " is a superclass. " "Inserting polymorphic speculative call.\n"); // Try to devirtualize the static class of instance // if it is possible. auto FirstAI = speculateMonomorphicTarget(AI, SubType, LastCCBI); if (FirstAI) { Changed = true; AI = FirstAI; } // Perform a speculative devirtualization of a method invocation. // It replaces an indirect class_method-based call by a code to perform // a direct call of the method implementation based on the dynamic class // of the instance. // // The code is generated according to the following principles: // // - For each direct subclass, a dedicated checked_cast_br instruction // is generated to check if a dynamic class of the instance is exactly // this subclass. // // - If this check succeeds, then it jumps to the code which performs a // direct call of a method implementation specific to this subclass. // // - If this check fails, then a different subclass is checked by means of // checked_cast_br in a similar way. // // - Finally, if the instance does not exactly match any of the direct // subclasses, the "default" case code is generated, which should handle // all remaining alternatives, i.e. it should be able to dispatch to any // possible remaining method implementations. Typically this is achieved by // using a class_method instruction, which performs an indirect invocation. // But if it can be proven that only one specific implementation of // a method will be always invoked by this code, then a class_method-based // call can be devirtualized and replaced by a more efficient direct // invocation of this specific method implementation. // // Remark: With the current implementation of a speculative devirtualization, // if devirtualization of the "default" case is possible, then it would // by construction directly invoke the implementation of the method // corresponding to the static type of the instance. This may change // in the future, if we start using PGO for ordering of checked_cast_br // checks. // TODO: The ordering of checks may benefit from using a PGO, because // the most probable alternatives could be checked first. for (auto S : Subs) { DEBUG(llvm::dbgs() << "Inserting a speculative call for class " << CD->getName() << " and subclass " << S->getName() << "\n"); CanType CanClassType = S->getDeclaredType()->getCanonicalType(); SILType ClassType = SILType::getPrimitiveObjectType(CanClassType); if (!ClassType.getClassOrBoundGenericClass()) { // This subclass cannot be handled. This happens e.g. if it is // a generic class. NotHandledSubsNum++; continue; } auto ClassOrMetatypeType = ClassType; if (auto EMT = SubType.getAs<AnyMetatypeType>()) { auto InstTy = ClassType.getSwiftRValueType(); auto *MetaTy = MetatypeType::get(InstTy, EMT->getRepresentation()); auto CanMetaTy = CanMetatypeType::CanTypeWrapper(MetaTy); ClassOrMetatypeType = SILType::getPrimitiveObjectType(CanMetaTy); } // Pass the metatype of the subclass. auto NewAI = speculateMonomorphicTarget(AI, ClassOrMetatypeType, LastCCBI); if (!NewAI) { NotHandledSubsNum++; continue; } AI = NewAI; Changed = true; } // Check if there is only a single statically known implementation // of the method which can be called by the default case handler. if (NotHandledSubsNum || !isDefaultCaseKnown(CHA, AI, CD, Subs)) { // Devirtualization of remaining cases is not possible, // because more than one implementation of the method // needs to be handled here. Thus, an indirect call through // the class_method cannot be eliminated completely. // return Changed; } // At this point it is known that there is only one remaining method // implementation which is not covered by checked_cast_br checks yet. // So, it is safe to replace a class_method invocation by // a direct call of this remaining implementation. if (LastCCBI && SubTypeValue == LastCCBI->getOperand()) { // Remove last checked_cast_br, because it will always succeed. SILBuilderWithScope B(LastCCBI); auto CastedValue = B.createUncheckedBitCast(LastCCBI->getLoc(), LastCCBI->getOperand(), LastCCBI->getCastType()); B.createBranch(LastCCBI->getLoc(), LastCCBI->getSuccessBB(), {CastedValue}); LastCCBI->eraseFromParent(); return true; } auto NewInstPair = tryDevirtualizeClassMethod(AI, SubTypeValue); assert(NewInstPair.first && "Expected to be able to devirtualize apply!"); replaceDeadApply(AI, NewInstPair.first); return true; }
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast<DestructorDecl>(dtor.getDecl()); auto cd = cast<ClassDecl>(dd->getDeclContext()); MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation loc(dd); if (dd->isImplicit()) loc.markAutoGenerated(); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(loc); // Note: the ivar destroyer is responsible for destroying the // instance variables before the object is actually deallocated. // Form a reference to the superclass -dealloc. Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass()); assert(superclassTy && "Emitting Objective-C -dealloc without superclass?"); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); auto superclassDtor = SILDeclRef(superclassDtorDecl, SILDeclRef::Kind::Deallocator) .asForeign(); auto superclassDtorType = SGM.Types.getConstantType(superclassDtor); SILValue superclassDtorValue = B.createObjCSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); // Call the superclass's -dealloc. SILType superclassSILTy = getLoweredLoadableType(superclassTy); SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy); assert(superSelf.getOwnershipKind() == ValueOwnershipKind::Owned); auto subMap = superclassTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), superclass); auto substDtorType = superclassDtorType.substGenericArgs(SGM.M, subMap); CanSILFunctionType substFnType = substDtorType.castTo<SILFunctionType>(); SILFunctionConventions dtorConv(substFnType, SGM.M); assert(substFnType->getSelfParameter().getConvention() == ParameterConvention::Direct_Unowned && "Objective C deinitializing destructor takes self as unowned"); B.createApply(cleanupLoc, superclassDtorValue, substDtorType, dtorConv.getSILResultType(), subMap, superSelf); // We know that the givne value came in at +1, but we pass the relevant value // as unowned to the destructor. Create a fake balance for the verifier to be // happy. B.createEndLifetime(cleanupLoc, superSelf); // Return. B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc)); }
/// Emit a checked unconditional downcast of a class value. llvm::Value *irgen::emitClassDowncast(IRGenFunction &IGF, llvm::Value *from, SILType toType, CheckedCastMode mode) { // Emit the value we're casting from. if (from->getType() != IGF.IGM.Int8PtrTy) from = IGF.Builder.CreateBitOrPointerCast(from, IGF.IGM.Int8PtrTy); // Emit a reference to the metadata and figure out what cast // function to use. llvm::Value *metadataRef; llvm::Constant *castFn; // Get the best known type information about the destination type. ClassDecl *destClass = nullptr; if (auto archetypeTy = toType.getAs<ArchetypeType>()) { if (auto superclassTy = archetypeTy->getSuperclass()) destClass = superclassTy->getClassOrBoundGenericClass(); } else { destClass = toType.getClassOrBoundGenericClass(); assert(destClass != nullptr); } // If the destination type is known to have a Swift-compatible // implementation, use the most specific entrypoint. if (destClass && destClass->hasKnownSwiftImplementation()) { metadataRef = IGF.emitTypeMetadataRef(toType.getSwiftRValueType()); switch (mode) { case CheckedCastMode::Unconditional: castFn = IGF.IGM.getDynamicCastClassUnconditionalFn(); break; case CheckedCastMode::Conditional: castFn = IGF.IGM.getDynamicCastClassFn(); break; } // If the destination type is a CF type or a non-specific // class-bounded archetype, use the most general cast entrypoint. } else if (toType.is<ArchetypeType>() || destClass->getForeignClassKind()==ClassDecl::ForeignKind::CFType) { metadataRef = IGF.emitTypeMetadataRef(toType.getSwiftRValueType()); switch (mode) { case CheckedCastMode::Unconditional: castFn = IGF.IGM.getDynamicCastUnknownClassUnconditionalFn(); break; case CheckedCastMode::Conditional: castFn = IGF.IGM.getDynamicCastUnknownClassFn(); break; } // Otherwise, use the ObjC-specific entrypoint. } else { metadataRef = emitObjCHeapMetadataRef(IGF, destClass); switch (mode) { case CheckedCastMode::Unconditional: castFn = IGF.IGM.getDynamicCastObjCClassUnconditionalFn(); break; case CheckedCastMode::Conditional: castFn = IGF.IGM.getDynamicCastObjCClassFn(); break; } } if (metadataRef->getType() != IGF.IGM.Int8PtrTy) metadataRef = IGF.Builder.CreateBitCast(metadataRef, IGF.IGM.Int8PtrTy); // Call the (unconditional) dynamic cast. auto cc = IGF.IGM.DefaultCC; if (auto fun = dyn_cast<llvm::Function>(castFn)) cc = fun->getCallingConv(); auto call = IGF.Builder.CreateCall(castFn, {from, metadataRef}); // FIXME: Eventually, we may want to throw. call->setCallingConv(cc); call->setDoesNotThrow(); llvm::Type *subTy = IGF.getTypeInfo(toType).getStorageType(); return IGF.Builder.CreateBitCast(call, subTy); }