//===- LazyCallGraph.h - Analysis of a Module's call graph ------*- 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 // //===----------------------------------------------------------------------===// /// \file /// /// Implements a lazy call graph analysis and related passes for the new pass /// manager. /// /// NB: This is *not* a traditional call graph! It is a graph which models both /// the current calls and potential calls. As a consequence there are many /// edges in this call graph that do not correspond to a 'call' or 'invoke' /// instruction. /// /// The primary use cases of this graph analysis is to facilitate iterating /// across the functions of a module in ways that ensure all callees are /// visited prior to a caller (given any SCC constraints), or vice versa. As /// such is it particularly well suited to organizing CGSCC optimizations such /// as inlining, outlining, argument promotion, etc. That is its primary use /// case and motivates the design. It may not be appropriate for other /// purposes. The use graph of functions or some other conservative analysis of /// call instructions may be interesting for optimizations and subsequent /// analyses which don't work in the context of an overly specified /// potential-call-edge graph. /// /// To understand the specific rules and nature of this call graph analysis, /// see the documentation of the \c LazyCallGraph below. /// //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_LAZYCALLGRAPH_H #define LLVM_ANALYSIS_LAZYCALLGRAPH_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <iterator> #include <optional> #include <string> #include <utility> namespace llvm { class Constant; template <class GraphType> struct GraphTraits; class Module; /// A lazily constructed view of the call graph of a module. /// /// With the edges of this graph, the motivating constraint that we are /// attempting to maintain is that function-local optimization, CGSCC-local /// optimizations, and optimizations transforming a pair of functions connected /// by an edge in the graph, do not invalidate a bottom-up traversal of the SCC /// DAG. That is, no optimizations will delete, remove, or add an edge such /// that functions already visited in a bottom-up order of the SCC DAG are no /// longer valid to have visited, or such that functions not yet visited in /// a bottom-up order of the SCC DAG are not required to have already been /// visited. /// /// Within this constraint, the desire is to minimize the merge points of the /// SCC DAG. The greater the fanout of the SCC DAG and the fewer merge points /// in the SCC DAG, the more independence there is in optimizing within it. /// There is a strong desire to enable parallelization of optimizations over /// the call graph, and both limited fanout and merge points will (artificially /// in some cases) limit the scaling of such an effort. /// /// To this end, graph represents both direct and any potential resolution to /// an indirect call edge. Another way to think about it is that it represents /// both the direct call edges and any direct call edges that might be formed /// through static optimizations. Specifically, it considers taking the address /// of a function to be an edge in the call graph because this might be /// forwarded to become a direct call by some subsequent function-local /// optimization. The result is that the graph closely follows the use-def /// edges for functions. Walking "up" the graph can be done by looking at all /// of the uses of a function. /// /// The roots of the call graph are the external functions and functions /// escaped into global variables. Those functions can be called from outside /// of the module or via unknowable means in the IR -- we may not be able to /// form even a potential call edge from a function body which may dynamically /// load the function and call it. /// /// This analysis still requires updates to remain valid after optimizations /// which could potentially change the set of potential callees. The /// constraints it operates under only make the traversal order remain valid. /// /// The entire analysis must be re-computed if full interprocedural /// optimizations run at any point. For example, globalopt completely /// invalidates the information in this analysis. /// /// FIXME: This class is named LazyCallGraph in a lame attempt to distinguish /// it from the existing CallGraph. At some point, it is expected that this /// will be the only call graph and it will be renamed accordingly. class LazyCallGraph { … }; inline LazyCallGraph::Edge::Edge() = default; inline LazyCallGraph::Edge::Edge(Node &N, Kind K) : … { … } operator bool() inline LazyCallGraph::Edge::Kind LazyCallGraph::Edge::getKind() const { … } inline bool LazyCallGraph::Edge::isCall() const { … } inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode() const { … } inline Function &LazyCallGraph::Edge::getFunction() const { … } // Provide GraphTraits specializations for call graphs. template <> struct GraphTraits<LazyCallGraph::Node *> { … }; template <> struct GraphTraits<LazyCallGraph *> { … }; /// An analysis pass which computes the call graph for a module. class LazyCallGraphAnalysis : public AnalysisInfoMixin<LazyCallGraphAnalysis> { … }; /// A pass which prints the call graph to a \c raw_ostream. /// /// This is primarily useful for testing the analysis. class LazyCallGraphPrinterPass : public PassInfoMixin<LazyCallGraphPrinterPass> { … }; /// A pass which prints the call graph as a DOT file to a \c raw_ostream. /// /// This is primarily useful for visualization purposes. class LazyCallGraphDOTPrinterPass : public PassInfoMixin<LazyCallGraphDOTPrinterPass> { … }; } // end namespace llvm #endif // LLVM_ANALYSIS_LAZYCALLGRAPH_H