xref: /llvm-project/bolt/lib/Profile/BoltAddressTranslation.cpp (revision 79d695f049343c96eccbce9c06357256bc567be3)
12f09f445SMaksim Panchenko //===- bolt/Profile/BoltAddressTranslation.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 //===----------------------------------------------------------------------===//
82f09f445SMaksim Panchenko 
9a34c753fSRafael Auler #include "bolt/Profile/BoltAddressTranslation.h"
10a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
11df7d2b2fSAmir Ayupov #include "llvm/ADT/APInt.h"
12a34c753fSRafael Auler #include "llvm/Support/Errc.h"
13565f40d6SAmir Ayupov #include "llvm/Support/Error.h"
14565f40d6SAmir Ayupov #include "llvm/Support/LEB128.h"
15a34c753fSRafael Auler 
16a34c753fSRafael Auler #define DEBUG_TYPE "bolt-bat"
17a34c753fSRafael Auler 
18a34c753fSRafael Auler namespace llvm {
19a34c753fSRafael Auler namespace bolt {
20a34c753fSRafael Auler 
21a34c753fSRafael Auler const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat";
22a34c753fSRafael Auler 
2350574638SAmir Ayupov void BoltAddressTranslation::writeEntriesForBB(
2450574638SAmir Ayupov     MapTy &Map, const BinaryBasicBlock &BB, uint64_t FuncInputAddress,
2550574638SAmir Ayupov     uint64_t FuncOutputAddress) const {
26a34c753fSRafael Auler   const uint64_t BBOutputOffset =
27a91cd53dSAmir Ayupov       BB.getOutputAddressRange().first - FuncOutputAddress;
28a34c753fSRafael Auler   const uint32_t BBInputOffset = BB.getInputOffset();
29a34c753fSRafael Auler 
30fc0ced73SRafael Auler   // Every output BB must track back to an input BB for profile collection
31fc0ced73SRafael Auler   // in bolted binaries. If we are missing an offset, it means this block was
32fc0ced73SRafael Auler   // created by a pass. We will skip writing any entries for it, and this means
33fc0ced73SRafael Auler   // any traffic happening in this block will map to the previous block in the
34fc0ced73SRafael Auler   // layout. This covers the case where an input basic block is split into two,
35fc0ced73SRafael Auler   // and the second one lacks any offset.
36fc0ced73SRafael Auler   if (BBInputOffset == BinaryBasicBlock::INVALID_OFFSET)
37fc0ced73SRafael Auler     return;
38a34c753fSRafael Auler 
39a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "BB " << BB.getName() << "\n");
40a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "  Key: " << Twine::utohexstr(BBOutputOffset)
41a34c753fSRafael Auler                     << " Val: " << Twine::utohexstr(BBInputOffset) << "\n");
42a91cd53dSAmir Ayupov   // NB: in `writeEntriesForBB` we use the input address because hashes are
43a91cd53dSAmir Ayupov   // saved early in `saveMetadata` before output addresses are assigned.
44a91cd53dSAmir Ayupov   const BBHashMapTy &BBHashMap = getBBHashMap(FuncInputAddress);
45a91cd53dSAmir Ayupov   (void)BBHashMap;
46a91cd53dSAmir Ayupov   LLVM_DEBUG(
47a91cd53dSAmir Ayupov       dbgs() << formatv(" Hash: {0:x}\n", BBHashMap.getBBHash(BBInputOffset)));
48a91cd53dSAmir Ayupov   LLVM_DEBUG(
49a91cd53dSAmir Ayupov       dbgs() << formatv(" Index: {0}\n", BBHashMap.getBBIndex(BBInputOffset)));
50a34c753fSRafael Auler   // In case of conflicts (same Key mapping to different Vals), the last
51a34c753fSRafael Auler   // update takes precedence. Of course it is not ideal to have conflicts and
52a34c753fSRafael Auler   // those happen when we have an empty BB that either contained only
53a34c753fSRafael Auler   // NOPs or a jump to the next block (successor). Either way, the successor
54a34c753fSRafael Auler   // and this deleted block will both share the same output address (the same
55a34c753fSRafael Auler   // key), and we need to map back. We choose here to privilege the successor by
56a34c753fSRafael Auler   // allowing it to overwrite the previously inserted key in the map.
57d1d9545eSAmir Ayupov   Map.emplace(BBOutputOffset, BBInputOffset << 1);
58a34c753fSRafael Auler 
5923c8d382SJob Noorman   const auto &IOAddressMap =
6023c8d382SJob Noorman       BB.getFunction()->getBinaryContext().getIOAddressMap();
6123c8d382SJob Noorman 
6223c8d382SJob Noorman   for (const auto &[InputOffset, Sym] : BB.getLocSyms()) {
6323c8d382SJob Noorman     const auto InputAddress = BB.getFunction()->getAddress() + InputOffset;
6423c8d382SJob Noorman     const auto OutputAddress = IOAddressMap.lookup(InputAddress);
6523c8d382SJob Noorman     assert(OutputAddress && "Unknown instruction address");
66a91cd53dSAmir Ayupov     const auto OutputOffset = *OutputAddress - FuncOutputAddress;
67a34c753fSRafael Auler 
68a34c753fSRafael Auler     // Is this the first instruction in the BB? No need to duplicate the entry.
69a34c753fSRafael Auler     if (OutputOffset == BBOutputOffset)
70a34c753fSRafael Auler       continue;
71a34c753fSRafael Auler 
72a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "  Key: " << Twine::utohexstr(OutputOffset) << " Val: "
73a34c753fSRafael Auler                       << Twine::utohexstr(InputOffset) << " (branch)\n");
74d1d9545eSAmir Ayupov     Map.emplace(OutputOffset, (InputOffset << 1) | BRANCHENTRY);
75a34c753fSRafael Auler   }
76a34c753fSRafael Auler }
77a34c753fSRafael Auler 
78fc0ced73SRafael Auler void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
79a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Writing BOLT Address Translation Tables\n");
80a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
81fc0ced73SRafael Auler     const BinaryFunction &Function = BFI.second;
82ad00e7e5SAmir Ayupov     const uint64_t InputAddress = Function.getAddress();
83ad00e7e5SAmir Ayupov     const uint64_t OutputAddress = Function.getOutputAddress();
84a34c753fSRafael Auler     // We don't need a translation table if the body of the function hasn't
85a34c753fSRafael Auler     // changed
86fc0ced73SRafael Auler     if (Function.isIgnored() || (!BC.HasRelocations && !Function.isSimple()))
87a34c753fSRafael Auler       continue;
88a34c753fSRafael Auler 
891b763f23SAmir Ayupov     uint32_t NumSecondaryEntryPoints = 0;
901b763f23SAmir Ayupov     Function.forEachEntryPoint([&](uint64_t Offset, const MCSymbol *) {
911b763f23SAmir Ayupov       if (!Offset)
921b763f23SAmir Ayupov         return true;
931b763f23SAmir Ayupov       ++NumSecondaryEntryPoints;
941b763f23SAmir Ayupov       SecondaryEntryPointsMap[OutputAddress].push_back(Offset);
951b763f23SAmir Ayupov       return true;
961b763f23SAmir Ayupov     });
97ad00e7e5SAmir Ayupov 
98a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n");
99a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << " Address reference: 0x"
100a34c753fSRafael Auler                       << Twine::utohexstr(Function.getOutputAddress()) << "\n");
10102276239SAmir Ayupov     LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(InputAddress)));
1021b763f23SAmir Ayupov     LLVM_DEBUG(dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints
1031b763f23SAmir Ayupov                       << '\n');
1049b6e7861SFabian Parzefall 
105a34c753fSRafael Auler     MapTy Map;
1069b6e7861SFabian Parzefall     for (const BinaryBasicBlock *const BB :
1079b6e7861SFabian Parzefall          Function.getLayout().getMainFragment())
108a91cd53dSAmir Ayupov       writeEntriesForBB(Map, *BB, InputAddress, OutputAddress);
109d1d9545eSAmir Ayupov     // Add entries for deleted blocks. They are still required for correct BB
110d1d9545eSAmir Ayupov     // mapping of branches modified by SCTC. By convention, they would have the
111d1d9545eSAmir Ayupov     // end of the function as output address.
112d1d9545eSAmir Ayupov     const BBHashMapTy &BBHashMap = getBBHashMap(InputAddress);
113d1d9545eSAmir Ayupov     if (BBHashMap.size() != Function.size()) {
114d1d9545eSAmir Ayupov       const uint64_t EndOffset = Function.getOutputSize();
115d1d9545eSAmir Ayupov       std::unordered_set<uint32_t> MappedInputOffsets;
116d1d9545eSAmir Ayupov       for (const BinaryBasicBlock &BB : Function)
117d1d9545eSAmir Ayupov         MappedInputOffsets.emplace(BB.getInputOffset());
118d1d9545eSAmir Ayupov       for (const auto &[InputOffset, _] : BBHashMap)
119d1d9545eSAmir Ayupov         if (!llvm::is_contained(MappedInputOffsets, InputOffset))
120d1d9545eSAmir Ayupov           Map.emplace(EndOffset, InputOffset << 1);
121d1d9545eSAmir Ayupov     }
1229b6e7861SFabian Parzefall     Maps.emplace(Function.getOutputAddress(), std::move(Map));
123ad00e7e5SAmir Ayupov     ReverseMap.emplace(OutputAddress, InputAddress);
124a34c753fSRafael Auler 
1259b6e7861SFabian Parzefall     if (!Function.isSplit())
126a34c753fSRafael Auler       continue;
127a34c753fSRafael Auler 
1289b6e7861SFabian Parzefall     // Split maps
1296304e382SFabian Parzefall     LLVM_DEBUG(dbgs() << " Cold part\n");
1309b6e7861SFabian Parzefall     for (const FunctionFragment &FF :
1319b6e7861SFabian Parzefall          Function.getLayout().getSplitFragments()) {
132dc1da939SAmir Ayupov       // Skip empty fragments to avoid adding zero-address entries to maps.
133dc1da939SAmir Ayupov       if (FF.empty())
134dc1da939SAmir Ayupov         continue;
135ad00e7e5SAmir Ayupov       ColdPartSource.emplace(FF.getAddress(), Function.getOutputAddress());
1369b6e7861SFabian Parzefall       Map.clear();
1379b6e7861SFabian Parzefall       for (const BinaryBasicBlock *const BB : FF)
138a91cd53dSAmir Ayupov         writeEntriesForBB(Map, *BB, InputAddress, FF.getAddress());
1399b6e7861SFabian Parzefall 
1409b6e7861SFabian Parzefall       Maps.emplace(FF.getAddress(), std::move(Map));
141a34c753fSRafael Auler     }
142a34c753fSRafael Auler   }
143a34c753fSRafael Auler 
1448f1d94aaSAmir Ayupov   // Output addresses are delta-encoded
1458f1d94aaSAmir Ayupov   uint64_t PrevAddress = 0;
146*79d695f0SAmir Ayupov   writeMaps</*Cold=*/false>(PrevAddress, OS);
147*79d695f0SAmir Ayupov   writeMaps</*Cold=*/true>(PrevAddress, OS);
148dcba0771SAmir Ayupov 
14952cf0711SAmir Ayupov   BC.outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n";
150a91cd53dSAmir Ayupov   BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.getNumFunctions()
151a91cd53dSAmir Ayupov             << " function and " << FuncHashes.getNumBasicBlocks()
152a91cd53dSAmir Ayupov             << " basic block hashes\n";
153dcba0771SAmir Ayupov }
154dcba0771SAmir Ayupov 
15550574638SAmir Ayupov APInt BoltAddressTranslation::calculateBranchEntriesBitMask(
15650574638SAmir Ayupov     MapTy &Map, size_t EqualElems) const {
157df7d2b2fSAmir Ayupov   APInt BitMask(alignTo(EqualElems, 8), 0);
158df7d2b2fSAmir Ayupov   size_t Index = 0;
159df7d2b2fSAmir Ayupov   for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) {
160df7d2b2fSAmir Ayupov     if (Index == EqualElems)
161df7d2b2fSAmir Ayupov       break;
162df7d2b2fSAmir Ayupov     const uint32_t OutputOffset = KeyVal.second;
163df7d2b2fSAmir Ayupov     if (OutputOffset & BRANCHENTRY)
164df7d2b2fSAmir Ayupov       BitMask.setBit(Index);
165df7d2b2fSAmir Ayupov     ++Index;
166df7d2b2fSAmir Ayupov   }
167df7d2b2fSAmir Ayupov   return BitMask;
168df7d2b2fSAmir Ayupov }
169df7d2b2fSAmir Ayupov 
170b79b6f9cSAmir Ayupov size_t BoltAddressTranslation::getNumEqualOffsets(const MapTy &Map,
171b79b6f9cSAmir Ayupov                                                   uint32_t Skew) const {
172df7d2b2fSAmir Ayupov   size_t EqualOffsets = 0;
173df7d2b2fSAmir Ayupov   for (const std::pair<const uint32_t, uint32_t> &KeyVal : Map) {
174df7d2b2fSAmir Ayupov     const uint32_t OutputOffset = KeyVal.first;
175df7d2b2fSAmir Ayupov     const uint32_t InputOffset = KeyVal.second >> 1;
176b79b6f9cSAmir Ayupov     if (OutputOffset == InputOffset - Skew)
177df7d2b2fSAmir Ayupov       ++EqualOffsets;
178df7d2b2fSAmir Ayupov     else
179df7d2b2fSAmir Ayupov       break;
180df7d2b2fSAmir Ayupov   }
181df7d2b2fSAmir Ayupov   return EqualOffsets;
182df7d2b2fSAmir Ayupov }
183df7d2b2fSAmir Ayupov 
184dcba0771SAmir Ayupov template <bool Cold>
185*79d695f0SAmir Ayupov void BoltAddressTranslation::writeMaps(uint64_t &PrevAddress, raw_ostream &OS) {
186dcba0771SAmir Ayupov   const uint32_t NumFuncs =
187dcba0771SAmir Ayupov       llvm::count_if(llvm::make_first_range(Maps), [&](const uint64_t Address) {
188dcba0771SAmir Ayupov         return Cold == ColdPartSource.count(Address);
189dcba0771SAmir Ayupov       });
190565f40d6SAmir Ayupov   encodeULEB128(NumFuncs, OS);
191dcba0771SAmir Ayupov   LLVM_DEBUG(dbgs() << "Writing " << NumFuncs << (Cold ? " cold" : "")
192dcba0771SAmir Ayupov                     << " functions for BAT.\n");
193dcba0771SAmir Ayupov   size_t PrevIndex = 0;
194a34c753fSRafael Auler   for (auto &MapEntry : Maps) {
195a34c753fSRafael Auler     const uint64_t Address = MapEntry.first;
196dcba0771SAmir Ayupov     // Only process cold fragments in cold mode, and vice versa.
197dcba0771SAmir Ayupov     if (Cold != ColdPartSource.count(Address))
198dcba0771SAmir Ayupov       continue;
199a91cd53dSAmir Ayupov     // NB: in `writeMaps` we use the input address because hashes are saved
200a91cd53dSAmir Ayupov     // early in `saveMetadata` before output addresses are assigned.
201ad00e7e5SAmir Ayupov     const uint64_t HotInputAddress =
202ad00e7e5SAmir Ayupov         ReverseMap[Cold ? ColdPartSource[Address] : Address];
203a34c753fSRafael Auler     MapTy &Map = MapEntry.second;
204a34c753fSRafael Auler     const uint32_t NumEntries = Map.size();
205a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "Writing " << NumEntries << " entries for 0x"
206a34c753fSRafael Auler                       << Twine::utohexstr(Address) << ".\n");
2078fb8ad66SAmir Ayupov     encodeULEB128(Address - PrevAddress, OS);
2088fb8ad66SAmir Ayupov     PrevAddress = Address;
2091b763f23SAmir Ayupov     const uint32_t NumSecondaryEntryPoints =
2101b763f23SAmir Ayupov         SecondaryEntryPointsMap.count(Address)
2111b763f23SAmir Ayupov             ? SecondaryEntryPointsMap[Address].size()
2121b763f23SAmir Ayupov             : 0;
213b79b6f9cSAmir Ayupov     uint32_t Skew = 0;
214dcba0771SAmir Ayupov     if (Cold) {
215*79d695f0SAmir Ayupov       auto HotEntryIt = llvm::lower_bound(HotFuncs, ColdPartSource[Address]);
216*79d695f0SAmir Ayupov       assert(HotEntryIt != HotFuncs.end());
217*79d695f0SAmir Ayupov       size_t HotIndex = std::distance(HotFuncs.begin(), HotEntryIt);
218dcba0771SAmir Ayupov       encodeULEB128(HotIndex - PrevIndex, OS);
219dcba0771SAmir Ayupov       PrevIndex = HotIndex;
220b79b6f9cSAmir Ayupov       // Skew of all input offsets for cold fragments is simply the first input
221b79b6f9cSAmir Ayupov       // offset.
222b79b6f9cSAmir Ayupov       Skew = Map.begin()->second >> 1;
223b79b6f9cSAmir Ayupov       encodeULEB128(Skew, OS);
224ad00e7e5SAmir Ayupov     } else {
225*79d695f0SAmir Ayupov       HotFuncs.push_back(Address);
226ad00e7e5SAmir Ayupov       // Function hash
227a91cd53dSAmir Ayupov       size_t BFHash = getBFHash(HotInputAddress);
228a91cd53dSAmir Ayupov       LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash));
229a91cd53dSAmir Ayupov       OS.write(reinterpret_cast<char *>(&BFHash), 8);
230ceba3a38SAmir Ayupov       // Number of basic blocks
231e64eede0SAmir Ayupov       size_t NumBasicBlocks = NumBasicBlocksMap[HotInputAddress];
232ceba3a38SAmir Ayupov       LLVM_DEBUG(dbgs() << "Basic blocks: " << NumBasicBlocks << '\n');
233ceba3a38SAmir Ayupov       encodeULEB128(NumBasicBlocks, OS);
2341b763f23SAmir Ayupov       // Secondary entry points
2351b763f23SAmir Ayupov       encodeULEB128(NumSecondaryEntryPoints, OS);
2361b763f23SAmir Ayupov       LLVM_DEBUG(dbgs() << "Secondary Entry Points: " << NumSecondaryEntryPoints
2371b763f23SAmir Ayupov                         << '\n');
238dcba0771SAmir Ayupov     }
239565f40d6SAmir Ayupov     encodeULEB128(NumEntries, OS);
240b79b6f9cSAmir Ayupov     // Encode the number of equal offsets (output = input - skew) in the
241b79b6f9cSAmir Ayupov     // beginning of the function. Only encode one offset in these cases.
242b79b6f9cSAmir Ayupov     const size_t EqualElems = getNumEqualOffsets(Map, Skew);
243df7d2b2fSAmir Ayupov     encodeULEB128(EqualElems, OS);
244df7d2b2fSAmir Ayupov     if (EqualElems) {
245df7d2b2fSAmir Ayupov       const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8;
246df7d2b2fSAmir Ayupov       APInt BranchEntries = calculateBranchEntriesBitMask(Map, EqualElems);
247df7d2b2fSAmir Ayupov       OS.write(reinterpret_cast<const char *>(BranchEntries.getRawData()),
248df7d2b2fSAmir Ayupov                BranchEntriesBytes);
249df7d2b2fSAmir Ayupov       LLVM_DEBUG({
250df7d2b2fSAmir Ayupov         dbgs() << "BranchEntries: ";
251df7d2b2fSAmir Ayupov         SmallString<8> BitMaskStr;
252df7d2b2fSAmir Ayupov         BranchEntries.toString(BitMaskStr, 2, false);
253df7d2b2fSAmir Ayupov         dbgs() << BitMaskStr << '\n';
254df7d2b2fSAmir Ayupov       });
255df7d2b2fSAmir Ayupov     }
256a91cd53dSAmir Ayupov     const BBHashMapTy &BBHashMap = getBBHashMap(HotInputAddress);
257df7d2b2fSAmir Ayupov     size_t Index = 0;
2588f1d94aaSAmir Ayupov     uint64_t InOffset = 0;
259b0e23639SAmir Ayupov     size_t PrevBBIndex = 0;
260bbe07989SAmir Ayupov     // Output and Input addresses and delta-encoded
261a34c753fSRafael Auler     for (std::pair<const uint32_t, uint32_t> &KeyVal : Map) {
2628f1d94aaSAmir Ayupov       const uint64_t OutputAddress = KeyVal.first + Address;
2638f1d94aaSAmir Ayupov       encodeULEB128(OutputAddress - PrevAddress, OS);
2648f1d94aaSAmir Ayupov       PrevAddress = OutputAddress;
265df7d2b2fSAmir Ayupov       if (Index++ >= EqualElems)
266bbe07989SAmir Ayupov         encodeSLEB128(KeyVal.second - InOffset, OS);
267df7d2b2fSAmir Ayupov       InOffset = KeyVal.second; // Keeping InOffset as if BRANCHENTRY is encoded
268ad00e7e5SAmir Ayupov       if ((InOffset & BRANCHENTRY) == 0) {
269a91cd53dSAmir Ayupov         const bool IsBlock = BBHashMap.isInputBlock(InOffset >> 1);
270a91cd53dSAmir Ayupov         unsigned BBIndex = IsBlock ? BBHashMap.getBBIndex(InOffset >> 1) : 0;
271a91cd53dSAmir Ayupov         size_t BBHash = IsBlock ? BBHashMap.getBBHash(InOffset >> 1) : 0;
272ad00e7e5SAmir Ayupov         OS.write(reinterpret_cast<char *>(&BBHash), 8);
273b0e23639SAmir Ayupov         // Basic block index in the input binary
274b0e23639SAmir Ayupov         encodeULEB128(BBIndex - PrevBBIndex, OS);
275b0e23639SAmir Ayupov         PrevBBIndex = BBIndex;
276b0e23639SAmir Ayupov         LLVM_DEBUG(dbgs() << formatv("{0:x} -> {1:x} {2:x} {3}\n", KeyVal.first,
277b0e23639SAmir Ayupov                                      InOffset >> 1, BBHash, BBIndex));
278ad00e7e5SAmir Ayupov       }
279a34c753fSRafael Auler     }
2801b763f23SAmir Ayupov     uint32_t PrevOffset = 0;
2811b763f23SAmir Ayupov     if (!Cold && NumSecondaryEntryPoints) {
2821b763f23SAmir Ayupov       LLVM_DEBUG(dbgs() << "Secondary entry points: ");
2831b763f23SAmir Ayupov       // Secondary entry point offsets, delta-encoded
2841b763f23SAmir Ayupov       for (uint32_t Offset : SecondaryEntryPointsMap[Address]) {
2851b763f23SAmir Ayupov         encodeULEB128(Offset - PrevOffset, OS);
2861b763f23SAmir Ayupov         LLVM_DEBUG(dbgs() << formatv("{0:x} ", Offset));
2871b763f23SAmir Ayupov         PrevOffset = Offset;
2881b763f23SAmir Ayupov       }
2891b763f23SAmir Ayupov       LLVM_DEBUG(dbgs() << '\n');
2901b763f23SAmir Ayupov     }
291a34c753fSRafael Auler   }
292a34c753fSRafael Auler }
293a34c753fSRafael Auler 
29452cf0711SAmir Ayupov std::error_code BoltAddressTranslation::parse(raw_ostream &OS, StringRef Buf) {
295a34c753fSRafael Auler   DataExtractor DE = DataExtractor(Buf, true, 8);
296a34c753fSRafael Auler   uint64_t Offset = 0;
297a34c753fSRafael Auler   if (Buf.size() < 12)
298a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
299a34c753fSRafael Auler 
300a34c753fSRafael Auler   const uint32_t NameSz = DE.getU32(&Offset);
301a34c753fSRafael Auler   const uint32_t DescSz = DE.getU32(&Offset);
302a34c753fSRafael Auler   const uint32_t Type = DE.getU32(&Offset);
303a34c753fSRafael Auler 
304a34c753fSRafael Auler   if (Type != BinarySection::NT_BOLT_BAT ||
305a34c753fSRafael Auler       Buf.size() + Offset < alignTo(NameSz, 4) + DescSz)
306a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
307a34c753fSRafael Auler 
308a34c753fSRafael Auler   StringRef Name = Buf.slice(Offset, Offset + NameSz);
309a34c753fSRafael Auler   Offset = alignTo(Offset + NameSz, 4);
3108901f718SKazu Hirata   if (!Name.starts_with("BOLT"))
311a34c753fSRafael Auler     return make_error_code(llvm::errc::io_error);
312a34c753fSRafael Auler 
313565f40d6SAmir Ayupov   Error Err(Error::success());
3148f1d94aaSAmir Ayupov   uint64_t PrevAddress = 0;
315*79d695f0SAmir Ayupov   parseMaps</*Cold=*/false>(PrevAddress, DE, Offset, Err);
316*79d695f0SAmir Ayupov   parseMaps</*Cold=*/true>(PrevAddress, DE, Offset, Err);
31752cf0711SAmir Ayupov   OS << "BOLT-INFO: Parsed " << Maps.size() << " BAT entries\n";
318dcba0771SAmir Ayupov   return errorToErrorCode(std::move(Err));
319dcba0771SAmir Ayupov }
320dcba0771SAmir Ayupov 
321dcba0771SAmir Ayupov template <bool Cold>
322*79d695f0SAmir Ayupov void BoltAddressTranslation::parseMaps(uint64_t &PrevAddress, DataExtractor &DE,
3238f1d94aaSAmir Ayupov                                        uint64_t &Offset, Error &Err) {
324565f40d6SAmir Ayupov   const uint32_t NumFunctions = DE.getULEB128(&Offset, &Err);
325dcba0771SAmir Ayupov   LLVM_DEBUG(dbgs() << "Parsing " << NumFunctions << (Cold ? " cold" : "")
326dcba0771SAmir Ayupov                     << " functions\n");
327dcba0771SAmir Ayupov   size_t HotIndex = 0;
328a34c753fSRafael Auler   for (uint32_t I = 0; I < NumFunctions; ++I) {
3298fb8ad66SAmir Ayupov     const uint64_t Address = PrevAddress + DE.getULEB128(&Offset, &Err);
330ad00e7e5SAmir Ayupov     uint64_t HotAddress = Cold ? 0 : Address;
3318fb8ad66SAmir Ayupov     PrevAddress = Address;
3321b763f23SAmir Ayupov     uint32_t SecondaryEntryPoints = 0;
333b79b6f9cSAmir Ayupov     uint64_t ColdInputSkew = 0;
334dcba0771SAmir Ayupov     if (Cold) {
335dcba0771SAmir Ayupov       HotIndex += DE.getULEB128(&Offset, &Err);
336ad00e7e5SAmir Ayupov       HotAddress = HotFuncs[HotIndex];
337ad00e7e5SAmir Ayupov       ColdPartSource.emplace(Address, HotAddress);
338b79b6f9cSAmir Ayupov       ColdInputSkew = DE.getULEB128(&Offset, &Err);
339dcba0771SAmir Ayupov     } else {
340dcba0771SAmir Ayupov       HotFuncs.push_back(Address);
341ad00e7e5SAmir Ayupov       // Function hash
342ad00e7e5SAmir Ayupov       const size_t FuncHash = DE.getU64(&Offset, &Err);
343a91cd53dSAmir Ayupov       FuncHashes.addEntry(Address, FuncHash);
344ad00e7e5SAmir Ayupov       LLVM_DEBUG(dbgs() << formatv("{0:x}: hash {1:x}\n", Address, FuncHash));
345ceba3a38SAmir Ayupov       // Number of basic blocks
346ceba3a38SAmir Ayupov       const size_t NumBasicBlocks = DE.getULEB128(&Offset, &Err);
347ceba3a38SAmir Ayupov       NumBasicBlocksMap.emplace(Address, NumBasicBlocks);
348ceba3a38SAmir Ayupov       LLVM_DEBUG(dbgs() << formatv("{0:x}: #bbs {1}, {2} bytes\n", Address,
349ceba3a38SAmir Ayupov                                    NumBasicBlocks,
350ceba3a38SAmir Ayupov                                    getULEB128Size(NumBasicBlocks)));
3511b763f23SAmir Ayupov       // Secondary entry points
3521b763f23SAmir Ayupov       SecondaryEntryPoints = DE.getULEB128(&Offset, &Err);
3531b763f23SAmir Ayupov       LLVM_DEBUG(
3541b763f23SAmir Ayupov           dbgs() << formatv("{0:x}: secondary entry points {1}, {2} bytes\n",
3551b763f23SAmir Ayupov                             Address, SecondaryEntryPoints,
3561b763f23SAmir Ayupov                             getULEB128Size(SecondaryEntryPoints)));
357dcba0771SAmir Ayupov     }
358565f40d6SAmir Ayupov     const uint32_t NumEntries = DE.getULEB128(&Offset, &Err);
359b79b6f9cSAmir Ayupov     // Equal offsets.
360b79b6f9cSAmir Ayupov     const size_t EqualElems = DE.getULEB128(&Offset, &Err);
361df7d2b2fSAmir Ayupov     APInt BEBitMask;
362b79b6f9cSAmir Ayupov     LLVM_DEBUG(dbgs() << formatv("Equal offsets: {0}, {1} bytes\n", EqualElems,
363b79b6f9cSAmir Ayupov                                  getULEB128Size(EqualElems)));
364df7d2b2fSAmir Ayupov     if (EqualElems) {
365df7d2b2fSAmir Ayupov       const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8;
366df7d2b2fSAmir Ayupov       BEBitMask = APInt(alignTo(EqualElems, 8), 0);
367df7d2b2fSAmir Ayupov       LoadIntFromMemory(
368df7d2b2fSAmir Ayupov           BEBitMask,
369df7d2b2fSAmir Ayupov           reinterpret_cast<const uint8_t *>(
370df7d2b2fSAmir Ayupov               DE.getBytes(&Offset, BranchEntriesBytes, &Err).data()),
371df7d2b2fSAmir Ayupov           BranchEntriesBytes);
372df7d2b2fSAmir Ayupov       LLVM_DEBUG({
373df7d2b2fSAmir Ayupov         dbgs() << "BEBitMask: ";
374df7d2b2fSAmir Ayupov         SmallString<8> BitMaskStr;
375df7d2b2fSAmir Ayupov         BEBitMask.toString(BitMaskStr, 2, false);
376df7d2b2fSAmir Ayupov         dbgs() << BitMaskStr << ", " << BranchEntriesBytes << " bytes\n";
377df7d2b2fSAmir Ayupov       });
378df7d2b2fSAmir Ayupov     }
379a34c753fSRafael Auler     MapTy Map;
380a34c753fSRafael Auler 
381a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "Parsing " << NumEntries << " entries for 0x"
382a34c753fSRafael Auler                       << Twine::utohexstr(Address) << "\n");
3838f1d94aaSAmir Ayupov     uint64_t InputOffset = 0;
384b0e23639SAmir Ayupov     size_t BBIndex = 0;
385a34c753fSRafael Auler     for (uint32_t J = 0; J < NumEntries; ++J) {
386bbe07989SAmir Ayupov       const uint64_t OutputDelta = DE.getULEB128(&Offset, &Err);
3878f1d94aaSAmir Ayupov       const uint64_t OutputAddress = PrevAddress + OutputDelta;
3888f1d94aaSAmir Ayupov       const uint64_t OutputOffset = OutputAddress - Address;
3898f1d94aaSAmir Ayupov       PrevAddress = OutputAddress;
390df7d2b2fSAmir Ayupov       int64_t InputDelta = 0;
391df7d2b2fSAmir Ayupov       if (J < EqualElems) {
3928927ac86SKazu Hirata         InputOffset = ((OutputOffset + ColdInputSkew) << 1) | BEBitMask[J];
393df7d2b2fSAmir Ayupov       } else {
394df7d2b2fSAmir Ayupov         InputDelta = DE.getSLEB128(&Offset, &Err);
395bbe07989SAmir Ayupov         InputOffset += InputDelta;
396df7d2b2fSAmir Ayupov       }
397bbe07989SAmir Ayupov       Map.insert(std::pair<uint32_t, uint32_t>(OutputOffset, InputOffset));
398ad00e7e5SAmir Ayupov       size_t BBHash = 0;
399b0e23639SAmir Ayupov       size_t BBIndexDelta = 0;
400ad00e7e5SAmir Ayupov       const bool IsBranchEntry = InputOffset & BRANCHENTRY;
401ad00e7e5SAmir Ayupov       if (!IsBranchEntry) {
402ad00e7e5SAmir Ayupov         BBHash = DE.getU64(&Offset, &Err);
403b0e23639SAmir Ayupov         BBIndexDelta = DE.getULEB128(&Offset, &Err);
404b0e23639SAmir Ayupov         BBIndex += BBIndexDelta;
405ad00e7e5SAmir Ayupov         // Map basic block hash to hot fragment by input offset
406a91cd53dSAmir Ayupov         getBBHashMap(HotAddress).addEntry(InputOffset >> 1, BBIndex, BBHash);
407ad00e7e5SAmir Ayupov       }
408ad00e7e5SAmir Ayupov       LLVM_DEBUG({
409ad00e7e5SAmir Ayupov         dbgs() << formatv(
410ad00e7e5SAmir Ayupov             "{0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}", OutputOffset,
411ad00e7e5SAmir Ayupov             InputOffset, OutputDelta, getULEB128Size(OutputDelta), InputDelta,
412ad00e7e5SAmir Ayupov             (J < EqualElems) ? 0 : getSLEB128Size(InputDelta), OutputAddress);
413b0e23639SAmir Ayupov         if (!IsBranchEntry) {
414b0e23639SAmir Ayupov           dbgs() << formatv(" {0:x} {1}/{2}b", BBHash, BBIndex,
415b0e23639SAmir Ayupov                             getULEB128Size(BBIndexDelta));
416b0e23639SAmir Ayupov         }
417ad00e7e5SAmir Ayupov         dbgs() << '\n';
418ad00e7e5SAmir Ayupov       });
419a34c753fSRafael Auler     }
420a34c753fSRafael Auler     Maps.insert(std::pair<uint64_t, MapTy>(Address, Map));
4211b763f23SAmir Ayupov     if (!Cold && SecondaryEntryPoints) {
4221b763f23SAmir Ayupov       uint32_t EntryPointOffset = 0;
4231b763f23SAmir Ayupov       LLVM_DEBUG(dbgs() << "Secondary entry points: ");
4241b763f23SAmir Ayupov       for (uint32_t EntryPointId = 0; EntryPointId != SecondaryEntryPoints;
4251b763f23SAmir Ayupov            ++EntryPointId) {
4261b763f23SAmir Ayupov         uint32_t OffsetDelta = DE.getULEB128(&Offset, &Err);
4271b763f23SAmir Ayupov         EntryPointOffset += OffsetDelta;
4281b763f23SAmir Ayupov         SecondaryEntryPointsMap[Address].push_back(EntryPointOffset);
4291b763f23SAmir Ayupov         LLVM_DEBUG(dbgs() << formatv("{0:x}/{1}b ", EntryPointOffset,
4301b763f23SAmir Ayupov                                      getULEB128Size(OffsetDelta)));
4311b763f23SAmir Ayupov       }
4321b763f23SAmir Ayupov       LLVM_DEBUG(dbgs() << '\n');
4331b763f23SAmir Ayupov     }
434a34c753fSRafael Auler   }
435a34c753fSRafael Auler }
436a34c753fSRafael Auler 
43750574638SAmir Ayupov void BoltAddressTranslation::dump(raw_ostream &OS) const {
438fc0ced73SRafael Auler   const size_t NumTables = Maps.size();
439fc0ced73SRafael Auler   OS << "BAT tables for " << NumTables << " functions:\n";
440fc0ced73SRafael Auler   for (const auto &MapEntry : Maps) {
441ad00e7e5SAmir Ayupov     const uint64_t Address = MapEntry.first;
442ad00e7e5SAmir Ayupov     const uint64_t HotAddress = fetchParentAddress(Address);
443e64eede0SAmir Ayupov     const bool IsHotFunction = HotAddress == 0;
444ad00e7e5SAmir Ayupov     OS << "Function Address: 0x" << Twine::utohexstr(Address);
445e64eede0SAmir Ayupov     if (IsHotFunction)
446ad00e7e5SAmir Ayupov       OS << formatv(", hash: {0:x}", getBFHash(Address));
447ad00e7e5SAmir Ayupov     OS << "\n";
448fc0ced73SRafael Auler     OS << "BB mappings:\n";
449a91cd53dSAmir Ayupov     const BBHashMapTy &BBHashMap =
450a91cd53dSAmir Ayupov         getBBHashMap(HotAddress ? HotAddress : Address);
451fc0ced73SRafael Auler     for (const auto &Entry : MapEntry.second) {
452fc0ced73SRafael Auler       const bool IsBranch = Entry.second & BRANCHENTRY;
453565f40d6SAmir Ayupov       const uint32_t Val = Entry.second >> 1; // dropping BRANCHENTRY bit
454fc0ced73SRafael Auler       OS << "0x" << Twine::utohexstr(Entry.first) << " -> "
455fc0ced73SRafael Auler          << "0x" << Twine::utohexstr(Val);
456fc0ced73SRafael Auler       if (IsBranch)
457fc0ced73SRafael Auler         OS << " (branch)";
458ad00e7e5SAmir Ayupov       else
459a91cd53dSAmir Ayupov         OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val));
460fc0ced73SRafael Auler       OS << "\n";
461fc0ced73SRafael Auler     }
46250574638SAmir Ayupov     if (IsHotFunction) {
46350574638SAmir Ayupov       auto NumBasicBlocksIt = NumBasicBlocksMap.find(Address);
46450574638SAmir Ayupov       assert(NumBasicBlocksIt != NumBasicBlocksMap.end());
46550574638SAmir Ayupov       OS << "NumBlocks: " << NumBasicBlocksIt->second << '\n';
46650574638SAmir Ayupov     }
46750574638SAmir Ayupov     auto SecondaryEntryPointsIt = SecondaryEntryPointsMap.find(Address);
46850574638SAmir Ayupov     if (SecondaryEntryPointsIt != SecondaryEntryPointsMap.end()) {
4691b763f23SAmir Ayupov       const std::vector<uint32_t> &SecondaryEntryPoints =
47050574638SAmir Ayupov           SecondaryEntryPointsIt->second;
4711b763f23SAmir Ayupov       OS << SecondaryEntryPoints.size() << " secondary entry points:\n";
4721b763f23SAmir Ayupov       for (uint32_t EntryPointOffset : SecondaryEntryPoints)
4731b763f23SAmir Ayupov         OS << formatv("{0:x}\n", EntryPointOffset);
4741b763f23SAmir Ayupov     }
475fc0ced73SRafael Auler     OS << "\n";
476fc0ced73SRafael Auler   }
477fc0ced73SRafael Auler   const size_t NumColdParts = ColdPartSource.size();
478fc0ced73SRafael Auler   if (!NumColdParts)
479fc0ced73SRafael Auler     return;
480fc0ced73SRafael Auler 
481fc0ced73SRafael Auler   OS << NumColdParts << " cold mappings:\n";
482fc0ced73SRafael Auler   for (const auto &Entry : ColdPartSource) {
483fc0ced73SRafael Auler     OS << "0x" << Twine::utohexstr(Entry.first) << " -> "
484fc0ced73SRafael Auler        << Twine::utohexstr(Entry.second) << "\n";
485fc0ced73SRafael Auler   }
486fc0ced73SRafael Auler   OS << "\n";
487fc0ced73SRafael Auler }
488fc0ced73SRafael Auler 
489fc0ced73SRafael Auler uint64_t BoltAddressTranslation::translate(uint64_t FuncAddress,
490a34c753fSRafael Auler                                            uint64_t Offset,
491a34c753fSRafael Auler                                            bool IsBranchSrc) const {
492fc0ced73SRafael Auler   auto Iter = Maps.find(FuncAddress);
493a34c753fSRafael Auler   if (Iter == Maps.end())
494a34c753fSRafael Auler     return Offset;
495a34c753fSRafael Auler 
496a34c753fSRafael Auler   const MapTy &Map = Iter->second;
497a34c753fSRafael Auler   auto KeyVal = Map.upper_bound(Offset);
498a34c753fSRafael Auler   if (KeyVal == Map.begin())
499a34c753fSRafael Auler     return Offset;
500a34c753fSRafael Auler 
501a34c753fSRafael Auler   --KeyVal;
502a34c753fSRafael Auler 
503565f40d6SAmir Ayupov   const uint32_t Val = KeyVal->second >> 1; // dropping BRANCHENTRY bit
504a34c753fSRafael Auler   // Branch source addresses are translated to the first instruction of the
505a34c753fSRafael Auler   // source BB to avoid accounting for modifications BOLT may have made in the
506a34c753fSRafael Auler   // BB regarding deletion/addition of instructions.
507a34c753fSRafael Auler   if (IsBranchSrc)
508a34c753fSRafael Auler     return Val;
509a34c753fSRafael Auler   return Offset - KeyVal->first + Val;
510a34c753fSRafael Auler }
511a34c753fSRafael Auler 
5123d573fdbSAmir Ayupov std::optional<BoltAddressTranslation::FallthroughListTy>
513fc0ced73SRafael Auler BoltAddressTranslation::getFallthroughsInTrace(uint64_t FuncAddress,
51440c2e0faSMaksim Panchenko                                                uint64_t From,
51540c2e0faSMaksim Panchenko                                                uint64_t To) const {
516a34c753fSRafael Auler   SmallVector<std::pair<uint64_t, uint64_t>, 16> Res;
517a34c753fSRafael Auler 
518a34c753fSRafael Auler   // Filter out trivial case
519a34c753fSRafael Auler   if (From >= To)
520a34c753fSRafael Auler     return Res;
521a34c753fSRafael Auler 
522fc0ced73SRafael Auler   From -= FuncAddress;
523fc0ced73SRafael Auler   To -= FuncAddress;
524a34c753fSRafael Auler 
525fc0ced73SRafael Auler   auto Iter = Maps.find(FuncAddress);
526def464aaSAmir Ayupov   if (Iter == Maps.end())
527e324a80fSKazu Hirata     return std::nullopt;
528a34c753fSRafael Auler 
529a34c753fSRafael Auler   const MapTy &Map = Iter->second;
530a34c753fSRafael Auler   auto FromIter = Map.upper_bound(From);
531a34c753fSRafael Auler   if (FromIter == Map.begin())
532a34c753fSRafael Auler     return Res;
533a34c753fSRafael Auler   // Skip instruction entries, to create fallthroughs we are only interested in
534a34c753fSRafael Auler   // BB boundaries
535a34c753fSRafael Auler   do {
536a34c753fSRafael Auler     if (FromIter == Map.begin())
537a34c753fSRafael Auler       return Res;
538a34c753fSRafael Auler     --FromIter;
539a34c753fSRafael Auler   } while (FromIter->second & BRANCHENTRY);
540a34c753fSRafael Auler 
541a34c753fSRafael Auler   auto ToIter = Map.upper_bound(To);
542a34c753fSRafael Auler   if (ToIter == Map.begin())
543a34c753fSRafael Auler     return Res;
544a34c753fSRafael Auler   --ToIter;
545a34c753fSRafael Auler   if (FromIter->first >= ToIter->first)
546a34c753fSRafael Auler     return Res;
547a34c753fSRafael Auler 
548a34c753fSRafael Auler   for (auto Iter = FromIter; Iter != ToIter;) {
549a34c753fSRafael Auler     const uint32_t Src = Iter->first;
550a34c753fSRafael Auler     if (Iter->second & BRANCHENTRY) {
551a34c753fSRafael Auler       ++Iter;
552a34c753fSRafael Auler       continue;
553a34c753fSRafael Auler     }
554a34c753fSRafael Auler 
555a34c753fSRafael Auler     ++Iter;
556def464aaSAmir Ayupov     while (Iter->second & BRANCHENTRY && Iter != ToIter)
557a34c753fSRafael Auler       ++Iter;
558a34c753fSRafael Auler     if (Iter->second & BRANCHENTRY)
559a34c753fSRafael Auler       break;
560a34c753fSRafael Auler     Res.emplace_back(Src, Iter->first);
561a34c753fSRafael Auler   }
562a34c753fSRafael Auler 
563a34c753fSRafael Auler   return Res;
564a34c753fSRafael Auler }
565a34c753fSRafael Auler 
566a34c753fSRafael Auler bool BoltAddressTranslation::enabledFor(
567a34c753fSRafael Auler     llvm::object::ELFObjectFileBase *InputFile) const {
568a34c753fSRafael Auler   for (const SectionRef &Section : InputFile->sections()) {
569a34c753fSRafael Auler     Expected<StringRef> SectionNameOrErr = Section.getName();
570a34c753fSRafael Auler     if (Error E = SectionNameOrErr.takeError())
571a34c753fSRafael Auler       continue;
572a34c753fSRafael Auler 
573a34c753fSRafael Auler     if (SectionNameOrErr.get() == SECTION_NAME)
574a34c753fSRafael Auler       return true;
575a34c753fSRafael Auler   }
576a34c753fSRafael Auler   return false;
577a34c753fSRafael Auler }
578d2c9a19dSAmir Ayupov 
579d2c9a19dSAmir Ayupov void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
580d2c9a19dSAmir Ayupov   for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) {
581d2c9a19dSAmir Ayupov     // We don't need a translation table if the body of the function hasn't
582d2c9a19dSAmir Ayupov     // changed
583d2c9a19dSAmir Ayupov     if (BF.isIgnored() || (!BC.HasRelocations && !BF.isSimple()))
584d2c9a19dSAmir Ayupov       continue;
585d2c9a19dSAmir Ayupov     // Prepare function and block hashes
586a91cd53dSAmir Ayupov     FuncHashes.addEntry(BF.getAddress(), BF.computeHash());
587d2c9a19dSAmir Ayupov     BF.computeBlockHashes();
588a91cd53dSAmir Ayupov     BBHashMapTy &BBHashMap = getBBHashMap(BF.getAddress());
589a91cd53dSAmir Ayupov     // Set BF/BB metadata
590d2c9a19dSAmir Ayupov     for (const BinaryBasicBlock &BB : BF)
591a91cd53dSAmir Ayupov       BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash());
592e64eede0SAmir Ayupov     NumBasicBlocksMap.emplace(BF.getAddress(), BF.size());
593d2c9a19dSAmir Ayupov   }
594d2c9a19dSAmir Ayupov }
595ad00e7e5SAmir Ayupov 
5962d3c827cSAmir Ayupov unsigned
5972d3c827cSAmir Ayupov BoltAddressTranslation::getSecondaryEntryPointId(uint64_t Address,
5982d3c827cSAmir Ayupov                                                  uint32_t Offset) const {
5992d3c827cSAmir Ayupov   auto FunctionIt = SecondaryEntryPointsMap.find(Address);
6002d3c827cSAmir Ayupov   if (FunctionIt == SecondaryEntryPointsMap.end())
6012d3c827cSAmir Ayupov     return 0;
6022d3c827cSAmir Ayupov   const std::vector<uint32_t> &Offsets = FunctionIt->second;
6032d3c827cSAmir Ayupov   auto OffsetIt = std::find(Offsets.begin(), Offsets.end(), Offset);
6042d3c827cSAmir Ayupov   if (OffsetIt == Offsets.end())
6052d3c827cSAmir Ayupov     return 0;
6062d3c827cSAmir Ayupov   // Adding one here because main entry point is not stored in BAT, and
6072d3c827cSAmir Ayupov   // enumeration for secondary entry points starts with 1.
6082d3c827cSAmir Ayupov   return OffsetIt - Offsets.begin() + 1;
6092d3c827cSAmir Ayupov }
6102d3c827cSAmir Ayupov 
6112d3c827cSAmir Ayupov std::pair<const BinaryFunction *, unsigned>
6122d3c827cSAmir Ayupov BoltAddressTranslation::translateSymbol(const BinaryContext &BC,
6132d3c827cSAmir Ayupov                                         const MCSymbol &Symbol,
6142d3c827cSAmir Ayupov                                         uint32_t Offset) const {
6152d3c827cSAmir Ayupov   // The symbol could be a secondary entry in a cold fragment.
6162d3c827cSAmir Ayupov   uint64_t SymbolValue = cantFail(errorOrToExpected(BC.getSymbolValue(Symbol)));
6172d3c827cSAmir Ayupov 
6182d3c827cSAmir Ayupov   const BinaryFunction *Callee = BC.getFunctionForSymbol(&Symbol);
6192d3c827cSAmir Ayupov   assert(Callee);
6202d3c827cSAmir Ayupov 
6212d3c827cSAmir Ayupov   // Containing function, not necessarily the same as symbol value.
6222d3c827cSAmir Ayupov   const uint64_t CalleeAddress = Callee->getAddress();
6232d3c827cSAmir Ayupov   const uint32_t OutputOffset = SymbolValue - CalleeAddress;
6242d3c827cSAmir Ayupov 
6252d3c827cSAmir Ayupov   const uint64_t ParentAddress = fetchParentAddress(CalleeAddress);
6262d3c827cSAmir Ayupov   const uint64_t HotAddress = ParentAddress ? ParentAddress : CalleeAddress;
6272d3c827cSAmir Ayupov 
6282d3c827cSAmir Ayupov   const BinaryFunction *ParentBF = BC.getBinaryFunctionAtAddress(HotAddress);
6292d3c827cSAmir Ayupov 
6302d3c827cSAmir Ayupov   const uint32_t InputOffset =
6312d3c827cSAmir Ayupov       translate(CalleeAddress, OutputOffset, /*IsBranchSrc*/ false) + Offset;
6322d3c827cSAmir Ayupov 
6332d3c827cSAmir Ayupov   unsigned SecondaryEntryId{0};
6342d3c827cSAmir Ayupov   if (InputOffset)
6352d3c827cSAmir Ayupov     SecondaryEntryId = getSecondaryEntryPointId(HotAddress, InputOffset);
6362d3c827cSAmir Ayupov 
6372d3c827cSAmir Ayupov   return std::pair(ParentBF, SecondaryEntryId);
6382d3c827cSAmir Ayupov }
6392d3c827cSAmir Ayupov 
64040c2e0faSMaksim Panchenko } // namespace bolt
64140c2e0faSMaksim Panchenko } // namespace llvm
642