Skip to content

Commit 00c0b1a

Browse files
authored
[CGData] LLD for MachO (#90166)
It reads raw CG data encoded in the custom section (__llvm_outline) in object files and merges them into the indexed codegen data file specified by `-codegen-data-generate-path={path}`. This depends on #90074. This is a patch for https://discourse.llvm.org/t/rfc-enhanced-machine-outliner-part-2-thinlto-nolto/78753.
1 parent cebc130 commit 00c0b1a

File tree

7 files changed

+135
-0
lines changed

7 files changed

+135
-0
lines changed

lld/MachO/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct Configuration {
210210
std::vector<SectionAlign> sectionAlignments;
211211
std::vector<SegmentProtection> segmentProtections;
212212
bool ltoDebugPassManager = false;
213+
llvm::StringRef codegenDataGeneratePath;
213214
bool csProfileGenerate = false;
214215
llvm::StringRef csProfilePath;
215216
bool pgoWarnMismatch;

lld/MachO/Driver.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/ADT/StringRef.h"
3737
#include "llvm/BinaryFormat/MachO.h"
3838
#include "llvm/BinaryFormat/Magic.h"
39+
#include "llvm/CGData/CodeGenDataWriter.h"
3940
#include "llvm/Config/llvm-config.h"
4041
#include "llvm/LTO/LTO.h"
4142
#include "llvm/Object/Archive.h"
@@ -1322,6 +1323,37 @@ static void gatherInputSections() {
13221323
}
13231324
}
13241325

1326+
static void codegenDataGenerate() {
1327+
TimeTraceScope timeScope("Generating codegen data");
1328+
1329+
OutlinedHashTreeRecord globalOutlineRecord;
1330+
for (ConcatInputSection *isec : inputSections)
1331+
if (isec->getSegName() == segment_names::data &&
1332+
isec->getName() == section_names::outlinedHashTree) {
1333+
// Read outlined hash tree from each section.
1334+
OutlinedHashTreeRecord localOutlineRecord;
1335+
auto *data = isec->data.data();
1336+
localOutlineRecord.deserialize(data);
1337+
1338+
// Merge it to the global hash tree.
1339+
globalOutlineRecord.merge(localOutlineRecord);
1340+
}
1341+
1342+
CodeGenDataWriter Writer;
1343+
if (!globalOutlineRecord.empty())
1344+
Writer.addRecord(globalOutlineRecord);
1345+
1346+
std::error_code EC;
1347+
auto fileName = config->codegenDataGeneratePath;
1348+
assert(!fileName.empty());
1349+
raw_fd_ostream Output(fileName, EC, sys::fs::OF_None);
1350+
if (EC)
1351+
error("fail to create " + fileName + ": " + EC.message());
1352+
1353+
if (auto E = Writer.write(Output))
1354+
error("fail to write CGData: " + toString(std::move(E)));
1355+
}
1356+
13251357
static void foldIdenticalLiterals() {
13261358
TimeTraceScope timeScope("Fold identical literals");
13271359
// We always create a cStringSection, regardless of whether dedupLiterals is
@@ -1759,6 +1791,8 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
17591791
config->ignoreAutoLinkOptions.insert(arg->getValue());
17601792
config->strictAutoLink = args.hasArg(OPT_strict_auto_link);
17611793
config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
1794+
config->codegenDataGeneratePath =
1795+
args.getLastArgValue(OPT_codegen_data_generate_path);
17621796
config->csProfileGenerate = args.hasArg(OPT_cs_profile_generate);
17631797
config->csProfilePath = args.getLastArgValue(OPT_cs_profile_path);
17641798
config->pgoWarnMismatch =
@@ -2103,6 +2137,10 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
21032137
}
21042138

21052139
gatherInputSections();
2140+
2141+
if (!config->codegenDataGeneratePath.empty())
2142+
codegenDataGenerate();
2143+
21062144
if (config->callGraphProfileSort)
21072145
priorityBuilder.extractCallGraphProfile();
21082146

lld/MachO/InputSection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ constexpr const char objcMethname[] = "__objc_methname";
354354
constexpr const char objcNonLazyCatList[] = "__objc_nlcatlist";
355355
constexpr const char objcNonLazyClassList[] = "__objc_nlclslist";
356356
constexpr const char objcProtoList[] = "__objc_protolist";
357+
constexpr const char outlinedHashTree[] = "__llvm_outline";
357358
constexpr const char pageZero[] = "__pagezero";
358359
constexpr const char pointers[] = "__pointers";
359360
constexpr const char rebase[] = "__rebase";

lld/MachO/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">,
162162
Group<grp_lld>;
163163
def lto_debug_pass_manager: Flag<["--"], "lto-debug-pass-manager">,
164164
HelpText<"Debug new pass manager">, Group<grp_lld>;
165+
def codegen_data_generate_path : Separate<["--"], "codegen-data-generate-path">, Group<grp_lld>;
166+
def codegen_data_generate_path_eq : Joined<["--"], "codegen-data-generate-path=">,
167+
Alias<!cast<Separate>(codegen_data_generate_path)>, MetaVarName<"<cgdata>">,
168+
HelpText<"Write the CG data to the specified path <cgdata>.">, Group<grp_lld>;
165169
def cs_profile_generate: Flag<["--"], "cs-profile-generate">,
166170
HelpText<"Perform context sensitive PGO instrumentation">, Group<grp_lld>;
167171
def cs_profile_path: Joined<["--"], "cs-profile-path=">,

lld/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ if (NOT LLD_BUILT_STANDALONE)
4848
llvm-ar
4949
llvm-as
5050
llvm-bcanalyzer
51+
llvm-cgdata
5152
llvm-config
5253
llvm-cvtres
5354
llvm-dis

lld/test/MachO/cgdata-generate.s

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# UNSUPPORTED: system-windows
2+
# REQUIRES: aarch64
3+
4+
# RUN: rm -rf %t; split-file %s %t
5+
6+
# Synthesize raw cgdata without the header (24 byte) from the indexed cgdata.
7+
# RUN: llvm-cgdata --convert --format binary %t/raw-1.cgtext -o %t/raw-1.cgdata
8+
# RUN: od -t x1 -j 24 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/ \+/ /g; s/^ *//; s/ *$//; s/ /,0x/g; s/^/0x/' > %t/raw-1-bytes.txt
9+
# RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-1-bytes.txt)/g" %t/merge-template.s > %t/merge-1.s
10+
# RUN: llvm-cgdata --convert --format binary %t/raw-2.cgtext -o %t/raw-2.cgdata
11+
# RUN: od -t x1 -j 24 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/ \+/ /g; s/^ *//; s/ *$//; s/ /,0x/g; s/^/0x/' > %t/raw-2-bytes.txt
12+
# RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-2-bytes.txt)/g" %t/merge-template.s > %t/merge-2.s
13+
14+
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-1.s -o %t/merge-1.o
15+
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-2.s -o %t/merge-2.o
16+
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/main.s -o %t/main.o
17+
18+
# This checks if the codegen data from the linker is identical to the merged codegen data
19+
# from each object file, which is obtained using the llvm-cgdata tool.
20+
# RUN: %no-arg-lld -dylib -arch arm64 -platform_version ios 14.0 15.0 -o %t/out \
21+
# RUN: %t/merge-1.o %t/merge-2.o %t/main.o --codegen-data-generate-path=%t/out-cgdata
22+
# RUN: llvm-cgdata --merge %t/merge-1.o %t/merge-2.o %t/main.o -o %t/merge-cgdata
23+
# RUN: diff %t/out-cgdata %t/merge-cgdata
24+
25+
# Merge order doesn't matter. `main.o` is dropped due to missing __llvm_outline.
26+
# RUN: llvm-cgdata --merge %t/merge-2.o %t/merge-1.o -o %t/merge-cgdata-shuffle
27+
# RUN: diff %t/out-cgdata %t/merge-cgdata-shuffle
28+
29+
# We can also generate the merged codegen data from the executable that is not dead-stripped.
30+
# RUN: llvm-objdump -h %t/out| FileCheck %s
31+
# CHECK: __llvm_outline
32+
# RUN: llvm-cgdata --merge %t/out -o %t/merge-cgdata-exe
33+
# RUN: diff %t/merge-cgdata-exe %t/merge-cgdata
34+
35+
# Dead-strip will remove __llvm_outline sections from the final executable.
36+
# But the codeden data is still correctly produced from the linker.
37+
# RUN: %no-arg-lld -dylib -arch arm64 -platform_version ios 14.0 15.0 -o %t/out-strip \
38+
# RUN: %t/merge-1.o %t/merge-2.o %t/main.o -dead_strip --codegen-data-generate-path=%t/out-cgdata-strip
39+
# RUN: llvm-cgdata --merge %t/merge-1.o %t/merge-2.o %t/main.o -o %t/merge-cgdata-strip
40+
# RUN: diff %t/out-cgdata-strip %t/merge-cgdata-strip
41+
# RUN: diff %t/out-cgdata-strip %t/merge-cgdata
42+
43+
# Ensure no __llvm_outline section remains in the executable.
44+
# RUN: llvm-objdump -h %t/out-strip | FileCheck %s --check-prefix=STRIP
45+
# STRIP-NOT: __llvm_outline
46+
47+
#--- raw-1.cgtext
48+
:outlined_hash_tree
49+
0:
50+
Hash: 0x0
51+
Terminals: 0
52+
SuccessorIds: [ 1 ]
53+
1:
54+
Hash: 0x1
55+
Terminals: 0
56+
SuccessorIds: [ 2 ]
57+
2:
58+
Hash: 0x2
59+
Terminals: 4
60+
SuccessorIds: [ ]
61+
...
62+
63+
#--- raw-2.cgtext
64+
:outlined_hash_tree
65+
0:
66+
Hash: 0x0
67+
Terminals: 0
68+
SuccessorIds: [ 1 ]
69+
1:
70+
Hash: 0x1
71+
Terminals: 0
72+
SuccessorIds: [ 2 ]
73+
2:
74+
Hash: 0x3
75+
Terminals: 5
76+
SuccessorIds: [ ]
77+
...
78+
79+
#--- merge-template.s
80+
.section __DATA,__llvm_outline
81+
_data:
82+
.byte <RAW_BYTES>
83+
84+
#--- main.s
85+
.globl _main
86+
87+
.text
88+
_main:
89+
ret

lld/test/lit.cfg.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
tool_patterns = [
4141
"llc",
4242
"llvm-as",
43+
"llvm-cgdata",
4344
"llvm-mc",
4445
"llvm-nm",
4546
"llvm-objdump",

0 commit comments

Comments
 (0)