@@ -89,6 +89,13 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
89
89
BinaryFunctionCallGraph Cg;
90
90
static constexpr auto COUNT_NO_PROFILE = BinaryBasicBlock::COUNT_NO_PROFILE;
91
91
92
+ // Compute function size
93
+ auto functionSize = [&](const BinaryFunction *Function) {
94
+ return UseFunctionHotSize && Function->isSplit ()
95
+ ? Function->estimateHotSize (UseSplitHotSize)
96
+ : Function->estimateSize ();
97
+ };
98
+
92
99
// Add call graph nodes.
93
100
auto lookupNode = [&](BinaryFunction *Function) {
94
101
const auto Id = Cg.maybeGetNodeId (Function);
@@ -97,9 +104,7 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
97
104
// because emitFunctions will emit the hot part first in the order that is
98
105
// computed by ReorderFunctions. The cold part will be emitted with the
99
106
// rest of the cold functions and code.
100
- const auto Size = UseFunctionHotSize && Function->isSplit ()
101
- ? Function->estimateHotSize (UseSplitHotSize)
102
- : Function->estimateSize ();
107
+ const auto Size = functionSize (Function);
103
108
// NOTE: for functions without a profile, we set the number of samples
104
109
// to zero. This will keep these functions from appearing in the hot
105
110
// section. This is a little weird because we wouldn't be trying to
@@ -125,14 +130,14 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
125
130
for (auto &It : BFs) {
126
131
auto *Function = &It.second ;
127
132
128
- if (Filter (*Function)) {
133
+ if (Filter (*Function)) {
129
134
continue ;
130
135
}
131
136
132
137
const auto *BranchData = Function->getBranchData ();
133
138
const auto SrcId = lookupNode (Function);
134
- uint64_t Offset = Function-> getAddress ();
135
- uint64_t LastInstSize = 0 ;
139
+ // Offset of the current basic block from the beginning of the function
140
+ uint64_t Offset = 0 ;
136
141
137
142
auto recordCall = [&](const MCSymbol *DestSymbol, const uint64_t Count) {
138
143
if (auto *DstFunc =
@@ -145,18 +150,19 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
145
150
return false ;
146
151
}
147
152
const auto DstId = lookupNode (DstFunc);
148
- const auto AvgDelta = UseEdgeCounts ? 0 : Offset - DstFunc->getAddress ();
149
153
const bool IsValidCount = Count != COUNT_NO_PROFILE;
150
154
const auto AdjCount = UseEdgeCounts && IsValidCount ? Count : 1 ;
151
- if (!IsValidCount) ++NoProfileCallsites;
152
- Cg.incArcWeight (SrcId, DstId, AdjCount, AvgDelta);
155
+ if (!IsValidCount)
156
+ ++NoProfileCallsites;
157
+ Cg.incArcWeight (SrcId, DstId, AdjCount, Offset);
153
158
DEBUG (
154
159
if (opts::Verbosity > 1 ) {
155
160
dbgs () << " BOLT-DEBUG: buildCallGraph: call " << *Function
156
161
<< " -> " << *DstFunc << " @ " << Offset << " \n " ;
157
162
});
158
163
return true ;
159
164
}
165
+
160
166
return false ;
161
167
};
162
168
@@ -209,8 +215,14 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
209
215
DEBUG (dbgs () << " BOLT-DEBUG: buildCallGraph: Falling back to perf data"
210
216
<< " for " << *Function << " \n " );
211
217
++NumFallbacks;
218
+ const auto Size = functionSize (Function);
212
219
for (const auto &BI : BranchData->Data ) {
213
- Offset = Function->getAddress () + BI.From .Offset ;
220
+ Offset = BI.From .Offset ;
221
+ // The computed offset may exceed the hot part of the function; hence,
222
+ // bound it the size
223
+ if (Offset > Size)
224
+ Offset = Size;
225
+
214
226
const auto CI = getCallInfoFromBranchData (BI, true );
215
227
if (!CI.first && CI.second == COUNT_NO_PROFILE) // probably a branch
216
228
continue ;
@@ -225,30 +237,38 @@ BinaryFunctionCallGraph buildCallGraph(BinaryContext &BC,
225
237
if (BB->isCold () && !IncludeColdCalls)
226
238
continue ;
227
239
228
- for (auto &Inst : *BB) {
229
- if (!UseEdgeCounts) {
230
- Offset += LastInstSize;
231
- LastInstSize = BC.computeCodeSize (&Inst, &Inst + 1 );
232
- }
240
+ // Determine whether the block is included in Function's (hot) size
241
+ // See BinaryFunction::estimateHotSize
242
+ bool BBIncludedInFunctionSize = false ;
243
+ if (UseFunctionHotSize && Function->isSplit ()) {
244
+ if (UseSplitHotSize)
245
+ BBIncludedInFunctionSize = !BB->isCold ();
246
+ else
247
+ BBIncludedInFunctionSize = BB->getKnownExecutionCount () != 0 ;
248
+ } else {
249
+ BBIncludedInFunctionSize = true ;
250
+ }
233
251
252
+ for (auto &Inst : *BB) {
234
253
// Find call instructions and extract target symbols from each one.
235
- if (!BC.MIA ->isCall (Inst))
236
- continue ;
237
-
238
- const auto CallInfo = getCallInfo (BB, Inst);
254
+ if (BC.MIA ->isCall (Inst)) {
255
+ const auto CallInfo = getCallInfo (BB, Inst);
239
256
240
- if (CallInfo.empty ()) {
241
- ++TotalCallsites;
242
- ++NotProcessed;
243
- continue ;
244
- }
245
-
246
- for (const auto &CI : CallInfo) {
247
- ++TotalCallsites;
248
- if (!recordCall (CI.first , CI.second )) {
257
+ if (!CallInfo.empty ()) {
258
+ for (const auto &CI : CallInfo) {
259
+ ++TotalCallsites;
260
+ if (!recordCall (CI.first , CI.second ))
261
+ ++NotProcessed;
262
+ }
263
+ } else {
264
+ ++TotalCallsites;
249
265
++NotProcessed;
250
266
}
251
267
}
268
+ // Increase Offset if needed
269
+ if (BBIncludedInFunctionSize) {
270
+ Offset += BC.computeCodeSize (&Inst, &Inst + 1 );
271
+ }
252
272
}
253
273
}
254
274
}
0 commit comments