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