xref: /llvm-project/bolt/lib/Core/CallGraph.cpp (revision 2430a354bfb9e8c08e0dd5f294012b40afb75ce0)
1*2430a354Sshaw young //===- bolt/Core/CallGraph.cpp ------------------------------------------===//
2*2430a354Sshaw young //
3*2430a354Sshaw young // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2430a354Sshaw young // See https://llvm.org/LICENSE.txt for license information.
5*2430a354Sshaw young // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*2430a354Sshaw young //
7*2430a354Sshaw young //===----------------------------------------------------------------------===//
8*2430a354Sshaw young //
9*2430a354Sshaw young // This file implements the CallGraph class.
10*2430a354Sshaw young //
11*2430a354Sshaw young //===----------------------------------------------------------------------===//
12*2430a354Sshaw young 
13*2430a354Sshaw young #include "bolt/Core/CallGraph.h"
14*2430a354Sshaw young 
15*2430a354Sshaw young #define DEBUG_TYPE "callgraph"
16*2430a354Sshaw young 
17*2430a354Sshaw young #if defined(__x86_64__) && !defined(_MSC_VER)
18*2430a354Sshaw young #if (!defined USE_SSECRC)
19*2430a354Sshaw young #define USE_SSECRC
20*2430a354Sshaw young #endif
21*2430a354Sshaw young #else
22*2430a354Sshaw young #undef USE_SSECRC
23*2430a354Sshaw young #endif
24*2430a354Sshaw young 
hash_int64_fallback(int64_t k)25*2430a354Sshaw young static LLVM_ATTRIBUTE_UNUSED inline size_t hash_int64_fallback(int64_t k) {
26*2430a354Sshaw young   uint64_t key = (unsigned long long)k;
27*2430a354Sshaw young   // "64 bit Mix Functions", from Thomas Wang's "Integer Hash Function."
28*2430a354Sshaw young   // http://www.concentric.net/~ttwang/tech/inthash.htm
29*2430a354Sshaw young   key = (~key) + (key << 21); // key = (key << 21) - key - 1;
30*2430a354Sshaw young   key = key ^ (key >> 24);
31*2430a354Sshaw young   key = (key + (key << 3)) + (key << 8); // key * 265
32*2430a354Sshaw young   key = key ^ (key >> 14);
33*2430a354Sshaw young   key = (key + (key << 2)) + (key << 4); // key * 21
34*2430a354Sshaw young   key = key ^ (key >> 28);
35*2430a354Sshaw young   return static_cast<size_t>(static_cast<uint32_t>(key));
36*2430a354Sshaw young }
37*2430a354Sshaw young 
hash_int64(int64_t k)38*2430a354Sshaw young static LLVM_ATTRIBUTE_UNUSED inline size_t hash_int64(int64_t k) {
39*2430a354Sshaw young #if defined(USE_SSECRC) && defined(__SSE4_2__)
40*2430a354Sshaw young   size_t h = 0;
41*2430a354Sshaw young   __asm("crc32q %1, %0\n" : "+r"(h) : "rm"(k));
42*2430a354Sshaw young   return h;
43*2430a354Sshaw young #else
44*2430a354Sshaw young   return hash_int64_fallback(k);
45*2430a354Sshaw young #endif
46*2430a354Sshaw young }
47*2430a354Sshaw young 
hash_int64_pair(int64_t k1,int64_t k2)48*2430a354Sshaw young static inline size_t hash_int64_pair(int64_t k1, int64_t k2) {
49*2430a354Sshaw young #if defined(USE_SSECRC) && defined(__SSE4_2__)
50*2430a354Sshaw young   // crc32 is commutative, so we need to perturb k1 so that (k1, k2) hashes
51*2430a354Sshaw young   // differently from (k2, k1).
52*2430a354Sshaw young   k1 += k1;
53*2430a354Sshaw young   __asm("crc32q %1, %0\n" : "+r"(k1) : "rm"(k2));
54*2430a354Sshaw young   return k1;
55*2430a354Sshaw young #else
56*2430a354Sshaw young   return (hash_int64(k1) << 1) ^ hash_int64(k2);
57*2430a354Sshaw young #endif
58*2430a354Sshaw young }
59*2430a354Sshaw young 
60*2430a354Sshaw young namespace llvm {
61*2430a354Sshaw young namespace bolt {
62*2430a354Sshaw young 
operator ()(const Arc & Arc) const63*2430a354Sshaw young int64_t CallGraph::Arc::Hash::operator()(const Arc &Arc) const {
64*2430a354Sshaw young #ifdef USE_STD_HASH
65*2430a354Sshaw young   std::hash<int64_t> Hasher;
66*2430a354Sshaw young   return hashCombine(Hasher(Arc.src()), Arc.dst());
67*2430a354Sshaw young #else
68*2430a354Sshaw young   return hash_int64_pair(int64_t(Arc.src()), int64_t(Arc.dst()));
69*2430a354Sshaw young #endif
70*2430a354Sshaw young }
71*2430a354Sshaw young 
addNode(uint32_t Size,uint64_t Samples)72*2430a354Sshaw young CallGraph::NodeId CallGraph::addNode(uint32_t Size, uint64_t Samples) {
73*2430a354Sshaw young   NodeId Id = Nodes.size();
74*2430a354Sshaw young   Nodes.emplace_back(Size, Samples);
75*2430a354Sshaw young   return Id;
76*2430a354Sshaw young }
77*2430a354Sshaw young 
incArcWeight(NodeId Src,NodeId Dst,double W,double Offset)78*2430a354Sshaw young const CallGraph::Arc &CallGraph::incArcWeight(NodeId Src, NodeId Dst, double W,
79*2430a354Sshaw young                                               double Offset) {
80*2430a354Sshaw young   assert(Offset <= size(Src) && "Call offset exceeds function size");
81*2430a354Sshaw young 
82*2430a354Sshaw young   std::pair<ArcIterator, bool> Res = Arcs.emplace(Src, Dst, W);
83*2430a354Sshaw young   if (!Res.second) {
84*2430a354Sshaw young     Res.first->Weight += W;
85*2430a354Sshaw young     Res.first->AvgCallOffset += Offset * W;
86*2430a354Sshaw young     return *Res.first;
87*2430a354Sshaw young   }
88*2430a354Sshaw young   Res.first->AvgCallOffset = Offset * W;
89*2430a354Sshaw young   Nodes[Src].Succs.push_back(Dst);
90*2430a354Sshaw young   Nodes[Dst].Preds.push_back(Src);
91*2430a354Sshaw young   return *Res.first;
92*2430a354Sshaw young }
93*2430a354Sshaw young 
normalizeArcWeights()94*2430a354Sshaw young void CallGraph::normalizeArcWeights() {
95*2430a354Sshaw young   for (NodeId FuncId = 0; FuncId < numNodes(); ++FuncId) {
96*2430a354Sshaw young     const Node &Func = getNode(FuncId);
97*2430a354Sshaw young     for (NodeId Caller : Func.predecessors()) {
98*2430a354Sshaw young       ArcIterator Arc = findArc(Caller, FuncId);
99*2430a354Sshaw young       Arc->NormalizedWeight = Arc->weight() / Func.samples();
100*2430a354Sshaw young       if (Arc->weight() > 0)
101*2430a354Sshaw young         Arc->AvgCallOffset /= Arc->weight();
102*2430a354Sshaw young       assert(Arc->AvgCallOffset <= size(Caller) &&
103*2430a354Sshaw young              "Avg call offset exceeds function size");
104*2430a354Sshaw young     }
105*2430a354Sshaw young   }
106*2430a354Sshaw young }
107*2430a354Sshaw young 
adjustArcWeights()108*2430a354Sshaw young void CallGraph::adjustArcWeights() {
109*2430a354Sshaw young   for (NodeId FuncId = 0; FuncId < numNodes(); ++FuncId) {
110*2430a354Sshaw young     const Node &Func = getNode(FuncId);
111*2430a354Sshaw young     uint64_t InWeight = 0;
112*2430a354Sshaw young     for (NodeId Caller : Func.predecessors()) {
113*2430a354Sshaw young       ArcIterator Arc = findArc(Caller, FuncId);
114*2430a354Sshaw young       InWeight += (uint64_t)Arc->weight();
115*2430a354Sshaw young     }
116*2430a354Sshaw young     if (Func.samples() < InWeight)
117*2430a354Sshaw young       setSamples(FuncId, InWeight);
118*2430a354Sshaw young   }
119*2430a354Sshaw young }
120*2430a354Sshaw young 
121*2430a354Sshaw young } // namespace bolt
122*2430a354Sshaw young } // namespace llvm
123