Skip to content

Commit 4d0a735

Browse files
author
Sharon Xu
committed
[lld] Support order cstrings with -order_file_cstring
1 parent 8e53e3b commit 4d0a735

File tree

7 files changed

+359
-38
lines changed

7 files changed

+359
-38
lines changed

lld/MachO/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ struct Configuration {
225225
bool callGraphProfileSort = false;
226226
llvm::StringRef printSymbolOrder;
227227

228+
llvm::StringRef cStringOrderFilePath;
228229
llvm::StringRef irpgoProfilePath;
229230
bool bpStartupFunctionSort = false;
230231
bool bpCompressionSortStartupFunctions = false;

lld/MachO/Driver.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,15 @@ static InputFile *addFile(StringRef path, LoadType loadType,
337337
for (const object::Archive::Child &c : file->getArchive().children(e)) {
338338
StringRef reason;
339339
switch (loadType) {
340-
case LoadType::LCLinkerOption:
341-
reason = "LC_LINKER_OPTION";
342-
break;
343-
case LoadType::CommandLineForce:
344-
reason = "-force_load";
345-
break;
346-
case LoadType::CommandLine:
347-
reason = "-all_load";
348-
break;
340+
case LoadType::LCLinkerOption:
341+
reason = "LC_LINKER_OPTION";
342+
break;
343+
case LoadType::CommandLineForce:
344+
reason = "-force_load";
345+
break;
346+
case LoadType::CommandLine:
347+
reason = "-all_load";
348+
break;
349349
}
350350
if (Error e = file->fetch(c, reason)) {
351351
if (config->warnThinArchiveMissingMembers)
@@ -2178,6 +2178,9 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
21782178
StringRef orderFile = args.getLastArgValue(OPT_order_file);
21792179
if (!orderFile.empty())
21802180
priorityBuilder.parseOrderFile(orderFile);
2181+
config->cStringOrderFilePath = args.getLastArgValue(OPT_order_file_cstring);
2182+
if (!config->cStringOrderFilePath.empty())
2183+
priorityBuilder.parseOrderFileCString(config->cStringOrderFilePath);
21812184

21822185
referenceStubBinder();
21832186

lld/MachO/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,10 @@ def order_file : Separate<["-"], "order_file">,
400400
MetaVarName<"<file>">,
401401
HelpText<"Layout functions and data according to specification in <file>">,
402402
Group<grp_opts>;
403+
def order_file_cstring : Separate<["-"], "order_file_cstring">,
404+
MetaVarName<"<file>">,
405+
HelpText<"Layout cstrings according to specification in <file>">,
406+
Group<grp_opts>;
403407
def no_order_inits : Flag<["-"], "no_order_inits">,
404408
HelpText<"Disable default reordering of initializer and terminator functions">,
405409
Flags<[HelpHidden]>,

lld/MachO/SectionPriorities.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,3 +388,74 @@ macho::PriorityBuilder::buildInputSectionPriorities() {
388388

389389
return sectionPriorities;
390390
}
391+
392+
void macho::PriorityBuilder::parseOrderFileCString(StringRef path) {
393+
std::optional<MemoryBufferRef> buffer = readFile(path);
394+
if (!buffer) {
395+
error("Could not read cstring order file at " + path);
396+
return;
397+
}
398+
MemoryBufferRef mbref = *buffer;
399+
int priority = std::numeric_limits<int>::min();
400+
for (StringRef line : args::getLines(mbref)) {
401+
if (line.empty())
402+
continue;
403+
uint32_t hash = 0;
404+
if (!to_integer(line, hash))
405+
continue;
406+
auto it = cStringPriorities.find(hash);
407+
if (it == cStringPriorities.end())
408+
cStringPriorities[hash] = ++priority;
409+
else
410+
assert(it->second <= priority);
411+
}
412+
}
413+
414+
std::vector<StringPiecePair> macho::PriorityBuilder::buildCStringPriorities(
415+
ArrayRef<CStringInputSection *> inputs) {
416+
std::vector<StringPiecePair> orderedStringPieces;
417+
if (config->cStringOrderFilePath.empty()) {
418+
for (CStringInputSection *isec : inputs) {
419+
for (const auto &[stringPieceIdx, piece] :
420+
llvm::enumerate(isec->pieces)) {
421+
if (!piece.live)
422+
continue;
423+
orderedStringPieces.emplace_back(isec, stringPieceIdx);
424+
}
425+
}
426+
return orderedStringPieces;
427+
}
428+
429+
// Split the input strings into hold and cold sets.
430+
// Order hot set based on -order_file_cstring for performance improvement;
431+
// TODO: Order cold set of cstrings for compression via BP.
432+
std::vector<std::pair<int, StringPiecePair>>
433+
hotStringPrioritiesAndStringPieces;
434+
std::vector<StringPiecePair> coldStringPieces;
435+
436+
for (CStringInputSection *isec : inputs) {
437+
for (const auto &[stringPieceIdx, piece] : llvm::enumerate(isec->pieces)) {
438+
if (!piece.live)
439+
continue;
440+
441+
auto it = cStringPriorities.find(piece.hash);
442+
if (it != cStringPriorities.end())
443+
hotStringPrioritiesAndStringPieces.emplace_back(
444+
it->second, std::make_pair(isec, stringPieceIdx));
445+
else
446+
coldStringPieces.emplace_back(isec, stringPieceIdx);
447+
}
448+
}
449+
450+
// Order hot set for perf
451+
llvm::stable_sort(hotStringPrioritiesAndStringPieces);
452+
for (auto &[priority, stringPiecePair] : hotStringPrioritiesAndStringPieces)
453+
orderedStringPieces.push_back(stringPiecePair);
454+
455+
// TODO: Order cold set for compression
456+
457+
orderedStringPieces.insert(orderedStringPieces.end(),
458+
coldStringPieces.begin(), coldStringPieces.end());
459+
460+
return orderedStringPieces;
461+
}

lld/MachO/SectionPriorities.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace lld::macho {
1717

1818
using SectionPair = std::pair<const InputSection *, const InputSection *>;
19+
using StringPiecePair = std::pair<CStringInputSection *, size_t>;
1920

2021
class PriorityBuilder {
2122
public:
@@ -55,6 +56,23 @@ class PriorityBuilder {
5556
// contains.
5657
llvm::DenseMap<const InputSection *, int> buildInputSectionPriorities();
5758

59+
// Reads the cstring order file at `path` into cStringPriorities.
60+
// An cstring order file has one entry per line, in the following format:
61+
//
62+
// <hash of cstring literal content>
63+
//
64+
// Cstring literals are not symbolized, we can't identify them by name
65+
// However, cstrings are deduplicated, hence unique, so we use the hash of
66+
// the content of cstring literals to identify them and assign priority to it.
67+
// We use the same hash as used in StringPiece, i.e. 31 bit:
68+
// xxh3_64bits(string) & 0x7fffffff
69+
//
70+
// Additionally, given they are deduplicated and unique, we don't need to know
71+
// which object file they are from.
72+
void parseOrderFileCString(StringRef path);
73+
std::vector<StringPiecePair>
74+
buildCStringPriorities(ArrayRef<CStringInputSection *>);
75+
5876
private:
5977
// The symbol with the smallest priority should be ordered first in the output
6078
// section (modulo input section contiguity constraints).
@@ -68,6 +86,8 @@ class PriorityBuilder {
6886

6987
std::optional<int> getSymbolPriority(const Defined *sym);
7088
llvm::DenseMap<llvm::StringRef, SymbolPriorityEntry> priorities;
89+
/// A map from cstring literal hashes to priorities
90+
llvm::DenseMap<uint32_t, int> cStringPriorities;
7191
llvm::MapVector<SectionPair, uint64_t> callGraphProfile;
7292
};
7393

lld/MachO/SyntheticSections.cpp

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "MachOStructs.h"
1616
#include "ObjC.h"
1717
#include "OutputSegment.h"
18+
#include "SectionPriorities.h"
1819
#include "SymbolTable.h"
1920
#include "Symbols.h"
2021

@@ -1766,26 +1767,25 @@ void DeduplicatedCStringSection::finalizeContents() {
17661767
}
17671768
}
17681769

1769-
// Assign an offset for each string and save it to the corresponding
1770+
// Sort the strings for performance and compression size win, and then
1771+
// assign an offset for each string and save it to the corresponding
17701772
// StringPieces for easy access.
1771-
for (CStringInputSection *isec : inputs) {
1772-
for (const auto &[i, piece] : llvm::enumerate(isec->pieces)) {
1773-
if (!piece.live)
1774-
continue;
1775-
auto s = isec->getCachedHashStringRef(i);
1776-
auto it = stringOffsetMap.find(s);
1777-
assert(it != stringOffsetMap.end());
1778-
StringOffset &offsetInfo = it->second;
1779-
if (offsetInfo.outSecOff == UINT64_MAX) {
1780-
offsetInfo.outSecOff =
1781-
alignToPowerOf2(size, 1ULL << offsetInfo.trailingZeros);
1782-
size =
1783-
offsetInfo.outSecOff + s.size() + 1; // account for null terminator
1784-
}
1785-
piece.outSecOff = offsetInfo.outSecOff;
1773+
for (auto &[isec, i] : priorityBuilder.buildCStringPriorities(inputs)) {
1774+
auto &piece = isec->pieces[i];
1775+
auto s = isec->getCachedHashStringRef(i);
1776+
auto it = stringOffsetMap.find(s);
1777+
assert(it != stringOffsetMap.end());
1778+
lld::macho::DeduplicatedCStringSection::StringOffset &offsetInfo =
1779+
it->second;
1780+
if (offsetInfo.outSecOff == UINT64_MAX) {
1781+
offsetInfo.outSecOff =
1782+
alignToPowerOf2(size, 1ULL << offsetInfo.trailingZeros);
1783+
size = offsetInfo.outSecOff + s.size() + 1; // account for null terminator
17861784
}
1787-
isec->isFinal = true;
1785+
piece.outSecOff = offsetInfo.outSecOff;
17881786
}
1787+
for (CStringInputSection *isec : inputs)
1788+
isec->isFinal = true;
17891789
}
17901790

17911791
void DeduplicatedCStringSection::writeTo(uint8_t *buf) const {
@@ -1908,18 +1908,18 @@ ObjCImageInfoSection::parseImageInfo(const InputFile *file) {
19081908

19091909
static std::string swiftVersionString(uint8_t version) {
19101910
switch (version) {
1911-
case 1:
1912-
return "1.0";
1913-
case 2:
1914-
return "1.1";
1915-
case 3:
1916-
return "2.0";
1917-
case 4:
1918-
return "3.0";
1919-
case 5:
1920-
return "4.0";
1921-
default:
1922-
return ("0x" + Twine::utohexstr(version)).str();
1911+
case 1:
1912+
return "1.0";
1913+
case 2:
1914+
return "1.1";
1915+
case 3:
1916+
return "2.0";
1917+
case 4:
1918+
return "3.0";
1919+
case 5:
1920+
return "4.0";
1921+
default:
1922+
return ("0x" + Twine::utohexstr(version)).str();
19231923
}
19241924
}
19251925

0 commit comments

Comments
 (0)