Index: llvm/include/llvm/Analysis/FuncSpecCost.h =================================================================== --- /dev/null +++ llvm/include/llvm/Analysis/FuncSpecCost.h @@ -0,0 +1,95 @@ +//===- FuncSpecCost.h - Cost analysis for function specialization -*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===------------------------------------------------------------------------===// +// +// This file implements heuristics for function specialization decisions. +// +//===------------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_FUNCSPECCOST_H +#define LLVM_ANALYSIS_FUNCSPECCOST_H + +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/PassManager.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" +#include "llvm/Support/InstructionCost.h" + +namespace llvm { + +class AssumptionCache; +class TargetTransformInfo; +class TargetLibraryInfo; + +/// Cost/Bonus information for specialize a function with +/// each argument. +class FuncSpecCostInfo { + /// The cost to specialize the function. + InstructionCost Cost; + /// Map from the number of the argument, to the base bonuss for specialize it. + /// Base bonus stands for the bonus we could get by the function body. + MapVector SpecBonusBaseMap; + + unsigned getBonusBase(Argument *Arg) const; + unsigned getBonusBase(unsigned Index) const; + +public: + InstructionCost getCost() const { return Cost; } + unsigned + getBonus(Argument *Arg, Constant *C, + function_ref GetTTI, + function_ref GetAC, + function_ref GetTLI) const; + + FuncSpecCostInfo() {} + FuncSpecCostInfo(FuncSpecCostInfo &&Other) + : FuncSpecCostInfo(std::move(Other.Cost), + std::move(Other.SpecBonusBaseMap)) {} + FuncSpecCostInfo(InstructionCost Cost, + MapVector &&BonusBaseMap) + : Cost(std::move(Cost)) { + SpecBonusBaseMap.swap(BonusBaseMap); + } +}; + +/// Analysis pass which computes a \c FuncSpecCostInfo. +class FunctionSpecializationAnalysis + : public AnalysisInfoMixin { + friend AnalysisInfoMixin; + static AnalysisKey Key; + +public: + using Result = FuncSpecCostInfo; + + Result run(Function &F, FunctionAnalysisManager &); +}; + +/// Legacy analysis pass which computes a \c FuncSpecCostInfo. +class FunctionSpecializationWrapperPass : public FunctionPass { + Optional Info; + +public: + static char ID; + + FunctionSpecializationWrapperPass(); + + FuncSpecCostInfo &getFuncSpecCost() { return *Info; } + const FuncSpecCostInfo &getFuncSpecCost() const { return *Info; } + + bool runOnFunction(Function &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override; + + StringRef getPassName() const override; +}; + +} // namespace llvm + +#endif Index: llvm/include/llvm/InitializePasses.h =================================================================== --- llvm/include/llvm/InitializePasses.h +++ llvm/include/llvm/InitializePasses.h @@ -169,6 +169,7 @@ void initializeFuncletLayoutPass(PassRegistry&); void initializeFunctionImportLegacyPassPass(PassRegistry&); void initializeFunctionSpecializationLegacyPassPass(PassRegistry &); +void initializeFunctionSpecializationWrapperPassPass(PassRegistry &); void initializeGCMachineCodeAnalysisPass(PassRegistry&); void initializeGCModuleInfoPass(PassRegistry&); void initializeGCOVProfilerLegacyPassPass(PassRegistry&); Index: llvm/include/llvm/Transforms/Scalar/SCCP.h =================================================================== --- llvm/include/llvm/Transforms/Scalar/SCCP.h +++ llvm/include/llvm/Transforms/Scalar/SCCP.h @@ -33,6 +33,7 @@ namespace llvm { class PostDominatorTree; +class FuncSpecCostInfo; /// This pass performs function-level constant propagation and merging. class SCCPPass : public PassInfoMixin { @@ -49,6 +50,7 @@ std::function GetTLI, std::function GetTTI, std::function GetAC, + std::function GetFSCI, function_ref GetAnalysis); } // end namespace llvm Index: llvm/lib/Analysis/Analysis.cpp =================================================================== --- llvm/lib/Analysis/Analysis.cpp +++ llvm/lib/Analysis/Analysis.cpp @@ -42,6 +42,7 @@ initializeDomViewerPass(Registry); initializeDomPrinterPass(Registry); initializeDomOnlyViewerPass(Registry); + initializeFunctionSpecializationWrapperPassPass(Registry); initializePostDomViewerPass(Registry); initializeDomOnlyPrinterPass(Registry); initializePostDomPrinterPass(Registry); Index: llvm/lib/Analysis/CMakeLists.txt =================================================================== --- llvm/lib/Analysis/CMakeLists.txt +++ llvm/lib/Analysis/CMakeLists.txt @@ -69,6 +69,7 @@ DomTreeUpdater.cpp DominanceFrontier.cpp EHPersonalities.cpp + FuncSpecCost.cpp FunctionPropertiesAnalysis.cpp GlobalsModRef.cpp GuardUtils.cpp Index: llvm/lib/Analysis/FuncSpecCost.cpp =================================================================== --- /dev/null +++ llvm/lib/Analysis/FuncSpecCost.cpp @@ -0,0 +1,223 @@ +//===- FuncSpecCost.cpp - Cost analysis for function specializer +//-*---------===// +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===-----------------------------------------------------------------------===// +// +// This file implements heuristics for specializing function decisions. +// +//===-----------------------------------------------------------------------===// + +#include "llvm/Analysis/FuncSpecCost.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/CodeMetrics.h" +#include "llvm/Analysis/InlineCost.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Support/CommandLine.h" +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "func-spec-cost" + +static cl::opt + AvgLoopIterationCount("func-specialization-avg-iters-cost", cl::Hidden, + cl::desc("Average loop iteration count cost"), + cl::init(10)); + +static Function *getFunction(Value *CalledValue) { + // Since the argument is a function pointer, its incoming constant values + // should be functions or constant expressions. The code below attempts to + // look through cast expressions to find the function that will be called. + if (!isa(CalledValue->getType()) || + !isa(CalledValue->getType()->getPointerElementType())) + return nullptr; + + while (isa(CalledValue) && + cast(CalledValue)->isCast()) + CalledValue = cast(CalledValue)->getOperand(0); + return dyn_cast(CalledValue); +} + +/// Bonus equals to basebonus plus extrabonus. +/// The extrabonus means bonus we could find at the callsites. +/// For example, if the callsite passes a function to the specializing function, +/// we could compute the bonus for the callsite by the bonus of inline +/// the function into the specializing function. +unsigned FuncSpecCostInfo::getBonus( + Argument *Arg, Constant *C, + function_ref GetTTI, + function_ref GetAC, + function_ref GetTLI) const { + LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing bonus for: " << *Arg + << "\n"); + + unsigned BonusBase = getBonusBase(Arg); + + // The below heuristic is only concerned with exposing inlining + // opportunities via indirect call promotion. If the argument is not a + // function pointer, give up. + Function *CalledFunction = getFunction(C); + if (!CalledFunction) + return BonusBase; + + // Get TTI for the called function (used for the inline cost). + auto &CalleeTTI = (GetTTI)(*CalledFunction); + + int Bonus = 0; + for (User *U : Arg->users()) { + if (!isa(U) && !isa(U)) + continue; + auto *CS = cast(U); + if (CS->getCalledOperand() != Arg) + continue; + + // Get the cost of inlining the called function at this call site. Note + // that this is only an estimate. The called function may eventually + // change in a way that leads to it not being inlined here, even though + // inlining looks profitable now. For example, one of its called + // functions may be inlined into it, making the called function too large + // to be inlined into this call site. + // + // We apply a boost for performing indirect call promotion by increasing + // the default threshold by the threshold for indirect calls. + auto Params = getInlineParams(); + Params.DefaultThreshold += InlineConstants::IndirectCallThreshold; + InlineCost IC = + getInlineCost(*CS, CalledFunction, Params, CalleeTTI, GetAC, GetTLI); + + // We clamp the bonus for this call to be between zero and the default + // threshold. + if (IC.isAlways()) + Bonus += Params.DefaultThreshold; + else if (IC.isVariable() && IC.getCostDelta() > 0) + Bonus += IC.getCostDelta(); + } + + return BonusBase + Bonus; +} + +unsigned FuncSpecCostInfo::getBonusBase(Argument *Arg) const { + return getBonusBase(Arg->getArgNo()); +} + +unsigned FuncSpecCostInfo::getBonusBase(unsigned Index) const { + if (!SpecBonusBaseMap.count(Index)) + return 0; + return SpecBonusBaseMap.lookup(Index); +} + +static InstructionCost getSpecializationCost(Function &F, AssumptionCache &AC, + TargetTransformInfo &TTI) { + // Compute the code metrics for the function. + SmallPtrSet EphValues; + CodeMetrics::collectEphemeralValues(&F, &AC, EphValues); + CodeMetrics Metrics; + for (BasicBlock &BB : F) + Metrics.analyzeBasicBlock(&BB, TTI, EphValues); + + // If the code metrics reveal that we shouldn't duplicate the function, we + // shouldn't specialize it. Set the specialization cost to Invalid. + if (Metrics.notDuplicatable) { + InstructionCost C{}; + C.setInvalid(); + return C; + } + + return Metrics.NumInsts * InlineConstants::InstrCost; +} + +static InstructionCost getUserBonus(User *U, TargetTransformInfo &TTI, + LoopInfo &LI) { + auto *I = dyn_cast_or_null(U); + // If not an instruction we do not know how to evaluate. + // Keep minimum possible cost for now so that it doesnt affect + // specialization. + if (!I) + return std::numeric_limits::min(); + + InstructionCost Cost = + TTI.getUserCost(U, TargetTransformInfo::TCK_SizeAndLatency); + + // Traverse recursively if there are more uses. + // TODO: Any other instructions to be added here? + if (I->mayReadFromMemory() || I->isCast()) + for (auto *User : I->users()) + Cost += getUserBonus(User, TTI, LI); + + // Increase the cost if it is inside the loop. + unsigned LoopDepth = LI.getLoopDepth(I->getParent()); + Cost *= std::pow((long double)AvgLoopIterationCount, LoopDepth); + return Cost; +} + +static FuncSpecCostInfo CreateFuncSpecCostInfo(Function &F, AssumptionCache &AC, + TargetTransformInfo &TTI, + LoopInfo &LI) { + InstructionCost SpecializeCost = getSpecializationCost(F, AC, TTI); + MapVector SpecBonusBaseMap; + for (Argument &A : F.args()) { + InstructionCost Cost = 0; + for (auto *U : A.users()) + Cost += getUserBonus(U, TTI, LI); + + if (Cost.isValid() && Cost > 0) + SpecBonusBaseMap.insert({A.getArgNo(), *Cost.getValue()}); + } + return FuncSpecCostInfo(SpecializeCost, std::move(SpecBonusBaseMap)); +} + +AnalysisKey FunctionSpecializationAnalysis::Key; + +FuncSpecCostInfo +FunctionSpecializationAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { + TargetTransformInfo &TTI = FAM.getResult(F); + LoopInfo &LI = FAM.getResult(F); + AssumptionCache &AC = FAM.getResult(F); + return CreateFuncSpecCostInfo(F, AC, TTI, LI); +} + +char FunctionSpecializationWrapperPass::ID = 0; +INITIALIZE_PASS_BEGIN(FunctionSpecializationWrapperPass, "func-spec-cost", + "Function Specialization Cost Analysis", false, true) +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) +INITIALIZE_PASS_END(FunctionSpecializationWrapperPass, "func-spec-cost", + "Function Specialization Cost Analysis", false, true) + +FunctionSpecializationWrapperPass::FunctionSpecializationWrapperPass() + : FunctionPass(ID) { + initializeFunctionSpecializationWrapperPassPass( + *PassRegistry::getPassRegistry()); +} + +void FunctionSpecializationWrapperPass::getAnalysisUsage( + AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); +} + +bool FunctionSpecializationWrapperPass::runOnFunction(Function &F) { + TargetTransformInfo &TTI = + getAnalysis().getTTI(F); + LoopInfo &LI = getAnalysis().getLoopInfo(); + AssumptionCache &AC = + getAnalysis().getAssumptionCache(F); + Info.emplace(CreateFuncSpecCostInfo(F, AC, TTI, LI)); + return false; +} + +StringRef FunctionSpecializationWrapperPass::getPassName() const { + return "Function Specialization Cost Analysis"; +} \ No newline at end of file Index: llvm/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/lib/Passes/PassBuilder.cpp +++ llvm/lib/Passes/PassBuilder.cpp @@ -34,6 +34,7 @@ #include "llvm/Analysis/DependenceAnalysis.h" #include "llvm/Analysis/DivergenceAnalysis.h" #include "llvm/Analysis/DominanceFrontier.h" +#include "llvm/Analysis/FuncSpecCost.h" #include "llvm/Analysis/FunctionPropertiesAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/IRSimilarityIdentifier.h" Index: llvm/lib/Passes/PassRegistry.def =================================================================== --- llvm/lib/Passes/PassRegistry.def +++ llvm/lib/Passes/PassRegistry.def @@ -156,6 +156,7 @@ FUNCTION_ANALYSIS("demanded-bits", DemandedBitsAnalysis()) FUNCTION_ANALYSIS("domfrontier", DominanceFrontierAnalysis()) FUNCTION_ANALYSIS("func-properties", FunctionPropertiesAnalysis()) +FUNCTION_ANALYSIS("func-spec-analysis", FunctionSpecializationAnalysis()) FUNCTION_ANALYSIS("loops", LoopAnalysis()) FUNCTION_ANALYSIS("lazy-value-info", LazyValueAnalysis()) FUNCTION_ANALYSIS("da", DependenceAnalysis()) Index: llvm/lib/Transforms/IPO/FunctionSpecialization.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -28,6 +28,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/DomTreeUpdater.h" +#include "llvm/Analysis/FuncSpecCost.h" #include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -59,11 +60,6 @@ "specialization"), cl::init(3)); -static cl::opt - AvgLoopIterationCount("func-specialization-avg-iters-cost", cl::Hidden, - cl::desc("Average loop iteration count cost"), - cl::init(10)); - static cl::opt EnableSpecializationForLiteralConstant( "function-specialization-for-literal-constant", cl::init(false), cl::Hidden, cl::desc("Make function specialization available for literal constant.")); @@ -82,6 +78,7 @@ std::function GetAC; std::function GetTTI; std::function GetTLI; + std::function GetFSCI; SmallPtrSet SpecializedFuncs; @@ -89,8 +86,10 @@ FunctionSpecializer(SCCPSolver &Solver, std::function GetAC, std::function GetTTI, - std::function GetTLI) - : Solver(Solver), GetAC(GetAC), GetTTI(GetTTI), GetTLI(GetTLI) {} + std::function GetTLI, + std::function GetFSCI) + : Solver(Solver), GetAC(GetAC), GetTTI(GetTTI), GetTLI(GetTLI), + GetFSCI(GetFSCI) {} /// Attempt to specialize functions in the module to enable constant /// propagation across function boundaries. @@ -244,123 +243,16 @@ /// Compute the cost of specializing function \p F. InstructionCost getSpecializationCost(Function *F) { - // Compute the code metrics for the function. - SmallPtrSet EphValues; - CodeMetrics::collectEphemeralValues(F, &(GetAC)(*F), EphValues); - CodeMetrics Metrics; - for (BasicBlock &BB : *F) - Metrics.analyzeBasicBlock(&BB, (GetTTI)(*F), EphValues); - - // If the code metrics reveal that we shouldn't duplicate the function, we - // shouldn't specialize it. Set the specialization cost to Invalid. - if (Metrics.notDuplicatable) { - InstructionCost C{}; - C.setInvalid(); - return C; - } - - // Otherwise, set the specialization cost to be the cost of all the - // instructions in the function and penalty for specializing more functions. - unsigned Penalty = NbFunctionsSpecialized + 1; - return Metrics.NumInsts * InlineConstants::InstrCost * Penalty; - } - - InstructionCost getUserBonus(User *U, llvm::TargetTransformInfo &TTI, - LoopInfo &LI) { - auto *I = dyn_cast_or_null(U); - // If not an instruction we do not know how to evaluate. - // Keep minimum possible cost for now so that it doesnt affect - // specialization. - if (!I) - return std::numeric_limits::min(); - - auto Cost = TTI.getUserCost(U, TargetTransformInfo::TCK_SizeAndLatency); - - // Traverse recursively if there are more uses. - // TODO: Any other instructions to be added here? - if (I->mayReadFromMemory() || I->isCast()) - for (auto *User : I->users()) - Cost += getUserBonus(User, TTI, LI); - - // Increase the cost if it is inside the loop. - auto LoopDepth = LI.getLoopDepth(I->getParent()); - Cost *= std::pow((double)AvgLoopIterationCount, LoopDepth); - return Cost; + FuncSpecCostInfo &FSCI = GetFSCI(*F); + // Penalty for specializing more functions. + unsigned Penalty = (NumFuncSpecialized + 1); + return FSCI.getCost() * Penalty; } /// Compute a bonus for replacing argument \p A with constant \p C. InstructionCost getSpecializationBonus(Argument *A, Constant *C) { - Function *F = A->getParent(); - DominatorTree DT(*F); - LoopInfo LI(DT); - auto &TTI = (GetTTI)(*F); - LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing bonus for: " << *A - << "\n"); - - InstructionCost TotalCost = 0; - for (auto *U : A->users()) { - TotalCost += getUserBonus(U, TTI, LI); - LLVM_DEBUG(dbgs() << "FnSpecialization: User cost "; - TotalCost.print(dbgs()); dbgs() << " for: " << *U << "\n"); - } - - // The below heuristic is only concerned with exposing inlining - // opportunities via indirect call promotion. If the argument is not a - // function pointer, give up. - if (!isa(A->getType()) || - !isa(A->getType()->getPointerElementType())) - return TotalCost; - - // Since the argument is a function pointer, its incoming constant values - // should be functions or constant expressions. The code below attempts to - // look through cast expressions to find the function that will be called. - Value *CalledValue = C; - while (isa(CalledValue) && - cast(CalledValue)->isCast()) - CalledValue = cast(CalledValue)->getOperand(0); - Function *CalledFunction = dyn_cast(CalledValue); - if (!CalledFunction) - return TotalCost; - - // Get TTI for the called function (used for the inline cost). - auto &CalleeTTI = (GetTTI)(*CalledFunction); - - // Look at all the call sites whose called value is the argument. - // Specializing the function on the argument would allow these indirect - // calls to be promoted to direct calls. If the indirect call promotion - // would likely enable the called function to be inlined, specializing is a - // good idea. - int Bonus = 0; - for (User *U : A->users()) { - if (!isa(U) && !isa(U)) - continue; - auto *CS = cast(U); - if (CS->getCalledOperand() != A) - continue; - - // Get the cost of inlining the called function at this call site. Note - // that this is only an estimate. The called function may eventually - // change in a way that leads to it not being inlined here, even though - // inlining looks profitable now. For example, one of its called - // functions may be inlined into it, making the called function too large - // to be inlined into this call site. - // - // We apply a boost for performing indirect call promotion by increasing - // the default threshold by the threshold for indirect calls. - auto Params = getInlineParams(); - Params.DefaultThreshold += InlineConstants::IndirectCallThreshold; - InlineCost IC = - getInlineCost(*CS, CalledFunction, Params, CalleeTTI, GetAC, GetTLI); - - // We clamp the bonus for this call to be between zero and the default - // threshold. - if (IC.isAlways()) - Bonus += Params.DefaultThreshold; - else if (IC.isVariable() && IC.getCostDelta() > 0) - Bonus += IC.getCostDelta(); - } - - return TotalCost + Bonus; + FuncSpecCostInfo &FSCI = GetFSCI(*A->getParent()); + return FSCI.getBonus(A, C, GetTTI, GetAC, GetTLI); } /// Determine if we should specialize a function based on the incoming values @@ -551,9 +443,10 @@ std::function GetTLI, std::function GetTTI, std::function GetAC, + std::function GetFSCI, function_ref GetAnalysis) { SCCPSolver Solver(DL, GetTLI, M.getContext()); - FunctionSpecializer FS(Solver, GetAC, GetTTI, GetTLI); + FunctionSpecializer FS(Solver, GetAC, GetTTI, GetTLI, GetFSCI); bool Changed = false; // Loop over all functions, marking arguments to those with their addresses Index: llvm/lib/Transforms/IPO/SCCP.cpp =================================================================== --- llvm/lib/Transforms/IPO/SCCP.cpp +++ llvm/lib/Transforms/IPO/SCCP.cpp @@ -12,6 +12,7 @@ #include "llvm/Transforms/IPO/SCCP.h" #include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/FuncSpecCost.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" @@ -118,6 +119,9 @@ auto GetAC = [&FAM](Function &F) -> AssumptionCache & { return FAM.getResult(F); }; + auto GetFSCI = [&FAM](Function &F) -> FuncSpecCostInfo & { + return FAM.getResult(F); + }; auto GetAnalysis = [&FAM](Function &F) -> AnalysisResultsForFn { DominatorTree &DT = FAM.getResult(F); return {std::make_unique( @@ -125,7 +129,8 @@ &DT, FAM.getCachedResult(F)}; }; - if (!runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetAnalysis)) + if (!runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetFSCI, + GetAnalysis)) return PreservedAnalyses::all(); PreservedAnalyses PA; @@ -144,6 +149,7 @@ AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); } virtual bool runOnModule(Module &M) override { @@ -160,6 +166,10 @@ auto GetAC = [this](Function &F) -> AssumptionCache & { return this->getAnalysis().getAssumptionCache(F); }; + auto GetFSCI = [this](Function &F) -> FuncSpecCostInfo & { + return this->getAnalysis(F) + .getFuncSpecCost(); + }; auto GetAnalysis = [this](Function &F) -> AnalysisResultsForFn { DominatorTree &DT = @@ -172,7 +182,8 @@ nullptr, // We cannot preserve the DT or PDT with the legacy pass nullptr}; // manager, so set them to nullptr. }; - return runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetAnalysis); + return runFunctionSpecialization(M, DL, GetTLI, GetTTI, GetAC, GetFSCI, + GetAnalysis); } };