@@ -23,6 +23,9 @@ const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat";
23
23
void BoltAddressTranslation::writeEntriesForBB (MapTy &Map,
24
24
const BinaryBasicBlock &BB,
25
25
uint64_t FuncAddress) {
26
+ uint64_t HotFuncAddress = ColdPartSource.count (FuncAddress)
27
+ ? ColdPartSource[FuncAddress]
28
+ : FuncAddress;
26
29
const uint64_t BBOutputOffset =
27
30
BB.getOutputAddressRange ().first - FuncAddress;
28
31
const uint32_t BBInputOffset = BB.getInputOffset ();
@@ -39,6 +42,8 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
39
42
LLVM_DEBUG (dbgs () << " BB " << BB.getName () << " \n " );
40
43
LLVM_DEBUG (dbgs () << " Key: " << Twine::utohexstr (BBOutputOffset)
41
44
<< " Val: " << Twine::utohexstr (BBInputOffset) << " \n " );
45
+ LLVM_DEBUG (dbgs () << formatv (" Hash: {0:x}\n " ,
46
+ getBBHash (HotFuncAddress, BBInputOffset)));
42
47
// In case of conflicts (same Key mapping to different Vals), the last
43
48
// update takes precedence. Of course it is not ideal to have conflicts and
44
49
// those happen when we have an empty BB that either contained only
@@ -72,20 +77,28 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
72
77
LLVM_DEBUG (dbgs () << " BOLT-DEBUG: Writing BOLT Address Translation Tables\n " );
73
78
for (auto &BFI : BC.getBinaryFunctions ()) {
74
79
const BinaryFunction &Function = BFI.second ;
80
+ const uint64_t InputAddress = Function.getAddress ();
81
+ const uint64_t OutputAddress = Function.getOutputAddress ();
75
82
// We don't need a translation table if the body of the function hasn't
76
83
// changed
77
84
if (Function.isIgnored () || (!BC.HasRelocations && !Function.isSimple ()))
78
85
continue ;
79
86
87
+ // TBD: handle BAT functions w/multiple entry points.
88
+ if (Function.isMultiEntry ())
89
+ continue ;
90
+
80
91
LLVM_DEBUG (dbgs () << " Function name: " << Function.getPrintName () << " \n " );
81
92
LLVM_DEBUG (dbgs () << " Address reference: 0x"
82
93
<< Twine::utohexstr (Function.getOutputAddress ()) << " \n " );
94
+ LLVM_DEBUG (dbgs () << formatv (" Hash: {0:x}\n " , getBFHash (OutputAddress)));
83
95
84
96
MapTy Map;
85
97
for (const BinaryBasicBlock *const BB :
86
98
Function.getLayout ().getMainFragment ())
87
99
writeEntriesForBB (Map, *BB, Function.getOutputAddress ());
88
100
Maps.emplace (Function.getOutputAddress (), std::move (Map));
101
+ ReverseMap.emplace (OutputAddress, InputAddress);
89
102
90
103
if (!Function.isSplit ())
91
104
continue ;
@@ -94,12 +107,12 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
94
107
LLVM_DEBUG (dbgs () << " Cold part\n " );
95
108
for (const FunctionFragment &FF :
96
109
Function.getLayout ().getSplitFragments ()) {
110
+ ColdPartSource.emplace (FF.getAddress (), Function.getOutputAddress ());
97
111
Map.clear ();
98
112
for (const BinaryBasicBlock *const BB : FF)
99
113
writeEntriesForBB (Map, *BB, FF.getAddress ());
100
114
101
115
Maps.emplace (FF.getAddress (), std::move (Map));
102
- ColdPartSource.emplace (FF.getAddress (), Function.getOutputAddress ());
103
116
}
104
117
}
105
118
@@ -109,6 +122,11 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
109
122
writeMaps</* Cold=*/ true >(Maps, PrevAddress, OS);
110
123
111
124
BC.outs () << " BOLT-INFO: Wrote " << Maps.size () << " BAT maps\n " ;
125
+ const uint64_t NumBBHashes = std::accumulate (
126
+ FuncHashes.begin (), FuncHashes.end (), 0ull ,
127
+ [](size_t Acc, const auto &B) { return Acc + B.second .second .size (); });
128
+ BC.outs () << " BOLT-INFO: Wrote " << FuncHashes.size () << " function and "
129
+ << NumBBHashes << " basic block hashes\n " ;
112
130
}
113
131
114
132
APInt BoltAddressTranslation::calculateBranchEntriesBitMask (MapTy &Map,
@@ -155,6 +173,11 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
155
173
// Only process cold fragments in cold mode, and vice versa.
156
174
if (Cold != ColdPartSource.count (Address))
157
175
continue ;
176
+ // NB: here we use the input address because hashes are saved early (in
177
+ // `saveMetadata`) before output addresses are assigned.
178
+ const uint64_t HotInputAddress =
179
+ ReverseMap[Cold ? ColdPartSource[Address] : Address];
180
+ std::pair<size_t , BBHashMap> &FuncHashPair = FuncHashes[HotInputAddress];
158
181
MapTy &Map = MapEntry.second ;
159
182
const uint32_t NumEntries = Map.size ();
160
183
LLVM_DEBUG (dbgs () << " Writing " << NumEntries << " entries for 0x"
@@ -166,6 +189,10 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
166
189
std::distance (ColdPartSource.begin (), ColdPartSource.find (Address));
167
190
encodeULEB128 (HotIndex - PrevIndex, OS);
168
191
PrevIndex = HotIndex;
192
+ } else {
193
+ // Function hash
194
+ LLVM_DEBUG (dbgs () << " Hash: " << formatv (" {0:x}\n " , FuncHashPair.first ));
195
+ OS.write (reinterpret_cast <char *>(&FuncHashPair.first ), 8 );
169
196
}
170
197
encodeULEB128 (NumEntries, OS);
171
198
// For hot fragments only: encode the number of equal offsets
@@ -197,6 +224,13 @@ void BoltAddressTranslation::writeMaps(std::map<uint64_t, MapTy> &Maps,
197
224
if (Index++ >= EqualElems)
198
225
encodeSLEB128 (KeyVal.second - InOffset, OS);
199
226
InOffset = KeyVal.second ; // Keeping InOffset as if BRANCHENTRY is encoded
227
+ if ((InOffset & BRANCHENTRY) == 0 ) {
228
+ // Basic block hash
229
+ size_t BBHash = FuncHashPair.second [InOffset >> 1 ];
230
+ OS.write (reinterpret_cast <char *>(&BBHash), 8 );
231
+ LLVM_DEBUG (dbgs () << formatv (" {0:x} -> {1:x} {2:x}\n " , KeyVal.first ,
232
+ InOffset >> 1 , BBHash));
233
+ }
200
234
}
201
235
}
202
236
}
@@ -239,12 +273,18 @@ void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
239
273
size_t HotIndex = 0 ;
240
274
for (uint32_t I = 0 ; I < NumFunctions; ++I) {
241
275
const uint64_t Address = PrevAddress + DE.getULEB128 (&Offset, &Err);
276
+ uint64_t HotAddress = Cold ? 0 : Address;
242
277
PrevAddress = Address;
243
278
if (Cold) {
244
279
HotIndex += DE.getULEB128 (&Offset, &Err);
245
- ColdPartSource.emplace (Address, HotFuncs[HotIndex]);
280
+ HotAddress = HotFuncs[HotIndex];
281
+ ColdPartSource.emplace (Address, HotAddress);
246
282
} else {
247
283
HotFuncs.push_back (Address);
284
+ // Function hash
285
+ const size_t FuncHash = DE.getU64 (&Offset, &Err);
286
+ FuncHashes[Address].first = FuncHash;
287
+ LLVM_DEBUG (dbgs () << formatv (" {0:x}: hash {1:x}\n " , Address, FuncHash));
248
288
}
249
289
const uint32_t NumEntries = DE.getULEB128 (&Offset, &Err);
250
290
// Equal offsets, hot fragments only.
@@ -288,12 +328,22 @@ void BoltAddressTranslation::parseMaps(std::vector<uint64_t> &HotFuncs,
288
328
InputOffset += InputDelta;
289
329
}
290
330
Map.insert (std::pair<uint32_t , uint32_t >(OutputOffset, InputOffset));
291
- LLVM_DEBUG (
292
- dbgs () << formatv (" {0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}\n " ,
293
- OutputOffset, InputOffset, OutputDelta,
294
- getULEB128Size (OutputDelta), InputDelta,
295
- (J < EqualElems) ? 0 : getSLEB128Size (InputDelta),
296
- OutputAddress));
331
+ size_t BBHash = 0 ;
332
+ const bool IsBranchEntry = InputOffset & BRANCHENTRY;
333
+ if (!IsBranchEntry) {
334
+ BBHash = DE.getU64 (&Offset, &Err);
335
+ // Map basic block hash to hot fragment by input offset
336
+ FuncHashes[HotAddress].second .emplace (InputOffset >> 1 , BBHash);
337
+ }
338
+ LLVM_DEBUG ({
339
+ dbgs () << formatv (
340
+ " {0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}" , OutputOffset,
341
+ InputOffset, OutputDelta, getULEB128Size (OutputDelta), InputDelta,
342
+ (J < EqualElems) ? 0 : getSLEB128Size (InputDelta), OutputAddress);
343
+ if (BBHash)
344
+ dbgs () << formatv (" {0:x}" , BBHash);
345
+ dbgs () << ' \n ' ;
346
+ });
297
347
}
298
348
Maps.insert (std::pair<uint64_t , MapTy>(Address, Map));
299
349
}
@@ -303,7 +353,12 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
303
353
const size_t NumTables = Maps.size ();
304
354
OS << " BAT tables for " << NumTables << " functions:\n " ;
305
355
for (const auto &MapEntry : Maps) {
306
- OS << " Function Address: 0x" << Twine::utohexstr (MapEntry.first ) << " \n " ;
356
+ const uint64_t Address = MapEntry.first ;
357
+ const uint64_t HotAddress = fetchParentAddress (Address);
358
+ OS << " Function Address: 0x" << Twine::utohexstr (Address);
359
+ if (HotAddress == 0 )
360
+ OS << formatv (" , hash: {0:x}" , getBFHash (Address));
361
+ OS << " \n " ;
307
362
OS << " BB mappings:\n " ;
308
363
for (const auto &Entry : MapEntry.second ) {
309
364
const bool IsBranch = Entry.second & BRANCHENTRY;
@@ -312,6 +367,9 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
312
367
<< " 0x" << Twine::utohexstr (Val);
313
368
if (IsBranch)
314
369
OS << " (branch)" ;
370
+ else
371
+ OS << formatv (" hash: {0:x}" ,
372
+ getBBHash (HotAddress ? HotAddress : Address, Val));
315
373
OS << " \n " ;
316
374
}
317
375
OS << " \n " ;
@@ -439,5 +497,15 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
439
497
BB.getHash ());
440
498
}
441
499
}
500
+
501
+ size_t BoltAddressTranslation::getBBHash (uint64_t FuncOutputAddress,
502
+ uint32_t BBInputOffset) const {
503
+ return FuncHashes.at (FuncOutputAddress).second .at (BBInputOffset);
504
+ }
505
+
506
+ size_t BoltAddressTranslation::getBFHash (uint64_t OutputAddress) const {
507
+ return FuncHashes.at (OutputAddress).first ;
508
+ }
509
+
442
510
} // namespace bolt
443
511
} // namespace llvm
0 commit comments