xref: /llvm-project/bolt/lib/Passes/ReorderData.cpp (revision 52cf07116bf0a8cab87b0f55176d198bcaa02575)
12f09f445SMaksim Panchenko //===- bolt/Passes/ReorderSection.cpp - Reordering of section data --------===//
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 //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements ReorderData class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler // TODO:
141a2f8336Sspaette // - make sure writable data isn't put on same cache line unless temporally
1540c2e0faSMaksim Panchenko // local
16a34c753fSRafael Auler // - estimate temporal locality by looking at CFG?
17a34c753fSRafael Auler 
18a34c753fSRafael Auler #include "bolt/Passes/ReorderData.h"
1973b89e3fSMaksim Panchenko #include "llvm/ADT/MapVector.h"
20a34c753fSRafael Auler #include <algorithm>
21a34c753fSRafael Auler 
22a34c753fSRafael Auler #undef  DEBUG_TYPE
23a34c753fSRafael Auler #define DEBUG_TYPE "reorder-data"
24a34c753fSRafael Auler 
25a34c753fSRafael Auler using namespace llvm;
26a34c753fSRafael Auler using namespace bolt;
27a34c753fSRafael Auler 
28a34c753fSRafael Auler namespace opts {
29a34c753fSRafael Auler extern cl::OptionCategory BoltCategory;
30a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
31a34c753fSRafael Auler extern cl::opt<JumpTableSupportLevel> JumpTables;
32a34c753fSRafael Auler 
33a34c753fSRafael Auler static cl::opt<bool>
34a34c753fSRafael Auler     PrintReorderedData("print-reordered-data",
35a34c753fSRafael Auler                        cl::desc("print section contents after reordering"),
36b92436efSFangrui Song                        cl::Hidden, cl::cat(BoltCategory));
37a34c753fSRafael Auler 
38a34c753fSRafael Auler cl::list<std::string>
39a34c753fSRafael Auler ReorderData("reorder-data",
40a34c753fSRafael Auler   cl::CommaSeparated,
41a34c753fSRafael Auler   cl::desc("list of sections to reorder"),
42a34c753fSRafael Auler   cl::value_desc("section1,section2,section3,..."),
43a34c753fSRafael Auler   cl::cat(BoltOptCategory));
44a34c753fSRafael Auler 
45a34c753fSRafael Auler enum ReorderAlgo : char {
46a34c753fSRafael Auler   REORDER_COUNT         = 0,
47a34c753fSRafael Auler   REORDER_FUNCS         = 1
48a34c753fSRafael Auler };
49a34c753fSRafael Auler 
50a34c753fSRafael Auler static cl::opt<ReorderAlgo>
51a34c753fSRafael Auler ReorderAlgorithm("reorder-data-algo",
52a34c753fSRafael Auler   cl::desc("algorithm used to reorder data sections"),
53a34c753fSRafael Auler   cl::init(REORDER_COUNT),
54a34c753fSRafael Auler   cl::values(
55a34c753fSRafael Auler     clEnumValN(REORDER_COUNT,
56a34c753fSRafael Auler       "count",
57a34c753fSRafael Auler       "sort hot data by read counts"),
58a34c753fSRafael Auler     clEnumValN(REORDER_FUNCS,
59a34c753fSRafael Auler       "funcs",
60a34c753fSRafael Auler       "sort hot data by hot function usage and count")),
61a34c753fSRafael Auler   cl::ZeroOrMore,
62a34c753fSRafael Auler   cl::cat(BoltOptCategory));
63a34c753fSRafael Auler 
64a34c753fSRafael Auler static cl::opt<unsigned>
65a34c753fSRafael Auler     ReorderDataMaxSymbols("reorder-data-max-symbols",
66a34c753fSRafael Auler                           cl::desc("maximum number of symbols to reorder"),
67a34c753fSRafael Auler                           cl::init(std::numeric_limits<unsigned>::max()),
68a34c753fSRafael Auler                           cl::cat(BoltOptCategory));
69a34c753fSRafael Auler 
70b92436efSFangrui Song static cl::opt<unsigned> ReorderDataMaxBytes(
71b92436efSFangrui Song     "reorder-data-max-bytes", cl::desc("maximum number of bytes to reorder"),
72b92436efSFangrui Song     cl::init(std::numeric_limits<unsigned>::max()), cl::cat(BoltOptCategory));
73a34c753fSRafael Auler 
74a34c753fSRafael Auler static cl::list<std::string>
75a34c753fSRafael Auler ReorderSymbols("reorder-symbols",
76a34c753fSRafael Auler   cl::CommaSeparated,
77a34c753fSRafael Auler   cl::desc("list of symbol names that can be reordered"),
78a34c753fSRafael Auler   cl::value_desc("symbol1,symbol2,symbol3,..."),
79a34c753fSRafael Auler   cl::Hidden,
80a34c753fSRafael Auler   cl::cat(BoltCategory));
81a34c753fSRafael Auler 
82a34c753fSRafael Auler static cl::list<std::string>
83a34c753fSRafael Auler SkipSymbols("reorder-skip-symbols",
84a34c753fSRafael Auler   cl::CommaSeparated,
85a34c753fSRafael Auler   cl::desc("list of symbol names that cannot be reordered"),
86a34c753fSRafael Auler   cl::value_desc("symbol1,symbol2,symbol3,..."),
87a34c753fSRafael Auler   cl::Hidden,
88a34c753fSRafael Auler   cl::cat(BoltCategory));
89a34c753fSRafael Auler 
90b92436efSFangrui Song static cl::opt<bool> ReorderInplace("reorder-data-inplace",
91a34c753fSRafael Auler                                     cl::desc("reorder data sections in place"),
92a34c753fSRafael Auler 
93b92436efSFangrui Song                                     cl::cat(BoltOptCategory));
94a34c753fSRafael Auler }
95a34c753fSRafael Auler 
96a34c753fSRafael Auler namespace llvm {
97a34c753fSRafael Auler namespace bolt {
98a34c753fSRafael Auler 
99a34c753fSRafael Auler namespace {
100a34c753fSRafael Auler 
101a34c753fSRafael Auler static constexpr uint16_t MinAlignment = 16;
102a34c753fSRafael Auler 
isSupported(const BinarySection & BS)10340c2e0faSMaksim Panchenko bool isSupported(const BinarySection &BS) { return BS.isData() && !BS.isTLS(); }
104a34c753fSRafael Auler 
filterSymbol(const BinaryData * BD)105a34c753fSRafael Auler bool filterSymbol(const BinaryData *BD) {
106a34c753fSRafael Auler   if (!BD->isAtomic() || BD->isJumpTable() || !BD->isMoveable())
107a34c753fSRafael Auler     return false;
108a34c753fSRafael Auler 
109a34c753fSRafael Auler   bool IsValid = true;
110a34c753fSRafael Auler 
111a34c753fSRafael Auler   if (!opts::ReorderSymbols.empty()) {
112f119a248SAmir Ayupov     IsValid = llvm::any_of(opts::ReorderSymbols, [&](const std::string &Name) {
113f119a248SAmir Ayupov       return BD->hasName(Name);
114f119a248SAmir Ayupov     });
115a34c753fSRafael Auler   }
116a34c753fSRafael Auler 
117a34c753fSRafael Auler   if (!IsValid)
118a34c753fSRafael Auler     return false;
119a34c753fSRafael Auler 
120a34c753fSRafael Auler   if (!opts::SkipSymbols.empty()) {
121a34c753fSRafael Auler     for (const std::string &Name : opts::SkipSymbols) {
122a34c753fSRafael Auler       if (BD->hasName(Name)) {
123a34c753fSRafael Auler         IsValid = false;
124a34c753fSRafael Auler         break;
125a34c753fSRafael Auler       }
126a34c753fSRafael Auler     }
127a34c753fSRafael Auler   }
128a34c753fSRafael Auler 
129a34c753fSRafael Auler   return IsValid;
130a34c753fSRafael Auler }
131a34c753fSRafael Auler 
13240c2e0faSMaksim Panchenko } // namespace
133a34c753fSRafael Auler 
134a34c753fSRafael Auler using DataOrder = ReorderData::DataOrder;
135a34c753fSRafael Auler 
printOrder(BinaryContext & BC,const BinarySection & Section,DataOrder::const_iterator Begin,DataOrder::const_iterator End) const136*52cf0711SAmir Ayupov void ReorderData::printOrder(BinaryContext &BC, const BinarySection &Section,
137a34c753fSRafael Auler                              DataOrder::const_iterator Begin,
138a34c753fSRafael Auler                              DataOrder::const_iterator End) const {
139a34c753fSRafael Auler   uint64_t TotalSize = 0;
140a34c753fSRafael Auler   bool PrintHeader = false;
141a34c753fSRafael Auler   while (Begin != End) {
142a34c753fSRafael Auler     const BinaryData *BD = Begin->first;
143a34c753fSRafael Auler 
144a34c753fSRafael Auler     if (!PrintHeader) {
145*52cf0711SAmir Ayupov       BC.outs() << "BOLT-INFO: Hot global symbols for " << Section.getName()
14640c2e0faSMaksim Panchenko                 << ":\n";
147a34c753fSRafael Auler       PrintHeader = true;
148a34c753fSRafael Auler     }
149a34c753fSRafael Auler 
150*52cf0711SAmir Ayupov     BC.outs() << "BOLT-INFO: " << *BD << ", moveable=" << BD->isMoveable()
151*52cf0711SAmir Ayupov               << format(", weight=%.5f\n",
152*52cf0711SAmir Ayupov                         double(Begin->second) / BD->getSize());
153a34c753fSRafael Auler 
154a34c753fSRafael Auler     TotalSize += BD->getSize();
155a34c753fSRafael Auler     ++Begin;
156a34c753fSRafael Auler   }
157a34c753fSRafael Auler   if (TotalSize)
158*52cf0711SAmir Ayupov     BC.outs() << "BOLT-INFO: Total hot symbol size = " << TotalSize << "\n";
159a34c753fSRafael Auler }
160a34c753fSRafael Auler 
baseOrder(BinaryContext & BC,const BinarySection & Section) const161a34c753fSRafael Auler DataOrder ReorderData::baseOrder(BinaryContext &BC,
162a34c753fSRafael Auler                                  const BinarySection &Section) const {
163a34c753fSRafael Auler   DataOrder Order;
164a34c753fSRafael Auler   for (auto &Entry : BC.getBinaryDataForSection(Section)) {
165a34c753fSRafael Auler     BinaryData *BD = Entry.second;
166a34c753fSRafael Auler     if (!BD->isAtomic()) // skip sub-symbols
167a34c753fSRafael Auler       continue;
168a34c753fSRafael Auler     auto BDCI = BinaryDataCounts.find(BD);
169a34c753fSRafael Auler     uint64_t BDCount = BDCI == BinaryDataCounts.end() ? 0 : BDCI->second;
170a34c753fSRafael Auler     Order.emplace_back(BD, BDCount);
171a34c753fSRafael Auler   }
172a34c753fSRafael Auler   return Order;
173a34c753fSRafael Auler }
174a34c753fSRafael Auler 
assignMemData(BinaryContext & BC)175a34c753fSRafael Auler void ReorderData::assignMemData(BinaryContext &BC) {
176a34c753fSRafael Auler   // Map of sections (or heap/stack) to count/size.
17773b89e3fSMaksim Panchenko   MapVector<StringRef, uint64_t> Counts;
17873b89e3fSMaksim Panchenko   MapVector<StringRef, uint64_t> JumpTableCounts;
179a34c753fSRafael Auler   uint64_t TotalCount = 0;
180a34c753fSRafael Auler   for (auto &BFI : BC.getBinaryFunctions()) {
181a34c753fSRafael Auler     const BinaryFunction &BF = BFI.second;
182a34c753fSRafael Auler     if (!BF.hasMemoryProfile())
183a34c753fSRafael Auler       continue;
184a34c753fSRafael Auler 
185a34c753fSRafael Auler     for (const BinaryBasicBlock &BB : BF) {
186a34c753fSRafael Auler       for (const MCInst &Inst : BB) {
1879966b3e7SGabriel Ravier         auto ErrorOrMemAccessProfile =
188a34c753fSRafael Auler             BC.MIB->tryGetAnnotationAs<MemoryAccessProfile>(
189a34c753fSRafael Auler                 Inst, "MemoryAccessProfile");
1909966b3e7SGabriel Ravier         if (!ErrorOrMemAccessProfile)
191a34c753fSRafael Auler           continue;
192a34c753fSRafael Auler 
193a34c753fSRafael Auler         const MemoryAccessProfile &MemAccessProfile =
1949966b3e7SGabriel Ravier             ErrorOrMemAccessProfile.get();
195a34c753fSRafael Auler         for (const AddressAccess &AccessInfo :
196a34c753fSRafael Auler              MemAccessProfile.AddressAccessInfo) {
197a34c753fSRafael Auler           if (BinaryData *BD = AccessInfo.MemoryObject) {
198a34c753fSRafael Auler             BinaryDataCounts[BD->getAtomicRoot()] += AccessInfo.Count;
199a34c753fSRafael Auler             Counts[BD->getSectionName()] += AccessInfo.Count;
200f92ab6afSAmir Ayupov             if (BD->getAtomicRoot()->isJumpTable())
201a34c753fSRafael Auler               JumpTableCounts[BD->getSectionName()] += AccessInfo.Count;
202a34c753fSRafael Auler           } else {
203a34c753fSRafael Auler             Counts["Heap/stack"] += AccessInfo.Count;
204a34c753fSRafael Auler           }
205a34c753fSRafael Auler           TotalCount += AccessInfo.Count;
206a34c753fSRafael Auler         }
207a34c753fSRafael Auler       }
208a34c753fSRafael Auler     }
209a34c753fSRafael Auler   }
210a34c753fSRafael Auler 
211a34c753fSRafael Auler   if (!Counts.empty()) {
212*52cf0711SAmir Ayupov     BC.outs() << "BOLT-INFO: Memory stats breakdown:\n";
21373b89e3fSMaksim Panchenko     for (const auto &KV : Counts) {
21473b89e3fSMaksim Panchenko       StringRef Section = KV.first;
21573b89e3fSMaksim Panchenko       const uint64_t Count = KV.second;
216*52cf0711SAmir Ayupov       BC.outs() << "BOLT-INFO:   " << Section << " = " << Count
217a34c753fSRafael Auler                 << format(" (%.1f%%)\n", 100.0 * Count / TotalCount);
218a34c753fSRafael Auler       if (JumpTableCounts.count(Section) != 0) {
219a34c753fSRafael Auler         const uint64_t JTCount = JumpTableCounts[Section];
220*52cf0711SAmir Ayupov         BC.outs() << "BOLT-INFO:     jump tables = " << JTCount
221a34c753fSRafael Auler                   << format(" (%.1f%%)\n", 100.0 * JTCount / Count);
222a34c753fSRafael Auler       }
223a34c753fSRafael Auler     }
224*52cf0711SAmir Ayupov     BC.outs() << "BOLT-INFO: Total memory events: " << TotalCount << "\n";
225a34c753fSRafael Auler   }
226a34c753fSRafael Auler }
227a34c753fSRafael Auler 
228a34c753fSRafael Auler /// Only consider moving data that is used by the hottest functions with
229a34c753fSRafael Auler /// valid profiles.
23040c2e0faSMaksim Panchenko std::pair<DataOrder, unsigned>
sortedByFunc(BinaryContext & BC,const BinarySection & Section,std::map<uint64_t,BinaryFunction> & BFs) const23140c2e0faSMaksim Panchenko ReorderData::sortedByFunc(BinaryContext &BC, const BinarySection &Section,
23240c2e0faSMaksim Panchenko                           std::map<uint64_t, BinaryFunction> &BFs) const {
233a34c753fSRafael Auler   std::map<BinaryData *, std::set<BinaryFunction *>> BDtoFunc;
234a34c753fSRafael Auler   std::map<BinaryData *, uint64_t> BDtoFuncCount;
235a34c753fSRafael Auler 
236a34c753fSRafael Auler   auto dataUses = [&BC](const BinaryFunction &BF, bool OnlyHot) {
237a34c753fSRafael Auler     std::set<BinaryData *> Uses;
238a34c753fSRafael Auler     for (const BinaryBasicBlock &BB : BF) {
239a34c753fSRafael Auler       if (OnlyHot && BB.isCold())
240a34c753fSRafael Auler         continue;
241a34c753fSRafael Auler 
242a34c753fSRafael Auler       for (const MCInst &Inst : BB) {
2439966b3e7SGabriel Ravier         auto ErrorOrMemAccessProfile =
244a34c753fSRafael Auler             BC.MIB->tryGetAnnotationAs<MemoryAccessProfile>(
245a34c753fSRafael Auler                 Inst, "MemoryAccessProfile");
2469966b3e7SGabriel Ravier         if (!ErrorOrMemAccessProfile)
247a34c753fSRafael Auler           continue;
248a34c753fSRafael Auler 
249a34c753fSRafael Auler         const MemoryAccessProfile &MemAccessProfile =
2509966b3e7SGabriel Ravier             ErrorOrMemAccessProfile.get();
251a34c753fSRafael Auler         for (const AddressAccess &AccessInfo :
252a34c753fSRafael Auler              MemAccessProfile.AddressAccessInfo) {
253a34c753fSRafael Auler           if (AccessInfo.MemoryObject)
254a34c753fSRafael Auler             Uses.insert(AccessInfo.MemoryObject);
255a34c753fSRafael Auler         }
256a34c753fSRafael Auler       }
257a34c753fSRafael Auler     }
258a34c753fSRafael Auler     return Uses;
259a34c753fSRafael Auler   };
260a34c753fSRafael Auler 
261a34c753fSRafael Auler   for (auto &Entry : BFs) {
262a34c753fSRafael Auler     BinaryFunction &BF = Entry.second;
263a34c753fSRafael Auler     if (BF.hasValidProfile()) {
264a34c753fSRafael Auler       for (BinaryData *BD : dataUses(BF, true)) {
265a34c753fSRafael Auler         if (!BC.getFunctionForSymbol(BD->getSymbol())) {
266a34c753fSRafael Auler           BDtoFunc[BD->getAtomicRoot()].insert(&BF);
267a34c753fSRafael Auler           BDtoFuncCount[BD->getAtomicRoot()] += BF.getKnownExecutionCount();
268a34c753fSRafael Auler         }
269a34c753fSRafael Auler       }
270a34c753fSRafael Auler     }
271a34c753fSRafael Auler   }
272a34c753fSRafael Auler 
273a34c753fSRafael Auler   DataOrder Order = baseOrder(BC, Section);
274a34c753fSRafael Auler   unsigned SplitPoint = Order.size();
275a34c753fSRafael Auler 
276d2c87699SAmir Ayupov   llvm::sort(
277d2c87699SAmir Ayupov       Order,
27840c2e0faSMaksim Panchenko       [&](const DataOrder::value_type &A, const DataOrder::value_type &B) {
279a34c753fSRafael Auler         // Total execution counts of functions referencing BD.
280a34c753fSRafael Auler         const uint64_t ACount = BDtoFuncCount[A.first];
281a34c753fSRafael Auler         const uint64_t BCount = BDtoFuncCount[B.first];
282a34c753fSRafael Auler         // Weight by number of loads/data size.
283a34c753fSRafael Auler         const double AWeight = double(A.second) / A.first->getSize();
284a34c753fSRafael Auler         const double BWeight = double(B.second) / B.first->getSize();
285a34c753fSRafael Auler         return (ACount > BCount ||
286a34c753fSRafael Auler                 (ACount == BCount &&
287a34c753fSRafael Auler                  (AWeight > BWeight ||
288a34c753fSRafael Auler                   (AWeight == BWeight &&
289a34c753fSRafael Auler                    A.first->getAddress() < B.first->getAddress()))));
290a34c753fSRafael Auler       });
291a34c753fSRafael Auler 
292a34c753fSRafael Auler   for (unsigned Idx = 0; Idx < Order.size(); ++Idx) {
293a34c753fSRafael Auler     if (!BDtoFuncCount[Order[Idx].first]) {
294a34c753fSRafael Auler       SplitPoint = Idx;
295a34c753fSRafael Auler       break;
296a34c753fSRafael Auler     }
297a34c753fSRafael Auler   }
298a34c753fSRafael Auler 
299a34c753fSRafael Auler   return std::make_pair(Order, SplitPoint);
300a34c753fSRafael Auler }
301a34c753fSRafael Auler 
30240c2e0faSMaksim Panchenko std::pair<DataOrder, unsigned>
sortedByCount(BinaryContext & BC,const BinarySection & Section) const30340c2e0faSMaksim Panchenko ReorderData::sortedByCount(BinaryContext &BC,
30440c2e0faSMaksim Panchenko                            const BinarySection &Section) const {
305a34c753fSRafael Auler   DataOrder Order = baseOrder(BC, Section);
306a34c753fSRafael Auler   unsigned SplitPoint = Order.size();
307a34c753fSRafael Auler 
308d2c87699SAmir Ayupov   llvm::sort(Order, [](const DataOrder::value_type &A,
309d2c87699SAmir Ayupov                        const DataOrder::value_type &B) {
310a34c753fSRafael Auler     // Weight by number of loads/data size.
311a34c753fSRafael Auler     const double AWeight = double(A.second) / A.first->getSize();
312a34c753fSRafael Auler     const double BWeight = double(B.second) / B.first->getSize();
313a34c753fSRafael Auler     return (AWeight > BWeight ||
314a34c753fSRafael Auler             (AWeight == BWeight &&
315a34c753fSRafael Auler              (A.first->getSize() < B.first->getSize() ||
316a34c753fSRafael Auler               (A.first->getSize() == B.first->getSize() &&
317a34c753fSRafael Auler                A.first->getAddress() < B.first->getAddress()))));
318a34c753fSRafael Auler   });
319a34c753fSRafael Auler 
320a34c753fSRafael Auler   for (unsigned Idx = 0; Idx < Order.size(); ++Idx) {
321a34c753fSRafael Auler     if (!Order[Idx].second) {
322a34c753fSRafael Auler       SplitPoint = Idx;
323a34c753fSRafael Auler       break;
324a34c753fSRafael Auler     }
325a34c753fSRafael Auler   }
326a34c753fSRafael Auler 
327a34c753fSRafael Auler   return std::make_pair(Order, SplitPoint);
328a34c753fSRafael Auler }
329a34c753fSRafael Auler 
330a34c753fSRafael Auler // TODO
331a34c753fSRafael Auler // add option for cache-line alignment (or just use cache-line when section
3321a2f8336Sspaette // is writable)?
setSectionOrder(BinaryContext & BC,BinarySection & OutputSection,DataOrder::iterator Begin,DataOrder::iterator End)333a34c753fSRafael Auler void ReorderData::setSectionOrder(BinaryContext &BC,
334a34c753fSRafael Auler                                   BinarySection &OutputSection,
335a34c753fSRafael Auler                                   DataOrder::iterator Begin,
336a34c753fSRafael Auler                                   DataOrder::iterator End) {
337a34c753fSRafael Auler   std::vector<BinaryData *> NewOrder;
338a34c753fSRafael Auler   unsigned NumReordered = 0;
339a34c753fSRafael Auler   uint64_t Offset = 0;
340a34c753fSRafael Auler   uint64_t Count = 0;
341a34c753fSRafael Auler 
342a34c753fSRafael Auler   // Get the total count just for stats
343a34c753fSRafael Auler   uint64_t TotalCount = 0;
344f92ab6afSAmir Ayupov   for (auto Itr = Begin; Itr != End; ++Itr)
345a34c753fSRafael Auler     TotalCount += Itr->second;
346a34c753fSRafael Auler 
347a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "BOLT-DEBUG: setSectionOrder for "
348a34c753fSRafael Auler                     << OutputSection.getName() << "\n");
349a34c753fSRafael Auler 
350a34c753fSRafael Auler   for (; Begin != End; ++Begin) {
351a34c753fSRafael Auler     BinaryData *BD = Begin->first;
352a34c753fSRafael Auler 
353933df2a4SMaksim Panchenko     // We can't move certain symbols.
354a34c753fSRafael Auler     if (!filterSymbol(BD))
355a34c753fSRafael Auler       continue;
356a34c753fSRafael Auler 
357a34c753fSRafael Auler     ++NumReordered;
358a34c753fSRafael Auler     if (NumReordered > opts::ReorderDataMaxSymbols) {
359f92ab6afSAmir Ayupov       if (!NewOrder.empty())
360a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "BOLT-DEBUG: processing ending on symbol "
361a34c753fSRafael Auler                           << *NewOrder.back() << "\n");
362a34c753fSRafael Auler       break;
363a34c753fSRafael Auler     }
364a34c753fSRafael Auler 
365a34c753fSRafael Auler     uint16_t Alignment = std::max(BD->getAlignment(), MinAlignment);
366a34c753fSRafael Auler     Offset = alignTo(Offset, Alignment);
367a34c753fSRafael Auler 
368a34c753fSRafael Auler     if ((Offset + BD->getSize()) > opts::ReorderDataMaxBytes) {
369f92ab6afSAmir Ayupov       if (!NewOrder.empty())
370a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "BOLT-DEBUG: processing ending on symbol "
371a34c753fSRafael Auler                           << *NewOrder.back() << "\n");
372a34c753fSRafael Auler       break;
373a34c753fSRafael Auler     }
374a34c753fSRafael Auler 
375a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " << BD->getName() << " @ 0x"
376a34c753fSRafael Auler                       << Twine::utohexstr(Offset) << "\n");
377a34c753fSRafael Auler 
378a34c753fSRafael Auler     BD->setOutputLocation(OutputSection, Offset);
379a34c753fSRafael Auler 
380a34c753fSRafael Auler     // reorder sub-symbols
381a34c753fSRafael Auler     for (std::pair<const uint64_t, BinaryData *> &SubBD :
382a34c753fSRafael Auler          BC.getSubBinaryData(BD)) {
383a34c753fSRafael Auler       if (!SubBD.second->isJumpTable()) {
384a34c753fSRafael Auler         uint64_t SubOffset =
385a34c753fSRafael Auler             Offset + SubBD.second->getAddress() - BD->getAddress();
386a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "BOLT-DEBUG: SubBD " << SubBD.second->getName()
387a34c753fSRafael Auler                           << " @ " << SubOffset << "\n");
388a34c753fSRafael Auler         SubBD.second->setOutputLocation(OutputSection, SubOffset);
389a34c753fSRafael Auler       }
390a34c753fSRafael Auler     }
391a34c753fSRafael Auler 
392a34c753fSRafael Auler     Offset += BD->getSize();
393a34c753fSRafael Auler     Count += Begin->second;
394a34c753fSRafael Auler     NewOrder.push_back(BD);
395a34c753fSRafael Auler   }
396a34c753fSRafael Auler 
397a34c753fSRafael Auler   OutputSection.reorderContents(NewOrder, opts::ReorderInplace);
398a34c753fSRafael Auler 
399*52cf0711SAmir Ayupov   BC.outs() << "BOLT-INFO: reorder-data: " << Count << "/" << TotalCount
400a34c753fSRafael Auler             << format(" (%.1f%%)", 100.0 * Count / TotalCount) << " events, "
401a34c753fSRafael Auler             << Offset << " hot bytes\n";
402a34c753fSRafael Auler }
403a34c753fSRafael Auler 
markUnmoveableSymbols(BinaryContext & BC,BinarySection & Section) const404a34c753fSRafael Auler bool ReorderData::markUnmoveableSymbols(BinaryContext &BC,
405a34c753fSRafael Auler                                         BinarySection &Section) const {
406a34c753fSRafael Auler   // Private symbols currently can't be moved because data can "leak" across
407a34c753fSRafael Auler   // the boundary of one symbol to the next, e.g. a string that has a common
408a34c753fSRafael Auler   // suffix might start in one private symbol and end with the common
409a34c753fSRafael Auler   // suffix in another.
410a34c753fSRafael Auler   auto isPrivate = [&](const BinaryData *BD) {
411a34c753fSRafael Auler     auto Prefix = std::string("PG") + BC.AsmInfo->getPrivateGlobalPrefix();
412ad8fd5b1SKazu Hirata     return BD->getName().starts_with(Prefix.str());
413a34c753fSRafael Auler   };
414a34c753fSRafael Auler   auto Range = BC.getBinaryDataForSection(Section);
415a34c753fSRafael Auler   bool FoundUnmoveable = false;
416a34c753fSRafael Auler   for (auto Itr = Range.begin(); Itr != Range.end(); ++Itr) {
4179c99e9fdSSinan Lin     BinaryData *Next =
4189c99e9fdSSinan Lin         std::next(Itr) != Range.end() ? std::next(Itr)->second : nullptr;
419ad8fd5b1SKazu Hirata     if (Itr->second->getName().starts_with("PG.")) {
420a34c753fSRafael Auler       BinaryData *Prev =
421a34c753fSRafael Auler           Itr != Range.begin() ? std::prev(Itr)->second : nullptr;
422a34c753fSRafael Auler       bool PrevIsPrivate = Prev && isPrivate(Prev);
423a34c753fSRafael Auler       bool NextIsPrivate = Next && isPrivate(Next);
424a34c753fSRafael Auler       if (isPrivate(Itr->second) && (PrevIsPrivate || NextIsPrivate))
425a34c753fSRafael Auler         Itr->second->setIsMoveable(false);
426a34c753fSRafael Auler     } else {
427a34c753fSRafael Auler       // check for overlapping symbols.
42840c2e0faSMaksim Panchenko       if (Next && Itr->second->getEndAddress() != Next->getAddress() &&
429a34c753fSRafael Auler           Next->containsAddress(Itr->second->getEndAddress())) {
430a34c753fSRafael Auler         Itr->second->setIsMoveable(false);
431a34c753fSRafael Auler         Next->setIsMoveable(false);
432a34c753fSRafael Auler       }
433a34c753fSRafael Auler     }
434a34c753fSRafael Auler     FoundUnmoveable |= !Itr->second->isMoveable();
435a34c753fSRafael Auler   }
436a34c753fSRafael Auler   return FoundUnmoveable;
437a34c753fSRafael Auler }
438a34c753fSRafael Auler 
runOnFunctions(BinaryContext & BC)439a5f3d1a8SAmir Ayupov Error ReorderData::runOnFunctions(BinaryContext &BC) {
44040c2e0faSMaksim Panchenko   static const char *DefaultSections[] = {".rodata", ".data", ".bss", nullptr};
441a34c753fSRafael Auler 
442a34c753fSRafael Auler   if (!BC.HasRelocations || opts::ReorderData.empty())
443a5f3d1a8SAmir Ayupov     return Error::success();
444a34c753fSRafael Auler 
445a34c753fSRafael Auler   // For now
446a34c753fSRafael Auler   if (opts::JumpTables > JTS_BASIC) {
447*52cf0711SAmir Ayupov     BC.outs() << "BOLT-WARNING: jump table support must be basic for "
448a34c753fSRafael Auler               << "data reordering to work.\n";
449a5f3d1a8SAmir Ayupov     return Error::success();
450a34c753fSRafael Auler   }
451a34c753fSRafael Auler 
452a34c753fSRafael Auler   assignMemData(BC);
453a34c753fSRafael Auler 
454a34c753fSRafael Auler   std::vector<BinarySection *> Sections;
455a34c753fSRafael Auler 
456a34c753fSRafael Auler   for (const std::string &SectionName : opts::ReorderData) {
457a34c753fSRafael Auler     if (SectionName == "default") {
458f92ab6afSAmir Ayupov       for (unsigned I = 0; DefaultSections[I]; ++I)
459a34c753fSRafael Auler         if (ErrorOr<BinarySection &> Section =
460a34c753fSRafael Auler                 BC.getUniqueSectionByName(DefaultSections[I]))
461a34c753fSRafael Auler           Sections.push_back(&*Section);
462a34c753fSRafael Auler       continue;
463a34c753fSRafael Auler     }
464a34c753fSRafael Auler 
465a34c753fSRafael Auler     ErrorOr<BinarySection &> Section = BC.getUniqueSectionByName(SectionName);
466a34c753fSRafael Auler     if (!Section) {
467*52cf0711SAmir Ayupov       BC.outs() << "BOLT-WARNING: Section " << SectionName
468a34c753fSRafael Auler                 << " not found, skipping.\n";
469a34c753fSRafael Auler       continue;
470a34c753fSRafael Auler     }
471a34c753fSRafael Auler 
472a34c753fSRafael Auler     if (!isSupported(*Section)) {
473*52cf0711SAmir Ayupov       BC.errs() << "BOLT-ERROR: Section " << SectionName << " not supported.\n";
474*52cf0711SAmir Ayupov       return createFatalBOLTError("");
475a34c753fSRafael Auler     }
476a34c753fSRafael Auler 
477a34c753fSRafael Auler     Sections.push_back(&*Section);
478a34c753fSRafael Auler   }
479a34c753fSRafael Auler 
480a34c753fSRafael Auler   for (BinarySection *Section : Sections) {
481a34c753fSRafael Auler     const bool FoundUnmoveable = markUnmoveableSymbols(BC, *Section);
482a34c753fSRafael Auler 
483a34c753fSRafael Auler     DataOrder Order;
484a34c753fSRafael Auler     unsigned SplitPointIdx;
485a34c753fSRafael Auler 
486a34c753fSRafael Auler     if (opts::ReorderAlgorithm == opts::ReorderAlgo::REORDER_COUNT) {
487*52cf0711SAmir Ayupov       BC.outs() << "BOLT-INFO: reorder-sections: ordering data by count\n";
488a34c753fSRafael Auler       std::tie(Order, SplitPointIdx) = sortedByCount(BC, *Section);
489a34c753fSRafael Auler     } else {
490*52cf0711SAmir Ayupov       BC.outs() << "BOLT-INFO: reorder-sections: ordering data by funcs\n";
491a34c753fSRafael Auler       std::tie(Order, SplitPointIdx) =
492a34c753fSRafael Auler           sortedByFunc(BC, *Section, BC.getBinaryFunctions());
493a34c753fSRafael Auler     }
494a34c753fSRafael Auler     auto SplitPoint = Order.begin() + SplitPointIdx;
495a34c753fSRafael Auler 
496f92ab6afSAmir Ayupov     if (opts::PrintReorderedData)
497*52cf0711SAmir Ayupov       printOrder(BC, *Section, Order.begin(), SplitPoint);
498a34c753fSRafael Auler 
499a34c753fSRafael Auler     if (!opts::ReorderInplace || FoundUnmoveable) {
500f92ab6afSAmir Ayupov       if (opts::ReorderInplace && FoundUnmoveable)
501*52cf0711SAmir Ayupov         BC.outs() << "BOLT-INFO: Found unmoveable symbols in "
502a34c753fSRafael Auler                   << Section->getName() << " falling back to splitting "
503a34c753fSRafael Auler                   << "instead of in-place reordering.\n";
504a34c753fSRafael Auler 
5054d3a0cadSMaksim Panchenko       // Rename sections.
5064d3a0cadSMaksim Panchenko       BinarySection &Hot =
5074d3a0cadSMaksim Panchenko           BC.registerSection(Section->getName() + ".hot", *Section);
5084d3a0cadSMaksim Panchenko       Hot.setOutputName(Section->getName());
5094d3a0cadSMaksim Panchenko       Section->setOutputName(".bolt.org" + Section->getName());
510a34c753fSRafael Auler 
511a34c753fSRafael Auler       // Reorder contents of original section.
5124d3a0cadSMaksim Panchenko       setSectionOrder(BC, Hot, Order.begin(), SplitPoint);
513a34c753fSRafael Auler 
514a34c753fSRafael Auler       // This keeps the original data from thinking it has been moved.
515a34c753fSRafael Auler       for (std::pair<const uint64_t, BinaryData *> &Entry :
516a34c753fSRafael Auler            BC.getBinaryDataForSection(*Section)) {
517a34c753fSRafael Auler         if (!Entry.second->isMoved()) {
5184d3a0cadSMaksim Panchenko           Entry.second->setSection(*Section);
5194d3a0cadSMaksim Panchenko           Entry.second->setOutputSection(*Section);
520a34c753fSRafael Auler         }
521a34c753fSRafael Auler       }
522a34c753fSRafael Auler     } else {
523*52cf0711SAmir Ayupov       BC.outs()
524*52cf0711SAmir Ayupov           << "BOLT-WARNING: Inplace section reordering not supported yet.\n";
525a34c753fSRafael Auler       setSectionOrder(BC, *Section, Order.begin(), Order.end());
526a34c753fSRafael Auler     }
527a34c753fSRafael Auler   }
528a5f3d1a8SAmir Ayupov   return Error::success();
529a34c753fSRafael Auler }
530a34c753fSRafael Auler 
53140c2e0faSMaksim Panchenko } // namespace bolt
53240c2e0faSMaksim Panchenko } // namespace llvm
533