8
8
9
9
#include " bolt/Profile/BoltAddressTranslation.h"
10
10
#include " bolt/Core/BinaryFunction.h"
11
- #include " llvm/Support/DataExtractor.h"
12
11
#include " llvm/Support/Errc.h"
12
+ #include " llvm/Support/Error.h"
13
+ #include " llvm/Support/LEB128.h"
13
14
14
15
#define DEBUG_TYPE " bolt-bat"
15
16
@@ -44,7 +45,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
44
45
// and this deleted block will both share the same output address (the same
45
46
// key), and we need to map back. We choose here to privilege the successor by
46
47
// allowing it to overwrite the previously inserted key in the map.
47
- Map[BBOutputOffset] = BBInputOffset;
48
+ Map[BBOutputOffset] = BBInputOffset << 1 ;
48
49
49
50
const auto &IOAddressMap =
50
51
BB.getFunction ()->getBinaryContext ().getIOAddressMap ();
@@ -61,8 +62,8 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map,
61
62
62
63
LLVM_DEBUG (dbgs () << " Key: " << Twine::utohexstr (OutputOffset) << " Val: "
63
64
<< Twine::utohexstr (InputOffset) << " (branch)\n " );
64
- Map.insert (
65
- std::pair< uint32_t , uint32_t >(OutputOffset, InputOffset | BRANCHENTRY));
65
+ Map.insert (std::pair< uint32_t , uint32_t >(OutputOffset,
66
+ ( InputOffset << 1 ) | BRANCHENTRY));
66
67
}
67
68
}
68
69
@@ -96,41 +97,53 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
96
97
for (const BinaryBasicBlock *const BB : FF)
97
98
writeEntriesForBB (Map, *BB, FF.getAddress ());
98
99
99
- Maps .emplace (FF.getAddress (), std::move (Map));
100
+ ColdMaps .emplace (FF.getAddress (), std::move (Map));
100
101
ColdPartSource.emplace (FF.getAddress (), Function.getOutputAddress ());
101
102
}
102
103
}
103
104
105
+ // Output addresses are delta-encoded
106
+ uint64_t PrevAddress = 0 ;
107
+ writeMaps</* Cold=*/ false >(Maps, PrevAddress, OS);
108
+ writeMaps</* Cold=*/ true >(ColdMaps, PrevAddress, OS);
109
+
110
+ outs () << " BOLT-INFO: Wrote " << Maps.size () + ColdMaps.size ()
111
+ << " BAT maps\n " ;
112
+ }
113
+
114
+ template <bool Cold>
115
+ void BoltAddressTranslation::writeMaps (std::map<uint64_t , MapTy> &Maps,
116
+ uint64_t &PrevAddress, raw_ostream &OS) {
104
117
const uint32_t NumFuncs = Maps.size ();
105
- OS.write (reinterpret_cast <const char *>(&NumFuncs), 4 );
106
- LLVM_DEBUG (dbgs () << " Writing " << NumFuncs << " functions for BAT.\n " );
118
+ encodeULEB128 (NumFuncs, OS);
119
+ LLVM_DEBUG (dbgs () << " Writing " << NumFuncs << (Cold ? " cold" : " " )
120
+ << " functions for BAT.\n " );
121
+ size_t PrevIndex = 0 ;
107
122
for (auto &MapEntry : Maps) {
108
123
const uint64_t Address = MapEntry.first ;
109
124
MapTy &Map = MapEntry.second ;
110
125
const uint32_t NumEntries = Map.size ();
111
126
LLVM_DEBUG (dbgs () << " Writing " << NumEntries << " entries for 0x"
112
127
<< Twine::utohexstr (Address) << " .\n " );
113
- OS.write (reinterpret_cast <const char *>(&Address), 8 );
114
- OS.write (reinterpret_cast <const char *>(&NumEntries), 4 );
128
+ encodeULEB128 (Address - PrevAddress, OS);
129
+ PrevAddress = Address;
130
+ if (Cold) {
131
+ size_t HotIndex =
132
+ std::distance (ColdPartSource.begin (), ColdPartSource.find (Address));
133
+ encodeULEB128 (HotIndex - PrevIndex, OS);
134
+ PrevIndex = HotIndex;
135
+ }
136
+ encodeULEB128 (NumEntries, OS);
137
+ uint64_t InOffset = 0 ;
138
+ // Output and Input addresses and delta-encoded
115
139
for (std::pair<const uint32_t , uint32_t > &KeyVal : Map) {
116
- OS.write (reinterpret_cast <const char *>(&KeyVal.first ), 4 );
117
- OS.write (reinterpret_cast <const char *>(&KeyVal.second ), 4 );
140
+ const uint64_t OutputAddress = KeyVal.first + Address;
141
+ encodeULEB128 (OutputAddress - PrevAddress, OS);
142
+ PrevAddress = OutputAddress;
143
+ encodeSLEB128 (KeyVal.second - InOffset, OS);
144
+ InOffset = KeyVal.second ;
118
145
}
119
146
}
120
- const uint32_t NumColdEntries = ColdPartSource.size ();
121
- LLVM_DEBUG (dbgs () << " Writing " << NumColdEntries
122
- << " cold part mappings.\n " );
123
- OS.write (reinterpret_cast <const char *>(&NumColdEntries), 4 );
124
- for (std::pair<const uint64_t , uint64_t > &ColdEntry : ColdPartSource) {
125
- OS.write (reinterpret_cast <const char *>(&ColdEntry.first ), 8 );
126
- OS.write (reinterpret_cast <const char *>(&ColdEntry.second ), 8 );
127
- LLVM_DEBUG (dbgs () << " " << Twine::utohexstr (ColdEntry.first ) << " -> "
128
- << Twine::utohexstr (ColdEntry.second ) << " \n " );
129
- }
130
-
131
- outs () << " BOLT-INFO: Wrote " << Maps.size () << " BAT maps\n " ;
132
- outs () << " BOLT-INFO: Wrote " << NumColdEntries
133
- << " BAT cold-to-hot entries\n " ;
134
147
}
135
148
136
149
std::error_code BoltAddressTranslation::parse (StringRef Buf) {
@@ -152,53 +165,54 @@ std::error_code BoltAddressTranslation::parse(StringRef Buf) {
152
165
if (Name.substr (0 , 4 ) != " BOLT" )
153
166
return make_error_code (llvm::errc::io_error);
154
167
155
- if (Buf.size () - Offset < 4 )
156
- return make_error_code (llvm::errc::io_error);
168
+ Error Err (Error::success ());
169
+ std::vector<uint64_t > HotFuncs;
170
+ uint64_t PrevAddress = 0 ;
171
+ parseMaps</* Cold=*/ false >(HotFuncs, PrevAddress, DE, Offset, Err);
172
+ parseMaps</* Cold=*/ true >(HotFuncs, PrevAddress, DE, Offset, Err);
173
+ outs () << " BOLT-INFO: Parsed " << Maps.size () << " BAT entries\n " ;
174
+ return errorToErrorCode (std::move (Err));
175
+ }
157
176
158
- const uint32_t NumFunctions = DE.getU32 (&Offset);
159
- LLVM_DEBUG (dbgs () << " Parsing " << NumFunctions << " functions\n " );
177
+ template <bool Cold>
178
+ void BoltAddressTranslation::parseMaps (std::vector<uint64_t > &HotFuncs,
179
+ uint64_t &PrevAddress, DataExtractor &DE,
180
+ uint64_t &Offset, Error &Err) {
181
+ const uint32_t NumFunctions = DE.getULEB128 (&Offset, &Err);
182
+ LLVM_DEBUG (dbgs () << " Parsing " << NumFunctions << (Cold ? " cold" : " " )
183
+ << " functions\n " );
184
+ size_t HotIndex = 0 ;
160
185
for (uint32_t I = 0 ; I < NumFunctions; ++I) {
161
- if (Buf.size () - Offset < 12 )
162
- return make_error_code (llvm::errc::io_error);
163
-
164
- const uint64_t Address = DE.getU64 (&Offset);
165
- const uint32_t NumEntries = DE.getU32 (&Offset);
186
+ const uint64_t Address = PrevAddress + DE.getULEB128 (&Offset, &Err);
187
+ PrevAddress = Address;
188
+ if (Cold) {
189
+ HotIndex += DE.getULEB128 (&Offset, &Err);
190
+ ColdPartSource.emplace (Address, HotFuncs[HotIndex]);
191
+ } else {
192
+ HotFuncs.push_back (Address);
193
+ }
194
+ const uint32_t NumEntries = DE.getULEB128 (&Offset, &Err);
166
195
MapTy Map;
167
196
168
197
LLVM_DEBUG (dbgs () << " Parsing " << NumEntries << " entries for 0x"
169
198
<< Twine::utohexstr (Address) << " \n " );
170
- if (Buf.size () - Offset < 8 * NumEntries)
171
- return make_error_code (llvm::errc::io_error);
199
+ uint64_t InputOffset = 0 ;
172
200
for (uint32_t J = 0 ; J < NumEntries; ++J) {
173
- const uint32_t OutputAddr = DE.getU32 (&Offset);
174
- const uint32_t InputAddr = DE.getU32 (&Offset);
175
- Map.insert (std::pair<uint32_t , uint32_t >(OutputAddr, InputAddr));
176
- LLVM_DEBUG (dbgs () << Twine::utohexstr (OutputAddr) << " -> "
177
- << Twine::utohexstr (InputAddr) << " \n " );
201
+ const uint64_t OutputDelta = DE.getULEB128 (&Offset, &Err);
202
+ const uint64_t OutputAddress = PrevAddress + OutputDelta;
203
+ const uint64_t OutputOffset = OutputAddress - Address;
204
+ PrevAddress = OutputAddress;
205
+ const int64_t InputDelta = DE.getSLEB128 (&Offset, &Err);
206
+ InputOffset += InputDelta;
207
+ Map.insert (std::pair<uint32_t , uint32_t >(OutputOffset, InputOffset));
208
+ LLVM_DEBUG (
209
+ dbgs () << formatv (" {0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}\n " ,
210
+ OutputOffset, InputOffset, OutputDelta,
211
+ encodeULEB128 (OutputDelta, nulls ()), InputDelta,
212
+ encodeSLEB128 (InputDelta, nulls ()), OutputAddress));
178
213
}
179
214
Maps.insert (std::pair<uint64_t , MapTy>(Address, Map));
180
215
}
181
-
182
- if (Buf.size () - Offset < 4 )
183
- return make_error_code (llvm::errc::io_error);
184
-
185
- const uint32_t NumColdEntries = DE.getU32 (&Offset);
186
- LLVM_DEBUG (dbgs () << " Parsing " << NumColdEntries << " cold part mappings\n " );
187
- for (uint32_t I = 0 ; I < NumColdEntries; ++I) {
188
- if (Buf.size () - Offset < 16 )
189
- return make_error_code (llvm::errc::io_error);
190
- const uint32_t ColdAddress = DE.getU64 (&Offset);
191
- const uint32_t HotAddress = DE.getU64 (&Offset);
192
- ColdPartSource.insert (
193
- std::pair<uint64_t , uint64_t >(ColdAddress, HotAddress));
194
- LLVM_DEBUG (dbgs () << Twine::utohexstr (ColdAddress) << " -> "
195
- << Twine::utohexstr (HotAddress) << " \n " );
196
- }
197
- outs () << " BOLT-INFO: Parsed " << Maps.size () << " BAT entries\n " ;
198
- outs () << " BOLT-INFO: Parsed " << NumColdEntries
199
- << " BAT cold-to-hot entries\n " ;
200
-
201
- return std::error_code ();
202
216
}
203
217
204
218
void BoltAddressTranslation::dump (raw_ostream &OS) {
@@ -209,7 +223,7 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
209
223
OS << " BB mappings:\n " ;
210
224
for (const auto &Entry : MapEntry.second ) {
211
225
const bool IsBranch = Entry.second & BRANCHENTRY;
212
- const uint32_t Val = Entry.second & ~BRANCHENTRY;
226
+ const uint32_t Val = Entry.second >> 1 ; // dropping BRANCHENTRY bit
213
227
OS << " 0x" << Twine::utohexstr (Entry.first ) << " -> "
214
228
<< " 0x" << Twine::utohexstr (Val);
215
229
if (IsBranch)
@@ -244,7 +258,7 @@ uint64_t BoltAddressTranslation::translate(uint64_t FuncAddress,
244
258
245
259
--KeyVal;
246
260
247
- const uint32_t Val = KeyVal->second & ~BRANCHENTRY;
261
+ const uint32_t Val = KeyVal->second >> 1 ; // dropping BRANCHENTRY bit
248
262
// Branch source addresses are translated to the first instruction of the
249
263
// source BB to avoid accounting for modifications BOLT may have made in the
250
264
// BB regarding deletion/addition of instructions.
0 commit comments