CanSILFunctionType FunctionSignatureTransformDescriptor::createOptimizedSILFunctionType() { SILFunction *F = OriginalFunction; CanSILFunctionType FTy = F->getLoweredFunctionType(); auto ExpectedFTy = F->getLoweredType().castTo<SILFunctionType>(); auto HasGenericSignature = FTy->getGenericSignature() != nullptr; // The only way that we modify the arity of function parameters is here for // dead arguments. Doing anything else is unsafe since by definition non-dead // arguments will have SSA uses in the function. We would need to be smarter // in our moving to handle such cases. llvm::SmallVector<SILParameterInfo, 8> InterfaceParams; for (auto &ArgDesc : ArgumentDescList) { computeOptimizedArgInterface(ArgDesc, InterfaceParams); } // ResultDescs only covers the direct results; we currently can't ever // change an indirect result. Piece the modified direct result information // back into the all-results list. llvm::SmallVector<SILResultInfo, 8> InterfaceResults; for (SILResultInfo InterfaceResult : FTy->getResults()) { if (InterfaceResult.isFormalDirect()) { auto &RV = ResultDescList[0]; if (!RV.CalleeRetain.empty()) { ++NumOwnedConvertedToNotOwnedResult; InterfaceResults.push_back(SILResultInfo(InterfaceResult.getType(), ResultConvention::Unowned)); continue; } } InterfaceResults.push_back(InterfaceResult); } llvm::SmallVector<SILYieldInfo, 8> InterfaceYields; for (SILYieldInfo InterfaceYield : FTy->getYields()) { // For now, don't touch the yield types. InterfaceYields.push_back(InterfaceYield); } bool UsesGenerics = false; if (HasGenericSignature) { // Not all of the generic type parameters are used by the function // parameters. // Check which of the generic type parameters are not used and check if they // are used anywhere in the function body. If this is not the case, we can // remove the unused generic type parameters from the generic signature. // This makes the code both smaller and faster, because no implicit // parameters for type metadata and conformances need to be passed to the // callee at the LLVM IR level. // TODO: Implement a more precise analysis, so that we can eliminate only // those generic parameters which are not used. UsesGenerics = usesGenerics(F, InterfaceParams, InterfaceResults); // The set of used archetypes is complete now. if (!UsesGenerics) { // None of the generic type parameters are used. LLVM_DEBUG(llvm::dbgs() << "None of generic parameters are used by " << F->getName() << "\n"; llvm::dbgs() << "Interface params:\n"; for (auto Param : InterfaceParams) { Param.getType().dump(); } llvm::dbgs() << "Interface results:\n"; for (auto Result : InterfaceResults) { Result.getType().dump(); }); }
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); }