|
27 | 27 | #include "llvm/Support/Path.h" |
28 | 28 | #include "llvm/Support/TimeProfiler.h" |
29 | 29 | #include "llvm/Support/raw_ostream.h" |
| 30 | +#include "llvm/Support/xxhash.h" |
30 | 31 |
|
31 | 32 | #include <numeric> |
32 | 33 |
|
@@ -246,33 +247,45 @@ DenseMap<const InputSection *, int> CallGraphSort::run() { |
246 | 247 | return orderMap; |
247 | 248 | } |
248 | 249 |
|
249 | | -std::optional<int> |
250 | | -macho::PriorityBuilder::getSymbolOrCStringPriority(const StringRef key, |
251 | | - InputFile *f) { |
| 250 | +void macho::PriorityBuilder::SymbolPriorityEntry::setPriority( |
| 251 | + int priority, StringRef objectFile) { |
| 252 | + if (!objectFile.empty()) |
| 253 | + objectFiles.try_emplace(objectFile, priority); |
| 254 | + else |
| 255 | + anyObjectFile = std::min(anyObjectFile, priority); |
| 256 | +} |
252 | 257 |
|
253 | | - auto it = priorities.find(key); |
254 | | - if (it == priorities.end()) |
255 | | - return std::nullopt; |
256 | | - const SymbolPriorityEntry &entry = it->second; |
| 258 | +int macho::PriorityBuilder::SymbolPriorityEntry::getPriority( |
| 259 | + const InputFile *f) const { |
257 | 260 | if (!f) |
258 | | - return entry.anyObjectFile; |
| 261 | + return anyObjectFile; |
259 | 262 | // We don't use toString(InputFile *) here because it returns the full path |
260 | 263 | // for object files, and we only want the basename. |
261 | | - StringRef filename; |
262 | | - if (f->archiveName.empty()) |
263 | | - filename = path::filename(f->getName()); |
264 | | - else |
265 | | - filename = saver().save(path::filename(f->archiveName) + "(" + |
266 | | - path::filename(f->getName()) + ")"); |
267 | | - return std::min(entry.objectFiles.lookup(filename), entry.anyObjectFile); |
| 264 | + StringRef basename = path::filename(f->getName()); |
| 265 | + StringRef filename = |
| 266 | + f->archiveName.empty() |
| 267 | + ? basename |
| 268 | + : saver().save(path::filename(f->archiveName) + "(" + basename + ")"); |
| 269 | + return std::min(objectFiles.lookup(filename), anyObjectFile); |
268 | 270 | } |
269 | 271 |
|
270 | 272 | std::optional<int> |
271 | | -macho::PriorityBuilder::getSymbolPriority(const Defined *sym) { |
| 273 | +macho::PriorityBuilder::getCStringPriority(uint32_t hash, |
| 274 | + const InputFile *f) const { |
| 275 | + auto it = cStringPriorities.find(hash); |
| 276 | + if (it == cStringPriorities.end()) |
| 277 | + return std::nullopt; |
| 278 | + return it->second.getPriority(f); |
| 279 | +} |
| 280 | + |
| 281 | +std::optional<int> |
| 282 | +macho::PriorityBuilder::getSymbolPriority(const Defined *sym) const { |
272 | 283 | if (sym->isAbsolute()) |
273 | 284 | return std::nullopt; |
274 | | - return getSymbolOrCStringPriority(utils::getRootSymbol(sym->getName()), |
275 | | - sym->isec()->getFile()); |
| 285 | + auto it = priorities.find(utils::getRootSymbol(sym->getName())); |
| 286 | + if (it == priorities.end()) |
| 287 | + return std::nullopt; |
| 288 | + return it->second.getPriority(sym->isec()->getFile()); |
276 | 289 | } |
277 | 290 |
|
278 | 291 | void macho::PriorityBuilder::extractCallGraphProfile() { |
@@ -307,7 +320,7 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) { |
307 | 320 | int prio = std::numeric_limits<int>::min(); |
308 | 321 | MemoryBufferRef mbref = *buffer; |
309 | 322 | for (StringRef line : args::getLines(mbref)) { |
310 | | - StringRef objectFile, symbolOrCStrHash; |
| 323 | + StringRef objectFile; |
311 | 324 | line = line.take_until([](char c) { return c == '#'; }); // ignore comments |
312 | 325 | line = line.ltrim(); |
313 | 326 |
|
@@ -338,22 +351,16 @@ void macho::PriorityBuilder::parseOrderFile(StringRef path) { |
338 | 351 | } |
339 | 352 |
|
340 | 353 | // The rest of the line is either <symbol name> or |
341 | | - // CStringEntryPrefix<cstring hash> |
| 354 | + // cStringEntryPrefix<cstring hash> |
342 | 355 | line = line.trim(); |
343 | | - if (line.starts_with(CStringEntryPrefix)) { |
344 | | - StringRef possibleHash = line.drop_front(CStringEntryPrefix.size()); |
| 356 | + if (line.consume_front(cStringEntryPrefix)) { |
345 | 357 | uint32_t hash = 0; |
346 | | - if (to_integer(possibleHash, hash)) |
347 | | - symbolOrCStrHash = possibleHash; |
348 | | - } else |
349 | | - symbolOrCStrHash = utils::getRootSymbol(line); |
350 | | - |
351 | | - if (!symbolOrCStrHash.empty()) { |
352 | | - SymbolPriorityEntry &entry = priorities[symbolOrCStrHash]; |
353 | | - if (!objectFile.empty()) |
354 | | - entry.objectFiles.insert(std::make_pair(objectFile, prio)); |
355 | | - else |
356 | | - entry.anyObjectFile = std::min(entry.anyObjectFile, prio); |
| 358 | + if (to_integer(line, hash)) |
| 359 | + cStringPriorities[hash].setPriority(prio, objectFile); |
| 360 | + } else { |
| 361 | + StringRef symbol = utils::getRootSymbol(line); |
| 362 | + if (!symbol.empty()) |
| 363 | + priorities[symbol].setPriority(prio, objectFile); |
357 | 364 | } |
358 | 365 |
|
359 | 366 | ++prio; |
@@ -405,40 +412,39 @@ macho::PriorityBuilder::buildInputSectionPriorities() { |
405 | 412 | return sectionPriorities; |
406 | 413 | } |
407 | 414 |
|
408 | | -std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities( |
409 | | - ArrayRef<CStringInputSection *> inputs) { |
410 | | - // Split the input strings into hold and cold sets. |
411 | | - // Order hot set based on -order_file_cstring for performance improvement; |
412 | | - // TODO: Order cold set of cstrings for compression via BP. |
413 | | - std::vector<std::pair<int, StringPiecePair>> |
414 | | - hotStringPrioritiesAndStringPieces; |
415 | | - std::vector<StringPiecePair> coldStringPieces; |
416 | | - std::vector<StringPiecePair> orderedStringPieces; |
417 | | - |
| 415 | +void macho::PriorityBuilder::forEachStringPiece( |
| 416 | + ArrayRef<CStringInputSection *> inputs, |
| 417 | + std::function<void(CStringInputSection &, StringPiece &, size_t)> f, |
| 418 | + bool forceInputOrder, bool computeHash) const { |
| 419 | + std::vector<std::tuple<int, CStringInputSection *, size_t>> orderedPieces; |
| 420 | + std::vector<std::pair<CStringInputSection *, size_t>> unorderedPieces; |
418 | 421 | for (CStringInputSection *isec : inputs) { |
419 | 422 | for (const auto &[stringPieceIdx, piece] : llvm::enumerate(isec->pieces)) { |
420 | 423 | if (!piece.live) |
421 | 424 | continue; |
422 | | - |
423 | | - std::optional<int> priority = getSymbolOrCStringPriority( |
424 | | - std::to_string(piece.hash), isec->getFile()); |
425 | | - if (!priority) |
426 | | - coldStringPieces.emplace_back(isec, stringPieceIdx); |
| 425 | + // Process pieces in input order if we have no cstrings in our orderfile |
| 426 | + if (forceInputOrder || cStringPriorities.empty()) { |
| 427 | + f(*isec, piece, stringPieceIdx); |
| 428 | + continue; |
| 429 | + } |
| 430 | + uint32_t hash = |
| 431 | + computeHash |
| 432 | + ? (xxh3_64bits(isec->getStringRef(stringPieceIdx)) & 0x7fffffff) |
| 433 | + : piece.hash; |
| 434 | + if (auto priority = getCStringPriority(hash, isec->getFile())) |
| 435 | + orderedPieces.emplace_back(*priority, isec, stringPieceIdx); |
427 | 436 | else |
428 | | - hotStringPrioritiesAndStringPieces.emplace_back( |
429 | | - *priority, std::make_pair(isec, stringPieceIdx)); |
| 437 | + unorderedPieces.emplace_back(isec, stringPieceIdx); |
430 | 438 | } |
431 | 439 | } |
432 | | - |
433 | | - // Order hot set for perf |
434 | | - llvm::stable_sort(hotStringPrioritiesAndStringPieces); |
435 | | - for (auto &[priority, stringPiecePair] : hotStringPrioritiesAndStringPieces) |
436 | | - orderedStringPieces.push_back(stringPiecePair); |
437 | | - |
438 | | - // TODO: Order cold set for compression |
439 | | - |
440 | | - orderedStringPieces.insert(orderedStringPieces.end(), |
441 | | - coldStringPieces.begin(), coldStringPieces.end()); |
442 | | - |
443 | | - return orderedStringPieces; |
| 440 | + if (orderedPieces.empty() && unorderedPieces.empty()) |
| 441 | + return; |
| 442 | + llvm::stable_sort(orderedPieces, [](const auto &left, const auto &right) { |
| 443 | + return std::get<0>(left) < std::get<0>(right); |
| 444 | + }); |
| 445 | + for (auto &[priority, isec, pieceIdx] : orderedPieces) |
| 446 | + f(*isec, isec->pieces[pieceIdx], pieceIdx); |
| 447 | + // TODO: Add option to order the remaining cstrings for compression |
| 448 | + for (auto &[isec, pieceIdx] : unorderedPieces) |
| 449 | + f(*isec, isec->pieces[pieceIdx], pieceIdx); |
444 | 450 | } |
0 commit comments