Skip to content

Commit

Permalink
[CGData] LLD for MachO
Browse files Browse the repository at this point in the history
  • Loading branch information
kyulee-com committed Apr 26, 2024
1 parent 74b8d8a commit 1a96212
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 0 deletions.
1 change: 1 addition & 0 deletions lld/MachO/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ struct Configuration {
std::vector<SectionAlign> sectionAlignments;
std::vector<SegmentProtection> segmentProtections;
bool ltoDebugPassManager = false;
llvm::StringRef codegenDataGeneratePath;
bool csProfileGenerate = false;
llvm::StringRef csProfilePath;
bool pgoWarnMismatch;
Expand Down
39 changes: 39 additions & 0 deletions lld/MachO/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/CodeGenData/CodeGenDataWriter.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
Expand Down Expand Up @@ -1250,6 +1251,38 @@ static void gatherInputSections() {
}
}

static void codegenDataGenerate() {
TimeTraceScope timeScope("Generating codegen data");

OutlinedHashTreeRecord globalOutlineRecord;
for (ConcatInputSection *isec : inputSections) {
if (isec->getSegName() == segment_names::data &&
isec->getName() == section_names::outlinedHashTree) {
// Read outlined hash tree from each section
OutlinedHashTreeRecord localOutlineRecord;
auto *data = isec->data.data();
localOutlineRecord.deserialize(data);

// Merge it to the global hash tree.
globalOutlineRecord.merge(localOutlineRecord);
}
}

CodeGenDataWriter Writer;
if (!globalOutlineRecord.empty())
Writer.addRecord(globalOutlineRecord);

std::error_code EC;
auto fileName = config->codegenDataGeneratePath;
assert(!fileName.empty());
raw_fd_ostream Output(fileName, EC, sys::fs::OF_None);
if (EC)
error("fail to create raw_fd_ostream");

if (auto E = Writer.write(Output))
error("fail to write CGData");
}

static void foldIdenticalLiterals() {
TimeTraceScope timeScope("Fold identical literals");
// We always create a cStringSection, regardless of whether dedupLiterals is
Expand Down Expand Up @@ -1665,6 +1698,8 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
config->ignoreAutoLinkOptions.insert(arg->getValue());
config->strictAutoLink = args.hasArg(OPT_strict_auto_link);
config->ltoDebugPassManager = args.hasArg(OPT_lto_debug_pass_manager);
config->codegenDataGeneratePath =
args.getLastArgValue(OPT_codegen_data_generate_path);
config->csProfileGenerate = args.hasArg(OPT_cs_profile_generate);
config->csProfilePath = args.getLastArgValue(OPT_cs_profile_path);
config->pgoWarnMismatch =
Expand Down Expand Up @@ -1959,6 +1994,10 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
}

gatherInputSections();

if (!config->codegenDataGeneratePath.empty())
codegenDataGenerate();

if (config->callGraphProfileSort)
priorityBuilder.extractCallGraphProfile();

Expand Down
1 change: 1 addition & 0 deletions lld/MachO/InputSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ constexpr const char objcMethname[] = "__objc_methname";
constexpr const char objcNonLazyCatList[] = "__objc_nlcatlist";
constexpr const char objcNonLazyClassList[] = "__objc_nlclslist";
constexpr const char objcProtoList[] = "__objc_protolist";
constexpr const char outlinedHashTree[] = "__llvm_outline";
constexpr const char pageZero[] = "__pagezero";
constexpr const char pointers[] = "__pointers";
constexpr const char rebase[] = "__rebase";
Expand Down
2 changes: 2 additions & 0 deletions lld/MachO/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ def no_objc_category_merging : Flag<["-"], "no_objc_category_merging">,
Group<grp_lld>;
def lto_debug_pass_manager: Flag<["--"], "lto-debug-pass-manager">,
HelpText<"Debug new pass manager">, Group<grp_lld>;
def codegen_data_generate_path : Joined<["--"], "codegen-data-generate-path=">,
HelpText<"Codegen data file path">, Group<grp_lld>;
def cs_profile_generate: Flag<["--"], "cs-profile-generate">,
HelpText<"Perform context sensitive PGO instrumentation">, Group<grp_lld>;
def cs_profile_path: Joined<["--"], "cs-profile-path=">,
Expand Down
83 changes: 83 additions & 0 deletions lld/test/MachO/cgdata-generate.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# REQUIRES: aarch64

# RUN: rm -rf %t; split-file %s %t

# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-1.s -o %t/merge-1.o
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-2.s -o %t/merge-2.o
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/main.s -o %t/main.o

# This checks if the codegen data from the linker is identical to the merged codegen data
# from each object file, which is obtained using the llvm-cgdata tool.
# RUN: %no-arg-lld -dylib -arch arm64 -platform_version ios 14.0 15.0 -o %t/out \
# RUN: %t/merge-1.o %t/merge-2.o %t/main.o --codegen-data-generate-path=%t/out-cgdata
# RUN: llvm-cgdata merge %t/merge-1.o %t/merge-2.o %t/main.o -o %t/merge-cgdata
# RUN: diff %t/out-cgdata %t/merge-cgdata

# Merge order doesn't matter. `main.o` is dropped due to missing __llvm_outline.
# RUN: llvm-cgdata merge %t/merge-2.o %t/merge-1.o -o %t/merge-cgdata-shuffle
# RUN: diff %t/out-cgdata %t/merge-cgdata-shuffle

# We can also generate the merged codegen data from the executable that is not dead-stripped.
# RUN: llvm-objdump -h %t/out| FileCheck %s
CHECK: __llvm_outline
# RUN: llvm-cgdata merge %t/out -o %t/merge-cgdata-exe
# RUN: diff %t/merge-cgdata-exe %t/merge-cgdata

# Dead-strip will remove __llvm_outline sections from the final executable.
# But the codeden data is still correctly produced from the linker.
# RUN: %no-arg-lld -dylib -arch arm64 -platform_version ios 14.0 15.0 -o %t/out-strip \
# RUN: %t/merge-1.o %t/merge-2.o %t/main.o -dead_strip --codegen-data-generate-path=%t/out-cgdata-strip
# RUN: llvm-cgdata merge %t/merge-1.o %t/merge-2.o %t/main.o -o %t/merge-cgdata-strip
# RUN: diff %t/out-cgdata-strip %t/merge-cgdata-strip
# RUN: diff %t/out-cgdata-strip %t/merge-cgdata

# Ensure no __llvm_outline section remains in the executable.
# RUN: llvm-objdump -h %t/out-strip | FileCheck %s --check-prefix=STRIP
STRIP-NOT: __llvm_outline

#--- merge-1.s
# The .data is encoded in a binary form based on the following yaml form. See serialize() in OutlinedHashTreeRecord.cpp
#---
#0:
# Hash: 0x0
# Terminals: 0
# SuccessorIds: [ 1 ]
#1:
# Hash: 0x1
# Terminals: 0
# SuccessorIds: [ 2 ]
#2:
# Hash: 0x2
# Terminals: 4
# SuccessorIds: [ ]
#...
.section __DATA,__llvm_outline
_data:
.byte 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00

#--- merge-2.s
# The .data is encoded in a binary form based on the following yaml form. See serialize() in OutlinedHashTreeRecord.cpp
#---
#0:
# Hash: 0x0
# Terminals: 0
# SuccessorIds: [ 1 ]
#1:
# Hash: 0x1
# Terminals: 0
# SuccessorIds: [ 2 ]
#2:
# Hash: 0x3
# Terminals: 5
# SuccessorIds: [ ]
#...
.section __DATA,__llvm_outline
_data:
.byte 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00

#--- main.s
.globl _main

.text
_main:
ret

0 comments on commit 1a96212

Please sign in to comment.