SILFunction *SILModule::findFunction(StringRef Name, SILLinkage Linkage) { assert((Linkage == SILLinkage::Public || Linkage == SILLinkage::PublicExternal) && "Only a lookup of public functions is supported currently"); SILFunction *F = nullptr; // First, check if there is a function with a required name in the // current module. SILFunction *CurF = lookUpFunction(Name); // Nothing to do if the current module has a required function // with a proper linkage already. if (CurF && CurF->getLinkage() == Linkage) { F = CurF; } else { assert((!CurF || CurF->getLinkage() != Linkage) && "hasFunction should be only called for functions that are not " "contained in the SILModule yet or do not have a required linkage"); } if (!F) { if (CurF) { // Perform this lookup only if a function with a given // name is present in the current module. // This is done to reduce the amount of IO from the // swift module file. if (!getSILLoader()->hasSILFunction(Name, Linkage)) return nullptr; // The function in the current module will be changed. F = CurF; } // If function with a given name wasn't seen anywhere yet // or if it is known to exist, perform a lookup. if (!F) { // Try to load the function from other modules. F = getSILLoader()->lookupSILFunction(Name, /*declarationOnly*/ true, Linkage); // Bail if nothing was found and we are not sure if // this function exists elsewhere. if (!F) return nullptr; assert(F && "SILFunction should be present in one of the modules"); assert(F->getLinkage() == Linkage && "SILFunction has a wrong linkage"); } } // If a function exists already and it is a non-optimizing // compilation, simply convert it into an external declaration, // so that a compiled version from the shared library is used. if (F->isDefinition() && !F->getModule().getOptions().shouldOptimize()) { F->convertToDeclaration(); } if (F->isExternalDeclaration()) F->setSerialized(IsSerialized_t::IsNotSerialized); F->setLinkage(Linkage); return F; }
static void cleanFunction(SILFunction &Fn) { for (auto &BB : Fn) { auto I = BB.begin(), E = BB.end(); while (I != E) { // Make sure there is no iterator invalidation if the inspected // instruction gets removed from the block. SILInstruction *Inst = &*I; ++I; // Remove calls to Builtin.staticReport(). if (BuiltinInst *BI = dyn_cast<BuiltinInst>(Inst)) { const BuiltinInfo &B = BI->getBuiltinInfo(); if (B.ID == BuiltinValueKind::StaticReport) { // The call to the builtin should get removed before we reach // IRGen. recursivelyDeleteTriviallyDeadInstructions(BI, /* Force */true); } } } } // Rename functions with public_external linkage to prevent symbol conflict // with stdlib. if (Fn.isDefinition() && Fn.getLinkage() == SILLinkage::PublicExternal) { Fn.setLinkage(SILLinkage::SharedExternal); } }
bool SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) { SILFunction *Callee = PAI->getCalleeFunction(); if (!Callee) return false; if (!isLinkAll() && !Callee->isTransparent() && !hasSharedVisibility(Callee->getLinkage())) return false; addFunctionToWorklist(Callee); return true; }
bool SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) { // Needed to handle closures which are no longer applied, but are left // behind as dead code. This shouldn't happen, but if it does don't get into // an inconsistent state. SILFunction *Callee = FRI->getReferencedFunction(); if (!isLinkAll() && !Callee->isTransparent() && !hasSharedVisibility(Callee->getLinkage())) return false; addFunctionToWorklist(FRI->getReferencedFunction()); return true; }
SILFunction * SILGenModule::emitVTableMethod(SILDeclRef derived, SILDeclRef base, SILLinkage &implLinkage) { SILFunction *implFn = getFunction(derived, NotForDefinition); implLinkage = implFn->getLinkage(); // As a fast path, if there is no override, definitely no thunk is necessary. if (derived == base) return implFn; // Determine the derived thunk type by lowering the derived type against the // abstraction pattern of the base. auto baseInfo = Types.getConstantInfo(base); auto derivedInfo = Types.getConstantInfo(derived); auto basePattern = AbstractionPattern(baseInfo.LoweredInterfaceType); auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base); // The override member type is semantically a subtype of the base // member type. If the override is ABI compatible, we do not need // a thunk. if (overrideInfo == derivedInfo) return implFn; // Generate the thunk name. // TODO: If we allocated a new vtable slot for the derived method, then // further derived methods would potentially need multiple thunks, and we // would need to mangle the base method into the symbol as well. auto name = derived.mangle(SILDeclRef::ManglingKind::VTableMethod); // If we already emitted this thunk, reuse it. // TODO: Allocating new vtable slots for derived methods with different ABIs // would invalidate the assumption that the same thunk is correct, as above. if (auto existingThunk = M.lookUpFunction(name)) return existingThunk; auto *derivedDecl = cast<AbstractFunctionDecl>(derived.getDecl()); SILLocation loc(derivedDecl); auto thunk = M.createFunction(SILLinkage::Private, name, overrideInfo.SILFnType, derivedDecl->getGenericEnvironment(), loc, IsBare, IsNotTransparent, IsNotFragile); thunk->setDebugScope(new (M) SILDebugScope(loc, thunk)); SILGenFunction(*this, *thunk) .emitVTableThunk(derived, implFn, basePattern, overrideInfo.LoweredInterfaceType, derivedInfo.LoweredInterfaceType); return thunk; }
bool SILLinkerVisitor::visitApplyInst(ApplyInst *AI) { // Ok we have a function ref inst, grab the callee. SILFunction *Callee = AI->getCalleeFunction(); if (!Callee) return false; // If the linking mode is not link all, AI is not transparent, and the // callee is not shared, we don't want to perform any linking. if (!isLinkAll() && !Callee->isTransparent() && !hasSharedVisibility(Callee->getLinkage())) return false; // Otherwise we want to try and link in the callee... Add it to the callee // list and return true. addFunctionToWorklist(Callee); return true; }
Optional<SILVTable::Entry> SILGenModule::emitVTableMethod(ClassDecl *theClass, SILDeclRef derived, SILDeclRef base) { assert(base.kind == derived.kind); auto *baseDecl = base.getDecl(); auto *derivedDecl = derived.getDecl(); // Note: We intentionally don't support extension members here. // // Once extensions can override or introduce new vtable entries, this will // all likely change anyway. auto *baseClass = cast<ClassDecl>(baseDecl->getDeclContext()); auto *derivedClass = cast<ClassDecl>(derivedDecl->getDeclContext()); // Figure out if the vtable entry comes from the superclass, in which // case we won't emit it if building a resilient module. SILVTable::Entry::Kind implKind; if (baseClass == theClass) { // This is a vtable entry for a method of the immediate class. implKind = SILVTable::Entry::Kind::Normal; } else if (derivedClass == theClass) { // This is a vtable entry for a method of a base class, but it is being // overridden in the immediate class. implKind = SILVTable::Entry::Kind::Override; } else { // This vtable entry is copied from the superclass. implKind = SILVTable::Entry::Kind::Inherited; // If the override is defined in a class from a different resilience // domain, don't emit the vtable entry. if (derivedClass->isResilient(M.getSwiftModule(), ResilienceExpansion::Maximal)) { return None; } } SILFunction *implFn; SILLinkage implLinkage; // If the member is dynamic, reference its dynamic dispatch thunk so that // it will be redispatched, funneling the method call through the runtime // hook point. if (derivedDecl->isDynamic() && derived.kind != SILDeclRef::Kind::Allocator) { implFn = getDynamicThunk(derived, Types.getConstantInfo(derived).SILFnType); implLinkage = SILLinkage::Public; } else { implFn = getFunction(derived, NotForDefinition); implLinkage = stripExternalFromLinkage(implFn->getLinkage()); } // As a fast path, if there is no override, definitely no thunk is necessary. if (derived == base) return SILVTable::Entry(base, implFn, implKind, implLinkage); // Determine the derived thunk type by lowering the derived type against the // abstraction pattern of the base. auto baseInfo = Types.getConstantInfo(base); auto derivedInfo = Types.getConstantInfo(derived); auto basePattern = AbstractionPattern(baseInfo.LoweredType); auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base); // The override member type is semantically a subtype of the base // member type. If the override is ABI compatible, we do not need // a thunk. if (M.Types.checkFunctionForABIDifferences(derivedInfo.SILFnType, overrideInfo.SILFnType) == TypeConverter::ABIDifference::Trivial) return SILVTable::Entry(base, implFn, implKind, implLinkage); // Generate the thunk name. std::string name; { Mangle::ASTMangler mangler; if (isa<FuncDecl>(baseDecl)) { name = mangler.mangleVTableThunk( cast<FuncDecl>(baseDecl), cast<FuncDecl>(derivedDecl)); } else { name = mangler.mangleConstructorVTableThunk( cast<ConstructorDecl>(baseDecl), cast<ConstructorDecl>(derivedDecl), base.kind == SILDeclRef::Kind::Allocator); } } // If we already emitted this thunk, reuse it. if (auto existingThunk = M.lookUpFunction(name)) return SILVTable::Entry(base, existingThunk, implKind, implLinkage); // Emit the thunk. SILLocation loc(derivedDecl); SILGenFunctionBuilder builder(*this); auto thunk = builder.createFunction( SILLinkage::Private, name, overrideInfo.SILFnType, cast<AbstractFunctionDecl>(derivedDecl)->getGenericEnvironment(), loc, IsBare, IsNotTransparent, IsNotSerialized); thunk->setDebugScope(new (M) SILDebugScope(loc, thunk)); SILGenFunction(*this, *thunk, theClass) .emitVTableThunk(derived, implFn, basePattern, overrideInfo.LoweredType, derivedInfo.LoweredType); return SILVTable::Entry(base, thunk, implKind, implLinkage); }
/// In this function we create the actual cloned function and its proper cloned /// type. But we do not create any body. This implies that the creation of the /// actual arguments in the function is in populateCloned. /// /// \arg PAUser The function that is being passed the partial apply. /// \arg PAI The partial apply that is being passed to PAUser. /// \arg ClosureIndex The index of the partial apply in PAUser's function /// signature. /// \arg ClonedName The name of the cloned function that we will create. SILFunction * ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, const CallSiteDescriptor &CallSiteDesc, StringRef ClonedName) { SILFunction *ClosureUser = CallSiteDesc.getApplyCallee(); // This is the list of new interface parameters of the cloned function. llvm::SmallVector<SILParameterInfo, 4> NewParameterInfoList; // First add to NewParameterInfoList all of the SILParameterInfo in the // original function except for the closure. CanSILFunctionType ClosureUserFunTy = ClosureUser->getLoweredFunctionType(); auto ClosureUserConv = ClosureUser->getConventions(); unsigned Index = ClosureUserConv.getSILArgIndexOfFirstParam(); for (auto ¶m : ClosureUserConv.getParameters()) { if (Index != CallSiteDesc.getClosureIndex()) NewParameterInfoList.push_back(param); ++Index; } // Then add any arguments that are captured in the closure to the function's // argument type. Since they are captured, we need to pass them directly into // the new specialized function. SILFunction *ClosedOverFun = CallSiteDesc.getClosureCallee(); auto ClosedOverFunConv = ClosedOverFun->getConventions(); SILModule &M = ClosureUser->getModule(); // Captured parameters are always appended to the function signature. If the // type of the captured argument is: // - direct and trivial, pass the argument as Direct_Unowned. // - direct and non-trivial, pass the argument as Direct_Owned. // - indirect, pass the argument using the same parameter convention as in the // original closure. // // We use the type of the closure here since we allow for the closure to be an // external declaration. unsigned NumTotalParams = ClosedOverFunConv.getNumParameters(); unsigned NumNotCaptured = NumTotalParams - CallSiteDesc.getNumArguments(); for (auto &PInfo : ClosedOverFunConv.getParameters().slice(NumNotCaptured)) { ParameterConvention ParamConv; if (PInfo.isFormalIndirect()) { ParamConv = PInfo.getConvention(); assert(!SILModuleConventions(M).useLoweredAddresses() || ParamConv == ParameterConvention::Indirect_Inout || ParamConv == ParameterConvention::Indirect_InoutAliasable); } else { ParamConv = ClosedOverFunConv.getSILType(PInfo).isTrivial(M) ? ParameterConvention::Direct_Unowned : ParameterConvention::Direct_Owned; } SILParameterInfo NewPInfo(PInfo.getType(), ParamConv); NewParameterInfoList.push_back(NewPInfo); } // The specialized function is always a thin function. This is important // because we may add additional parameters after the Self parameter of // witness methods. In this case the new function is not a method anymore. auto ExtInfo = ClosureUserFunTy->getExtInfo(); ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); auto ClonedTy = SILFunctionType::get( ClosureUserFunTy->getGenericSignature(), ExtInfo, ClosureUserFunTy->getCoroutineKind(), ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList, ClosureUserFunTy->getYields(), ClosureUserFunTy->getResults(), ClosureUserFunTy->getOptionalErrorResult(), M.getASTContext()); // We make this function bare so we don't have to worry about decls in the // SILArgument. auto *Fn = FunctionBuilder.createFunction( // It's important to use a shared linkage for the specialized function // and not the original linkage. // Otherwise the new function could have an external linkage (in case the // original function was de-serialized) and would not be code-gen'd. // It's also important to disconnect this specialized function from any // classes (the classSubclassScope), because that may incorrectly // influence the linkage. getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()), ClonedName, ClonedTy, ClosureUser->getGenericEnvironment(), ClosureUser->getLocation(), IsBare, ClosureUser->isTransparent(), CallSiteDesc.isSerialized(), IsNotDynamic, ClosureUser->getEntryCount(), ClosureUser->isThunk(), /*classSubclassScope=*/SubclassScope::NotApplicable, ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(), ClosureUser, ClosureUser->getDebugScope()); if (!ClosureUser->hasQualifiedOwnership()) { Fn->setUnqualifiedOwnership(); } for (auto &Attr : ClosureUser->getSemanticsAttrs()) Fn->addSemanticsAttr(Attr); return Fn; }
/// In this function we create the actual cloned function and its proper cloned /// type. But we do not create any body. This implies that the creation of the /// actual arguments in the function is in populateCloned. /// /// \arg PAUser The function that is being passed the partial apply. /// \arg PAI The partial apply that is being passed to PAUser. /// \arg ClosureIndex The index of the partial apply in PAUser's function /// signature. /// \arg ClonedName The name of the cloned function that we will create. SILFunction * ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc, StringRef ClonedName) { SILFunction *ClosureUser = CallSiteDesc.getApplyCallee(); // This is the list of new interface parameters of the cloned function. llvm::SmallVector<SILParameterInfo, 4> NewParameterInfoList; // First add to NewParameterInfoList all of the SILParameterInfo in the // original function except for the closure. CanSILFunctionType ClosureUserFunTy = ClosureUser->getLoweredFunctionType(); unsigned Index = ClosureUserFunTy->getNumIndirectResults(); for (auto ¶m : ClosureUserFunTy->getParameters()) { if (Index != CallSiteDesc.getClosureIndex()) NewParameterInfoList.push_back(param); ++Index; } // Then add any arguments that are captured in the closure to the function's // argument type. Since they are captured, we need to pass them directly into // the new specialized function. SILFunction *ClosedOverFun = CallSiteDesc.getClosureCallee(); CanSILFunctionType ClosedOverFunTy = ClosedOverFun->getLoweredFunctionType(); SILModule &M = ClosureUser->getModule(); // Captured parameters are always appended to the function signature. If the // type of the captured argument is trivial, pass the argument as // Direct_Unowned. Otherwise pass it as Direct_Owned. // // We use the type of the closure here since we allow for the closure to be an // external declaration. unsigned NumTotalParams = ClosedOverFunTy->getParameters().size(); unsigned NumNotCaptured = NumTotalParams - CallSiteDesc.getNumArguments(); for (auto &PInfo : ClosedOverFunTy->getParameters().slice(NumNotCaptured)) { if (PInfo.getSILType().isTrivial(M)) { SILParameterInfo NewPInfo(PInfo.getType(), ParameterConvention::Direct_Unowned); NewParameterInfoList.push_back(NewPInfo); continue; } SILParameterInfo NewPInfo(PInfo.getType(), ParameterConvention::Direct_Owned); NewParameterInfoList.push_back(NewPInfo); } // The specialized function is always a thin function. This is important // because we may add additional parameters after the Self parameter of // witness methods. In this case the new function is not a method anymore. auto ExtInfo = ClosureUserFunTy->getExtInfo(); ExtInfo = ExtInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); auto ClonedTy = SILFunctionType::get( ClosureUserFunTy->getGenericSignature(), ExtInfo, ClosureUserFunTy->getCalleeConvention(), NewParameterInfoList, ClosureUserFunTy->getAllResults(), ClosureUserFunTy->getOptionalErrorResult(), M.getASTContext()); // We make this function bare so we don't have to worry about decls in the // SILArgument. auto *Fn = M.createFunction( // It's important to use a shared linkage for the specialized function // and not the original linkage. // Otherwise the new function could have an external linkage (in case the // original function was de-serialized) and would not be code-gen'd. getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()), ClonedName, ClonedTy, ClosureUser->getGenericEnvironment(), ClosureUser->getLocation(), IsBare, ClosureUser->isTransparent(), CallSiteDesc.isFragile(), ClosureUser->isThunk(), ClosureUser->getClassVisibility(), ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(), ClosureUser, ClosureUser->getDebugScope()); Fn->setDeclCtx(ClosureUser->getDeclContext()); if (ClosureUser->hasUnqualifiedOwnership()) { Fn->setUnqualifiedOwnership(); } for (auto &Attr : ClosureUser->getSemanticsAttrs()) Fn->addSemanticsAttr(Attr); return Fn; }
void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() { // Create the optimized function ! SILModule &M = F->getModule(); std::string Name = createOptimizedSILFunctionName(); SILLinkage linkage = F->getLinkage(); if (isAvailableExternally(linkage)) linkage = SILLinkage::Shared; DEBUG(llvm::dbgs() << " -> create specialized function " << Name << "\n"); NewF = M.createFunction(linkage, Name, createOptimizedSILFunctionType(), F->getGenericEnvironment(), F->getLocation(), F->isBare(), F->isTransparent(), F->isSerialized(), F->isThunk(), F->getClassVisibility(), F->getInlineStrategy(), F->getEffectsKind(), nullptr, F->getDebugScope()); if (F->hasUnqualifiedOwnership()) { NewF->setUnqualifiedOwnership(); } // Then we transfer the body of F to NewF. NewF->spliceBody(F); // Array semantic clients rely on the signature being as in the original // version. for (auto &Attr : F->getSemanticsAttrs()) { if (!StringRef(Attr).startswith("array.")) NewF->addSemanticsAttr(Attr); } // Do the last bit of work to the newly created optimized function. ArgumentExplosionFinalizeOptimizedFunction(); DeadArgumentFinalizeOptimizedFunction(); // Create the thunk body ! F->setThunk(IsThunk); // The thunk now carries the information on how the signature is // optimized. If we inline the thunk, we will get the benefit of calling // the signature optimized function without additional setup on the // caller side. F->setInlineStrategy(AlwaysInline); SILBasicBlock *ThunkBody = F->createBasicBlock(); for (auto &ArgDesc : ArgumentDescList) { ThunkBody->createFunctionArgument(ArgDesc.Arg->getType(), ArgDesc.Decl); } SILLocation Loc = ThunkBody->getParent()->getLocation(); SILBuilder Builder(ThunkBody); Builder.setCurrentDebugScope(ThunkBody->getParent()->getDebugScope()); FunctionRefInst *FRI = Builder.createFunctionRef(Loc, NewF); // Create the args for the thunk's apply, ignoring any dead arguments. llvm::SmallVector<SILValue, 8> ThunkArgs; for (auto &ArgDesc : ArgumentDescList) { addThunkArgument(ArgDesc, Builder, ThunkBody, ThunkArgs); } // We are ignoring generic functions and functions with out parameters for // now. SILValue ReturnValue; SILType LoweredType = NewF->getLoweredType(); SILType ResultType = NewF->getConventions().getSILResultType(); auto FunctionTy = LoweredType.castTo<SILFunctionType>(); if (FunctionTy->hasErrorResult()) { // We need a try_apply to call a function with an error result. SILFunction *Thunk = ThunkBody->getParent(); SILBasicBlock *NormalBlock = Thunk->createBasicBlock(); ReturnValue = NormalBlock->createPHIArgument(ResultType, ValueOwnershipKind::Owned); SILBasicBlock *ErrorBlock = Thunk->createBasicBlock(); SILType Error = SILType::getPrimitiveObjectType(FunctionTy->getErrorResult().getType()); auto *ErrorArg = ErrorBlock->createPHIArgument(Error, ValueOwnershipKind::Owned); Builder.createTryApply(Loc, FRI, LoweredType, SubstitutionList(), ThunkArgs, NormalBlock, ErrorBlock); Builder.setInsertionPoint(ErrorBlock); Builder.createThrow(Loc, ErrorArg); Builder.setInsertionPoint(NormalBlock); } else { ReturnValue = Builder.createApply(Loc, FRI, LoweredType, ResultType, SubstitutionList(), ThunkArgs, false); } // Set up the return results. if (NewF->isNoReturnFunction()) { Builder.createUnreachable(Loc); } else { Builder.createReturn(Loc, ReturnValue); } // Do the last bit work to finalize the thunk. OwnedToGuaranteedFinalizeThunkFunction(Builder, F); assert(F->getDebugScope()->Parent != NewF->getDebugScope()->Parent); }