1 //===- bolt/Core/CallGraph.cpp ------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the CallGraph class.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Core/CallGraph.h"
15 #define DEBUG_TYPE "callgraph"
17 #if defined(__x86_64__) && !defined(_MSC_VER)
18 #if (!defined USE_SSECRC)
25 static LLVM_ATTRIBUTE_UNUSED
inline size_t hash_int64_fallback(int64_t k
) {
26 uint64_t key
= (unsigned long long)k
;
27 // "64 bit Mix Functions", from Thomas Wang's "Integer Hash Function."
28 // http://www.concentric.net/~ttwang/tech/inthash.htm
29 key
= (~key
) + (key
<< 21); // key = (key << 21) - key - 1;
30 key
= key
^ (key
>> 24);
31 key
= (key
+ (key
<< 3)) + (key
<< 8); // key * 265
32 key
= key
^ (key
>> 14);
33 key
= (key
+ (key
<< 2)) + (key
<< 4); // key * 21
34 key
= key
^ (key
>> 28);
35 return static_cast<size_t>(static_cast<uint32_t>(key
));
38 static LLVM_ATTRIBUTE_UNUSED
inline size_t hash_int64(int64_t k
) {
39 #if defined(USE_SSECRC) && defined(__SSE4_2__)
41 __asm("crc32q %1, %0\n" : "+r"(h
) : "rm"(k
));
44 return hash_int64_fallback(k
);
48 static inline size_t hash_int64_pair(int64_t k1
, int64_t k2
) {
49 #if defined(USE_SSECRC) && defined(__SSE4_2__)
50 // crc32 is commutative, so we need to perturb k1 so that (k1, k2) hashes
51 // differently from (k2, k1).
53 __asm("crc32q %1, %0\n" : "+r"(k1
) : "rm"(k2
));
56 return (hash_int64(k1
) << 1) ^ hash_int64(k2
);
63 int64_t CallGraph::Arc::Hash::operator()(const Arc
&Arc
) const {
65 std::hash
<int64_t> Hasher
;
66 return hashCombine(Hasher(Arc
.src()), Arc
.dst());
68 return hash_int64_pair(int64_t(Arc
.src()), int64_t(Arc
.dst()));
72 CallGraph::NodeId
CallGraph::addNode(uint32_t Size
, uint64_t Samples
) {
73 NodeId Id
= Nodes
.size();
74 Nodes
.emplace_back(Size
, Samples
);
78 const CallGraph::Arc
&CallGraph::incArcWeight(NodeId Src
, NodeId Dst
, double W
,
80 assert(Offset
<= size(Src
) && "Call offset exceeds function size");
82 std::pair
<ArcIterator
, bool> Res
= Arcs
.emplace(Src
, Dst
, W
);
84 Res
.first
->Weight
+= W
;
85 Res
.first
->AvgCallOffset
+= Offset
* W
;
88 Res
.first
->AvgCallOffset
= Offset
* W
;
89 Nodes
[Src
].Succs
.push_back(Dst
);
90 Nodes
[Dst
].Preds
.push_back(Src
);
94 void CallGraph::normalizeArcWeights() {
95 for (NodeId FuncId
= 0; FuncId
< numNodes(); ++FuncId
) {
96 const Node
&Func
= getNode(FuncId
);
97 for (NodeId Caller
: Func
.predecessors()) {
98 ArcIterator Arc
= findArc(Caller
, FuncId
);
99 Arc
->NormalizedWeight
= Arc
->weight() / Func
.samples();
100 if (Arc
->weight() > 0)
101 Arc
->AvgCallOffset
/= Arc
->weight();
102 assert(Arc
->AvgCallOffset
<= size(Caller
) &&
103 "Avg call offset exceeds function size");
108 void CallGraph::adjustArcWeights() {
109 for (NodeId FuncId
= 0; FuncId
< numNodes(); ++FuncId
) {
110 const Node
&Func
= getNode(FuncId
);
111 uint64_t InWeight
= 0;
112 for (NodeId Caller
: Func
.predecessors()) {
113 ArcIterator Arc
= findArc(Caller
, FuncId
);
114 InWeight
+= (uint64_t)Arc
->weight();
116 if (Func
.samples() < InWeight
)
117 setSamples(FuncId
, InWeight
);