//===- FunctionSpecialization.h - Function Specialization -----------------===// // // 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 // //===----------------------------------------------------------------------===// // // Overview: // --------- // Function Specialization is a transformation which propagates the constant // parameters of a function call from the caller to the callee. It is part of // the Inter-Procedural Sparse Conditional Constant Propagation (IPSCCP) pass. // The transformation runs iteratively a number of times which is controlled // by the option `funcspec-max-iters`. Running it multiple times is needed // for specializing recursive functions, but also exposes new opportunities // arising from specializations which return constant values or contain calls // which can be specialized. // // Function Specialization supports propagating constant parameters like // function pointers, literal constants and addresses of global variables. // By propagating function pointers, indirect calls become direct calls. This // exposes inlining opportunities which we would have otherwise missed. That's // why function specialization is run before the inliner in the optimization // pipeline; that is by design. // // Cost Model: // ----------- // The cost model facilitates a utility for estimating the specialization bonus // from propagating a constant argument. This is the InstCostVisitor, a class // that inherits from the InstVisitor. The bonus itself is expressed as codesize // and latency savings. Codesize savings means the amount of code that becomes // dead in the specialization from propagating the constant, whereas latency // savings represents the cycles we are saving from replacing instructions with // constant values. The InstCostVisitor overrides a set of `visit*` methods to // be able to handle different types of instructions. These attempt to constant- // fold the instruction in which case a constant is returned and propagated // further. // // Function pointers are not handled by the InstCostVisitor. They are treated // separately as they could expose inlining opportunities via indirect call // promotion. The inlining bonus contributes to the total specialization score. // // For a specialization to be profitable its bonus needs to exceed a minimum // threshold. There are three options for controlling the threshold which are // expressed as percentages of the original function size: // * funcspec-min-codesize-savings // * funcspec-min-latency-savings // * funcspec-min-inlining-bonus // There's also an option for controlling the codesize growth from recursive // specializations. That is `funcspec-max-codesize-growth`. // // Once we have all the potential specializations with their score we need to // choose the best ones, which fit in the module specialization budget. That // is controlled by the option `funcspec-max-clones`. To find the best `NSpec` // specializations we use a max-heap. For more details refer to D139346. // // Ideas: // ------ // - With a function specialization attribute for arguments, we could have // a direct way to steer function specialization, avoiding the cost-model, // and thus control compile-times / code-size. // // - Perhaps a post-inlining function specialization pass could be more // aggressive on literal constants. // // References: // ----------- // 2021 LLVM Dev Mtg “Introducing function specialisation, and can we enable // it by default?”, https://www.youtube.com/watch?v=zJiCjeXgV5Q // //===----------------------------------------------------------------------===// #ifndef LLVM_TRANSFORMS_IPO_FUNCTIONSPECIALIZATION_H #define LLVM_TRANSFORMS_IPO_FUNCTIONSPECIALIZATION_H #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/InstVisitor.h" #include "llvm/Transforms/Scalar/SCCP.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/SCCPSolver.h" #include "llvm/Transforms/Utils/SizeOpts.h" namespace llvm { // Map of potential specializations for each function. The FunctionSpecializer // keeps the discovered specialisation opportunities for the module in a single // vector, where the specialisations of each function form a contiguous range. // This map's value is the beginning and the end of that range. SpecMap; // Just a shorter abbreviation to improve indentation. Cost; // Map of known constants found during the specialization bonus estimation. ConstMap; // Specialization signature, used to uniquely designate a specialization within // a function. struct SpecSig { … }; // Specialization instance. struct Spec { … }; struct Bonus { … }; class InstCostVisitor : public InstVisitor<InstCostVisitor, Constant *> { … }; class FunctionSpecializer { … }; } // namespace llvm #endif // LLVM_TRANSFORMS_IPO_FUNCTIONSPECIALIZATION_H