1 //===- FunctionSpecialization.cpp - Function Specialization ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This specialises functions with constant parameters (e.g. functions,
10 // globals). Constant parameters like function pointers and constant globals
11 // are propagated to the callee by specializing the function.
12 //
13 // Current limitations:
14 // - It does not handle specialization of recursive functions,
15 // - It does not yet handle integer constants, and integer ranges,
16 // - Only 1 argument per function is specialised,
17 // - The cost-model could be further looked into,
18 // - We are not yet caching analysis results.
19 //
20 // Ideas:
21 // - With a function specialization attribute for arguments, we could have
22 //   a direct way to steer function specialization, avoiding the cost-model,
23 //   and thus control compile-times / code-size.
24 //
25 //===----------------------------------------------------------------------===//
26 
27 #include "llvm/ADT/Statistic.h"
28 #include "llvm/Analysis/AssumptionCache.h"
29 #include "llvm/Analysis/CodeMetrics.h"
30 #include "llvm/Analysis/DomTreeUpdater.h"
31 #include "llvm/Analysis/InlineCost.h"
32 #include "llvm/Analysis/LoopInfo.h"
33 #include "llvm/Analysis/TargetLibraryInfo.h"
34 #include "llvm/Analysis/TargetTransformInfo.h"
35 #include "llvm/Transforms/Scalar/SCCP.h"
36 #include "llvm/Transforms/Utils/Cloning.h"
37 #include "llvm/Transforms/Utils/SizeOpts.h"
38 #include <cmath>
39 
40 using namespace llvm;
41 
42 #define DEBUG_TYPE "function-specialization"
43 
44 STATISTIC(NumFuncSpecialized, "Number of functions specialized");
45 
46 static cl::opt<bool> ForceFunctionSpecialization(
47     "force-function-specialization", cl::init(false), cl::Hidden,
48     cl::desc("Force function specialization for every call site with a "
49              "constant argument"));
50 
51 static cl::opt<unsigned> FuncSpecializationMaxIters(
52     "func-specialization-max-iters", cl::Hidden,
53     cl::desc("The maximum number of iterations function specialization is run"),
54     cl::init(1));
55 
56 static cl::opt<unsigned> MaxConstantsThreshold(
57     "func-specialization-max-constants", cl::Hidden,
58     cl::desc("The maximum number of clones allowed for a single function "
59              "specialization"),
60     cl::init(3));
61 
62 static cl::opt<unsigned>
63     AvgLoopIterationCount("func-specialization-avg-iters-cost", cl::Hidden,
64                           cl::desc("Average loop iteration count cost"),
65                           cl::init(10));
66 
67 // Helper to check if \p LV is either overdefined or a constant int.
68 static bool isOverdefined(const ValueLatticeElement &LV) {
69   return !LV.isUnknownOrUndef() && !LV.isConstant();
70 }
71 
72 class FunctionSpecializer {
73 
74   /// The IPSCCP Solver.
75   SCCPSolver &Solver;
76 
77   /// Analyses used to help determine if a function should be specialized.
78   std::function<AssumptionCache &(Function &)> GetAC;
79   std::function<TargetTransformInfo &(Function &)> GetTTI;
80   std::function<TargetLibraryInfo &(Function &)> GetTLI;
81 
82   SmallPtrSet<Function *, 2> SpecializedFuncs;
83 
84 public:
85   FunctionSpecializer(SCCPSolver &Solver,
86                       std::function<AssumptionCache &(Function &)> GetAC,
87                       std::function<TargetTransformInfo &(Function &)> GetTTI,
88                       std::function<TargetLibraryInfo &(Function &)> GetTLI)
89       : Solver(Solver), GetAC(GetAC), GetTTI(GetTTI), GetTLI(GetTLI) {}
90 
91   /// Attempt to specialize functions in the module to enable constant
92   /// propagation across function boundaries.
93   ///
94   /// \returns true if at least one function is specialized.
95   bool
96   specializeFunctions(SmallVectorImpl<Function *> &FuncDecls,
97                       SmallVectorImpl<Function *> &CurrentSpecializations) {
98 
99     // Attempt to specialize the argument-tracked functions.
100     bool Changed = false;
101     for (auto *F : FuncDecls) {
102       if (specializeFunction(F, CurrentSpecializations)) {
103         Changed = true;
104         LLVM_DEBUG(dbgs() << "FnSpecialization: Can specialize this func.\n");
105       } else {
106         LLVM_DEBUG(
107             dbgs() << "FnSpecialization: Cannot specialize this func.\n");
108       }
109     }
110 
111     for (auto *SpecializedFunc : CurrentSpecializations) {
112       SpecializedFuncs.insert(SpecializedFunc);
113 
114       // TODO: If we want to support specializing specialized functions,
115       // initialize here the state of the newly created functions, marking
116       // them argument-tracked and executable.
117 
118       // Replace the function arguments for the specialized functions.
119       for (Argument &Arg : SpecializedFunc->args())
120         if (!Arg.use_empty() && tryToReplaceWithConstant(&Arg))
121           LLVM_DEBUG(dbgs() << "FnSpecialization: Replaced constant argument: "
122                             << Arg.getName() << "\n");
123     }
124 
125     NumFuncSpecialized += NbFunctionsSpecialized;
126     return Changed;
127   }
128 
129   bool tryToReplaceWithConstant(Value *V) {
130     if (!V->getType()->isSingleValueType() || isa<CallBase>(V) ||
131         V->user_empty())
132       return false;
133 
134     const ValueLatticeElement &IV = Solver.getLatticeValueFor(V);
135     if (isOverdefined(IV))
136       return false;
137     auto *Const = IV.isConstant() ? Solver.getConstant(IV)
138                                   : UndefValue::get(V->getType());
139     V->replaceAllUsesWith(Const);
140 
141     // TODO: Update the solver here if we want to specialize specialized
142     // functions.
143     return true;
144   }
145 
146 private:
147   // The number of functions specialised, used for collecting statistics and
148   // also in the cost model.
149   unsigned NbFunctionsSpecialized = 0;
150 
151   /// This function decides whether to specialize function \p F based on the
152   /// known constant values its arguments can take on. Specialization is
153   /// performed on the first interesting argument. Specializations based on
154   /// additional arguments will be evaluated on following iterations of the
155   /// main IPSCCP solve loop. \returns true if the function is specialized and
156   /// false otherwise.
157   bool specializeFunction(Function *F,
158                           SmallVectorImpl<Function *> &Specializations) {
159 
160     // Do not specialize the cloned function again.
161     if (SpecializedFuncs.contains(F)) {
162       return false;
163     }
164 
165     // If we're optimizing the function for size, we shouldn't specialize it.
166     if (F->hasOptSize() ||
167         shouldOptimizeForSize(F, nullptr, nullptr, PGSOQueryType::IRPass))
168       return false;
169 
170     // Exit if the function is not executable. There's no point in specializing
171     // a dead function.
172     if (!Solver.isBlockExecutable(&F->getEntryBlock()))
173       return false;
174 
175     LLVM_DEBUG(dbgs() << "FnSpecialization: Try function: " << F->getName()
176                       << "\n");
177     // Determine if we should specialize the function based on the values the
178     // argument can take on. If specialization is not profitable, we continue
179     // on to the next argument.
180     for (Argument &A : F->args()) {
181       LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing arg: " << A.getName()
182                         << "\n");
183       // True if this will be a partial specialization. We will need to keep
184       // the original function around in addition to the added specializations.
185       bool IsPartial = true;
186 
187       // Determine if this argument is interesting. If we know the argument can
188       // take on any constant values, they are collected in Constants. If the
189       // argument can only ever equal a constant value in Constants, the
190       // function will be completely specialized, and the IsPartial flag will
191       // be set to false by isArgumentInteresting (that function only adds
192       // values to the Constants list that are deemed profitable).
193       SmallVector<Constant *, 4> Constants;
194       if (!isArgumentInteresting(&A, Constants, IsPartial)) {
195         LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is not interesting\n");
196         continue;
197       }
198 
199       assert(!Constants.empty() && "No constants on which to specialize");
200       LLVM_DEBUG(dbgs() << "FnSpecialization: Argument is interesting!\n"
201                         << "FnSpecialization: Specializing '" << F->getName()
202                         << "' on argument: " << A << "\n"
203                         << "FnSpecialization: Constants are:\n\n";
204                  for (unsigned I = 0; I < Constants.size(); ++I) dbgs()
205                  << *Constants[I] << "\n";
206                  dbgs() << "FnSpecialization: End of constants\n\n");
207 
208       // Create a version of the function in which the argument is marked
209       // constant with the given value.
210       for (auto *C : Constants) {
211         // Clone the function. We leave the ValueToValueMap empty to allow
212         // IPSCCP to propagate the constant arguments.
213         ValueToValueMapTy EmptyMap;
214         Function *Clone = CloneFunction(F, EmptyMap);
215         Argument *ClonedArg = Clone->arg_begin() + A.getArgNo();
216 
217         // Rewrite calls to the function so that they call the clone instead.
218         rewriteCallSites(F, Clone, *ClonedArg, C);
219 
220         // Initialize the lattice state of the arguments of the function clone,
221         // marking the argument on which we specialized the function constant
222         // with the given value.
223         Solver.markArgInFuncSpecialization(F, ClonedArg, C);
224 
225         // Mark all the specialized functions
226         Specializations.push_back(Clone);
227         NbFunctionsSpecialized++;
228       }
229 
230       // TODO: if we want to support specialize specialized functions, and if
231       // the function has been completely specialized, the original function is
232       // no longer needed, so we would need to mark it unreachable here.
233 
234       // FIXME: Only one argument per function.
235       return true;
236     }
237 
238     return false;
239   }
240 
241   /// Compute the cost of specializing function \p F.
242   InstructionCost getSpecializationCost(Function *F) {
243     // Compute the code metrics for the function.
244     SmallPtrSet<const Value *, 32> EphValues;
245     CodeMetrics::collectEphemeralValues(F, &(GetAC)(*F), EphValues);
246     CodeMetrics Metrics;
247     for (BasicBlock &BB : *F)
248       Metrics.analyzeBasicBlock(&BB, (GetTTI)(*F), EphValues);
249 
250     // If the code metrics reveal that we shouldn't duplicate the function, we
251     // shouldn't specialize it. Set the specialization cost to the maximum.
252     if (Metrics.notDuplicatable)
253       return std::numeric_limits<unsigned>::max();
254 
255     // Otherwise, set the specialization cost to be the cost of all the
256     // instructions in the function and penalty for specializing more functions.
257     unsigned Penalty = NbFunctionsSpecialized + 1;
258     return Metrics.NumInsts * InlineConstants::InstrCost * Penalty;
259   }
260 
261   InstructionCost getUserBonus(User *U, llvm::TargetTransformInfo &TTI,
262                                LoopInfo &LI) {
263     auto *I = dyn_cast_or_null<Instruction>(U);
264     // If not an instruction we do not know how to evaluate.
265     // Keep minimum possible cost for now so that it doesnt affect
266     // specialization.
267     if (!I)
268       return std::numeric_limits<unsigned>::min();
269 
270     auto Cost = TTI.getUserCost(U, TargetTransformInfo::TCK_SizeAndLatency);
271 
272     // Traverse recursively if there are more uses.
273     // TODO: Any other instructions to be added here?
274     if (I->mayReadFromMemory() || I->isCast())
275       for (auto *User : I->users())
276         Cost += getUserBonus(User, TTI, LI);
277 
278     // Increase the cost if it is inside the loop.
279     auto LoopDepth = LI.getLoopDepth(I->getParent());
280     Cost *= std::pow((double)AvgLoopIterationCount, LoopDepth);
281     return Cost;
282   }
283 
284   /// Compute a bonus for replacing argument \p A with constant \p C.
285   InstructionCost getSpecializationBonus(Argument *A, Constant *C) {
286     Function *F = A->getParent();
287     DominatorTree DT(*F);
288     LoopInfo LI(DT);
289     auto &TTI = (GetTTI)(*F);
290     LLVM_DEBUG(dbgs() << "FnSpecialization: Analysing bonus for: " << *A
291                       << "\n");
292 
293     InstructionCost TotalCost = 0;
294     for (auto *U : A->users()) {
295       TotalCost += getUserBonus(U, TTI, LI);
296       LLVM_DEBUG(dbgs() << "FnSpecialization: User cost ";
297                  TotalCost.print(dbgs()); dbgs() << " for: " << *U << "\n");
298     }
299 
300     // The below heuristic is only concerned with exposing inlining
301     // opportunities via indirect call promotion. If the argument is not a
302     // function pointer, give up.
303     if (!isa<PointerType>(A->getType()) ||
304         !isa<FunctionType>(A->getType()->getPointerElementType()))
305       return TotalCost;
306 
307     // Since the argument is a function pointer, its incoming constant values
308     // should be functions or constant expressions. The code below attempts to
309     // look through cast expressions to find the function that will be called.
310     Value *CalledValue = C;
311     while (isa<ConstantExpr>(CalledValue) &&
312            cast<ConstantExpr>(CalledValue)->isCast())
313       CalledValue = cast<User>(CalledValue)->getOperand(0);
314     Function *CalledFunction = dyn_cast<Function>(CalledValue);
315     if (!CalledFunction)
316       return TotalCost;
317 
318     // Get TTI for the called function (used for the inline cost).
319     auto &CalleeTTI = (GetTTI)(*CalledFunction);
320 
321     // Look at all the call sites whose called value is the argument.
322     // Specializing the function on the argument would allow these indirect
323     // calls to be promoted to direct calls. If the indirect call promotion
324     // would likely enable the called function to be inlined, specializing is a
325     // good idea.
326     int Bonus = 0;
327     for (User *U : A->users()) {
328       if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
329         continue;
330       auto *CS = cast<CallBase>(U);
331       if (CS->getCalledOperand() != A)
332         continue;
333 
334       // Get the cost of inlining the called function at this call site. Note
335       // that this is only an estimate. The called function may eventually
336       // change in a way that leads to it not being inlined here, even though
337       // inlining looks profitable now. For example, one of its called
338       // functions may be inlined into it, making the called function too large
339       // to be inlined into this call site.
340       //
341       // We apply a boost for performing indirect call promotion by increasing
342       // the default threshold by the threshold for indirect calls.
343       auto Params = getInlineParams();
344       Params.DefaultThreshold += InlineConstants::IndirectCallThreshold;
345       InlineCost IC =
346           getInlineCost(*CS, CalledFunction, Params, CalleeTTI, GetAC, GetTLI);
347 
348       // We clamp the bonus for this call to be between zero and the default
349       // threshold.
350       if (IC.isAlways())
351         Bonus += Params.DefaultThreshold;
352       else if (IC.isVariable() && IC.getCostDelta() > 0)
353         Bonus += IC.getCostDelta();
354     }
355 
356     return TotalCost + Bonus;
357   }
358 
359   /// Determine if we should specialize a function based on the incoming values
360   /// of the given argument.
361   ///
362   /// This function implements the goal-directed heuristic. It determines if
363   /// specializing the function based on the incoming values of argument \p A
364   /// would result in any significant optimization opportunities. If
365   /// optimization opportunities exist, the constant values of \p A on which to
366   /// specialize the function are collected in \p Constants. If the values in
367   /// \p Constants represent the complete set of values that \p A can take on,
368   /// the function will be completely specialized, and the \p IsPartial flag is
369   /// set to false.
370   ///
371   /// \returns true if the function should be specialized on the given
372   /// argument.
373   bool isArgumentInteresting(Argument *A,
374                              SmallVectorImpl<Constant *> &Constants,
375                              bool &IsPartial) {
376     Function *F = A->getParent();
377 
378     // For now, don't attempt to specialize functions based on the values of
379     // composite types.
380     if (!A->getType()->isSingleValueType() || A->user_empty())
381       return false;
382 
383     // If the argument isn't overdefined, there's nothing to do. It should
384     // already be constant.
385     if (!Solver.getLatticeValueFor(A).isOverdefined()) {
386       LLVM_DEBUG(dbgs() << "FnSpecialization: nothing to do, arg is already "
387                         << "constant?\n");
388       return false;
389     }
390 
391     // Collect the constant values that the argument can take on. If the
392     // argument can't take on any constant values, we aren't going to
393     // specialize the function. While it's possible to specialize the function
394     // based on non-constant arguments, there's likely not much benefit to
395     // constant propagation in doing so.
396     //
397     // TODO 1: currently it won't specialize if there are over the threshold of
398     // calls using the same argument, e.g foo(a) x 4 and foo(b) x 1, but it
399     // might be beneficial to take the occurrences into account in the cost
400     // model, so we would need to find the unique constants.
401     //
402     // TODO 2: this currently does not support constants, i.e. integer ranges.
403     //
404     SmallVector<Constant *, 4> PossibleConstants;
405     bool AllConstant = getPossibleConstants(A, PossibleConstants);
406     if (PossibleConstants.empty()) {
407       LLVM_DEBUG(dbgs() << "FnSpecialization: no possible constants found\n");
408       return false;
409     }
410     if (PossibleConstants.size() > MaxConstantsThreshold) {
411       LLVM_DEBUG(dbgs() << "FnSpecialization: number of constants found exceed "
412                         << "the maximum number of constants threshold.\n");
413       return false;
414     }
415 
416     // Determine if it would be profitable to create a specialization of the
417     // function where the argument takes on the given constant value. If so,
418     // add the constant to Constants.
419     auto FnSpecCost = getSpecializationCost(F);
420     LLVM_DEBUG(dbgs() << "FnSpecialization: func specialisation cost: ";
421                FnSpecCost.print(dbgs()); dbgs() << "\n");
422 
423     for (auto *C : PossibleConstants) {
424       LLVM_DEBUG(dbgs() << "FnSpecialization: Constant: " << *C << "\n");
425       if (ForceFunctionSpecialization) {
426         LLVM_DEBUG(dbgs() << "FnSpecialization: Forced!\n");
427         Constants.push_back(C);
428         continue;
429       }
430       if (getSpecializationBonus(A, C) > FnSpecCost) {
431         LLVM_DEBUG(dbgs() << "FnSpecialization: profitable!\n");
432         Constants.push_back(C);
433       } else {
434         LLVM_DEBUG(dbgs() << "FnSpecialization: not profitable\n");
435       }
436     }
437 
438     // None of the constant values the argument can take on were deemed good
439     // candidates on which to specialize the function.
440     if (Constants.empty())
441       return false;
442 
443     // This will be a partial specialization if some of the constants were
444     // rejected due to their profitability.
445     IsPartial = !AllConstant || PossibleConstants.size() != Constants.size();
446 
447     return true;
448   }
449 
450   /// Collect in \p Constants all the constant values that argument \p A can
451   /// take on.
452   ///
453   /// \returns true if all of the values the argument can take on are constant
454   /// (e.g., the argument's parent function cannot be called with an
455   /// overdefined value).
456   bool getPossibleConstants(Argument *A,
457                             SmallVectorImpl<Constant *> &Constants) {
458     Function *F = A->getParent();
459     bool AllConstant = true;
460 
461     // Iterate over all the call sites of the argument's parent function.
462     for (User *U : F->users()) {
463       if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
464         continue;
465       auto &CS = *cast<CallBase>(U);
466 
467       // If the parent of the call site will never be executed, we don't need
468       // to worry about the passed value.
469       if (!Solver.isBlockExecutable(CS.getParent()))
470         continue;
471 
472       auto *V = CS.getArgOperand(A->getArgNo());
473       // TrackValueOfGlobalVariable only tracks scalar global variables.
474       if (auto *GV = dyn_cast<GlobalVariable>(V)) {
475         if (!GV->getValueType()->isSingleValueType()) {
476           return false;
477         }
478       }
479 
480       // Get the lattice value for the value the call site passes to the
481       // argument. If this value is not constant, move on to the next call
482       // site. Additionally, set the AllConstant flag to false.
483       if (V != A && !Solver.getLatticeValueFor(V).isConstant()) {
484         AllConstant = false;
485         continue;
486       }
487 
488       // Add the constant to the set.
489       if (auto *C = dyn_cast<Constant>(CS.getArgOperand(A->getArgNo())))
490         Constants.push_back(C);
491     }
492 
493     // If the argument can only take on constant values, AllConstant will be
494     // true.
495     return AllConstant;
496   }
497 
498   /// Rewrite calls to function \p F to call function \p Clone instead.
499   ///
500   /// This function modifies calls to function \p F whose argument at index \p
501   /// ArgNo is equal to constant \p C. The calls are rewritten to call function
502   /// \p Clone instead.
503   void rewriteCallSites(Function *F, Function *Clone, Argument &Arg,
504                         Constant *C) {
505     unsigned ArgNo = Arg.getArgNo();
506     SmallVector<CallBase *, 4> CallSitesToRewrite;
507     for (auto *U : F->users()) {
508       if (!isa<CallInst>(U) && !isa<InvokeInst>(U))
509         continue;
510       auto &CS = *cast<CallBase>(U);
511       if (!CS.getCalledFunction() || CS.getCalledFunction() != F)
512         continue;
513       CallSitesToRewrite.push_back(&CS);
514     }
515     for (auto *CS : CallSitesToRewrite) {
516       if ((CS->getFunction() == Clone && CS->getArgOperand(ArgNo) == &Arg) ||
517           CS->getArgOperand(ArgNo) == C) {
518         CS->setCalledFunction(Clone);
519         Solver.markOverdefined(CS);
520       }
521     }
522   }
523 };
524 
525 /// Function to clean up the left over intrinsics from SCCP util.
526 static void cleanup(Module &M) {
527   for (Function &F : M) {
528     for (BasicBlock &BB : F) {
529       for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) {
530         Instruction *Inst = &*BI++;
531         if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
532           if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
533             Value *Op = II->getOperand(0);
534             Inst->replaceAllUsesWith(Op);
535             Inst->eraseFromParent();
536           }
537         }
538       }
539     }
540   }
541 }
542 
543 bool llvm::runFunctionSpecialization(
544     Module &M, const DataLayout &DL,
545     std::function<TargetLibraryInfo &(Function &)> GetTLI,
546     std::function<TargetTransformInfo &(Function &)> GetTTI,
547     std::function<AssumptionCache &(Function &)> GetAC,
548     function_ref<AnalysisResultsForFn(Function &)> GetAnalysis) {
549   SCCPSolver Solver(DL, GetTLI, M.getContext());
550   FunctionSpecializer FS(Solver, GetAC, GetTTI, GetTLI);
551   bool Changed = false;
552 
553   // Loop over all functions, marking arguments to those with their addresses
554   // taken or that are external as overdefined.
555   for (Function &F : M) {
556     if (F.isDeclaration())
557       continue;
558     if (F.hasFnAttribute(Attribute::NoDuplicate))
559       continue;
560 
561     LLVM_DEBUG(dbgs() << "\nFnSpecialization: Analysing decl: " << F.getName()
562                       << "\n");
563     Solver.addAnalysis(F, GetAnalysis(F));
564 
565     // Determine if we can track the function's arguments. If so, add the
566     // function to the solver's set of argument-tracked functions.
567     if (canTrackArgumentsInterprocedurally(&F)) {
568       LLVM_DEBUG(dbgs() << "FnSpecialization: Can track arguments\n");
569       Solver.addArgumentTrackedFunction(&F);
570       continue;
571     } else {
572       LLVM_DEBUG(dbgs() << "FnSpecialization: Can't track arguments!\n"
573                         << "FnSpecialization: Doesn't have local linkage, or "
574                         << "has its address taken\n");
575     }
576 
577     // Assume the function is called.
578     Solver.markBlockExecutable(&F.front());
579 
580     // Assume nothing about the incoming arguments.
581     for (Argument &AI : F.args())
582       Solver.markOverdefined(&AI);
583   }
584 
585   // Determine if we can track any of the module's global variables. If so, add
586   // the global variables we can track to the solver's set of tracked global
587   // variables.
588   for (GlobalVariable &G : M.globals()) {
589     G.removeDeadConstantUsers();
590     if (canTrackGlobalVariableInterprocedurally(&G))
591       Solver.trackValueOfGlobalVariable(&G);
592   }
593 
594   // Solve for constants.
595   auto RunSCCPSolver = [&](auto &WorkList) {
596     bool ResolvedUndefs = true;
597 
598     while (ResolvedUndefs) {
599       LLVM_DEBUG(dbgs() << "FnSpecialization: Running solver\n");
600       Solver.solve();
601       LLVM_DEBUG(dbgs() << "FnSpecialization: Resolving undefs\n");
602       ResolvedUndefs = false;
603       for (Function *F : WorkList)
604         if (Solver.resolvedUndefsIn(*F))
605           ResolvedUndefs = true;
606     }
607 
608     for (auto *F : WorkList) {
609       for (BasicBlock &BB : *F) {
610         if (!Solver.isBlockExecutable(&BB))
611           continue;
612         for (auto &I : make_early_inc_range(BB))
613           FS.tryToReplaceWithConstant(&I);
614       }
615     }
616   };
617 
618   auto &TrackedFuncs = Solver.getArgumentTrackedFunctions();
619   SmallVector<Function *, 16> FuncDecls(TrackedFuncs.begin(),
620                                         TrackedFuncs.end());
621 #ifndef NDEBUG
622   LLVM_DEBUG(dbgs() << "FnSpecialization: Worklist fn decls:\n");
623   for (auto *F : FuncDecls)
624     LLVM_DEBUG(dbgs() << "FnSpecialization: *) " << F->getName() << "\n");
625 #endif
626 
627   // Initially resolve the constants in all the argument tracked functions.
628   RunSCCPSolver(FuncDecls);
629 
630   SmallVector<Function *, 2> CurrentSpecializations;
631   unsigned I = 0;
632   while (FuncSpecializationMaxIters != I++ &&
633          FS.specializeFunctions(FuncDecls, CurrentSpecializations)) {
634     // TODO: run the solver here for the specialized functions only if we want
635     // to specialize recursively.
636 
637     CurrentSpecializations.clear();
638     Changed = true;
639   }
640 
641   // Clean up the IR by removing ssa_copy intrinsics.
642   cleanup(M);
643   return Changed;
644 }
645