-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[ThinLTO] Add module names to ThinLTO final objects #74160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -351,23 +351,65 @@ std::vector<InputFile *> BitcodeCompiler::compile() { | |
if (!config->thinLTOCacheDir.empty()) | ||
pruneCache(config->thinLTOCacheDir, config->thinLTOCachePolicy, files); | ||
|
||
if (!config->ltoObjPath.empty()) { | ||
saveBuffer(buf[0], config->ltoObjPath); | ||
for (unsigned i = 1; i != maxTasks; ++i) | ||
saveBuffer(buf[i], config->ltoObjPath + Twine(i)); | ||
} | ||
auto doSaveBuffer = [&](const StringRef Arg, const StringRef Suffix = "") { | ||
// There are a few cases: | ||
// (1) path/test.o (using current directory) | ||
// (2) /tmp/test-a7a1e4.o (using tmp directory) | ||
// (3) if the input obj is in a archive. the module name is like | ||
// "arch/x86/built-in.a(procfs.o at 11368)" | ||
// | ||
// This function replaces '/' and '(' with '-' and terminates at the | ||
// last '.'. it returns the following for the above cases, respectively, | ||
// (1) path_test | ||
// (2) tmp_test-a7a1e4 (remove the first /). | ||
// (3) arch_x86_build-in.a_procfs | ||
// | ||
auto getFileNameString = [](const StringRef Str) { | ||
if (Str.empty()) | ||
return std::string(); | ||
size_t End = Str.find_last_of("."); | ||
size_t Begin = 0; | ||
if (Str[0] == '/' || Str[0] == '\\') | ||
Begin = 1; | ||
std::string Ret = Str.substr(Begin, End - Begin).str(); | ||
auto position = std::string::npos; | ||
while ((position = Ret.find_first_of("/\\(")) != std::string::npos) { | ||
Ret.replace(position, 1, 1, '_'); | ||
} | ||
return Ret; | ||
}; | ||
|
||
auto saveBufferOrFile = [](const StringRef &Buf, const MemoryBuffer *File, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comments about the Buf vs File changes would be good. But I think we might want this in a separate patch as mentioned. |
||
const Twine &Path) { | ||
if (Buf.empty() && File) | ||
return saveBuffer(File->getBuffer(), Path); | ||
saveBuffer(Buf, Path); | ||
}; | ||
|
||
if (config->saveTempsArgs.contains("prelink")) { | ||
if (!buf[0].empty()) | ||
saveBuffer(buf[0], config->outputFile + ".lto.o"); | ||
for (unsigned i = 1; i != maxTasks; ++i) | ||
saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); | ||
} | ||
saveBufferOrFile(buf[0], files[0].get(), Arg + Suffix); | ||
for (unsigned i = 1; i != maxTasks; ++i) { | ||
if (!config->ltoOutputModuleName) { | ||
saveBufferOrFile(buf[i], files[i].get(), Arg + Twine(i) + Suffix); | ||
} else { | ||
const std::string Name = | ||
getFileNameString(ltoObj->getModuleName(i - 1)); | ||
saveBufferOrFile(buf[i], files[i].get(), | ||
Arg + "_" + Twine(i) + "_" + Name + Suffix); | ||
} | ||
} | ||
}; | ||
|
||
if (!config->ltoObjPath.empty()) | ||
doSaveBuffer(config->ltoObjPath, | ||
config->ltoOutputModuleName ? ".lto.o" : ""); | ||
|
||
if (config->saveTempsArgs.contains("prelink")) | ||
doSaveBuffer(config->outputFile, ".lto.o"); | ||
|
||
if (config->ltoEmitAsm) { | ||
saveBuffer(buf[0], config->outputFile); | ||
for (unsigned i = 1; i != maxTasks; ++i) | ||
saveBuffer(buf[i], config->outputFile + Twine(i)); | ||
doSaveBuffer(config->outputFile, | ||
config->ltoOutputModuleName ? ".lto.s" : ""); | ||
return {}; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
; REQUIRES: x86 | ||
; | ||
; RUN: cd %T | ||
; RUN: opt -module-summary %s -o obj1.o | ||
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o obj2.o | ||
; RUN: opt -module-summary %s -o %t_obj3.o | ||
; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t_obj4.o | ||
; | ||
; Objects with a relative path. | ||
; RUN: rm -f *.lto.o *.s | ||
; RUN: ld.lld --lto-output-module-name --save-temps=prelink --lto-obj-path=aaa --lto-emit-asm --thinlto-jobs=1 --entry=f obj1.o obj2.o -o bin1 | ||
; RUN: ls -1 *.lto.o *.s | FileCheck %s --check-prefixes=OBJPATHOUT1,PRELINKOUT1 | ||
; With thinlto-jobs=all. | ||
; RUN: rm -f *.lto.o *.s | ||
; RUN: ld.lld --lto-output-module-name --save-temps=prelink --lto-obj-path=aaa --lto-emit-asm --thinlto-jobs=all --entry=f obj1.o obj2.o -o bin1 | ||
; RUN: ls -1 *.lto.o *.s | FileCheck %s --check-prefixes=OBJPATHOUT1,PRELINKOUT1 | ||
; Objects with an absolute path. | ||
; RUN: rm -f *.lto.o *.s | ||
; RUN: ld.lld --lto-output-module-name --save-temps=prelink --lto-obj-path=aaa --lto-emit-asm --thinlto-jobs=1 --entry=f %t_obj3.o %t_obj4.o -o bin2 | ||
; RUN: ls -1 *.lto.o *.s | FileCheck %s --check-prefixes=OBJPATHOUT2,PRELINKOUT2 | ||
; Objects in an archive | ||
; RUN: rm -f *.lto.o *.s | ||
; RUN: llvm-ar rcS ar.a obj1.o obj2.o | ||
; RUN: ld.lld --lto-output-module-name --save-temps=prelink --lto-obj-path=aaa --lto-emit-asm --thinlto-jobs=1 --entry=f ar.a -o bin1 | ||
; RUN: ls -1 *.lto.o *.s | FileCheck %s --check-prefixes=OBJPATHOUT3,PRELINKOUT3 | ||
; Use with thinlto-cahce | ||
; RUN: rm -f *.lto.o *.s | ||
; RUN: ld.lld --lto-output-module-name --save-temps=prelink --thinlto-cache-dir=thinlto-cache --lto-emit-asm --lto-obj-path=aaa --thinlto-jobs=1 --entry=f obj1.o obj2.o -o bin1 | ||
; RUN: ls -1 *.lto.o *.s | FileCheck %s --check-prefixes=OBJPATHOUT1,PRELINKOUT1 | ||
; | ||
; OBJPATHOUT1-DAG: aaa_1_obj1.lto.o | ||
; OBJPATHOUT1-DAG: aaa_2_obj2.lto.o | ||
; PRELINKOUT1-DAG: bin1_1_obj1.lto.o | ||
; PRELINKOUT1-DAG: bin1_2_obj2.lto.o | ||
; PRELINKOUT1-DAG: bin1_1_obj1.lto.s | ||
; PRELINKOUT1-DAG: bin1_2_obj2.lto.s | ||
; OBJPATHOUT2-DAG: aaa_1_{{.*}}_obj3.lto.o | ||
; OBJPATHOUT2-DAG: aaa_2_{{.*}}obj4.lto.o | ||
; PRELINKOUT2-DAG: bin2_1_{{.*}}obj3.lto.o | ||
; PRELINKOUT2-DAG: bin2_2_{{.*}}obj4.lto.o | ||
; PRELINKOUT2-DAG: bin2_1_{{.*}}obj3.lto.s | ||
; PRELINKOUT2-DAG: bin2_2_{{.*}}obj4.lto.s | ||
; OBJPATHOUT3-DAG: aaa_1_ar.a_obj1.lto.o | ||
; OBJPATHOUT3-DAG: aaa_2_ar.a_obj2.lto.o | ||
; PRELINKOUT3-DAG: bin1_1_ar.a_obj1.lto.o | ||
; PRELINKOUT3-DAG: bin1_2_ar.a_obj2.lto.o | ||
; PRELINKOUT3-DAG: bin1_1_ar.a_obj1.lto.s | ||
; PRELINKOUT3-DAG: bin1_2_ar.a_obj2.lto.s | ||
|
||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" | ||
target triple = "x86_64-unknown-linux-gnu" | ||
|
||
declare void @g(...) | ||
|
||
define void @f() { | ||
entry: | ||
call void (...) @g() | ||
ret void | ||
} |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -299,7 +299,18 @@ class LTO { | |||
|
||||
/// Static method that returns a list of libcall symbols that can be generated | ||||
/// by LTO but might not be visible from bitcode symbol table. | ||||
static ArrayRef<const char*> getRuntimeLibcallSymbols(); | ||||
static ArrayRef<const char *> getRuntimeLibcallSymbols(); | ||||
|
||||
/// Return the name of n-th module. This only applies to ThinLTO. | ||||
StringRef getModuleName(size_t N) const { | ||||
size_t I = N; | ||||
if (I >= ThinLTO.ModuleMap.size()) | ||||
return ""; | ||||
auto it = ThinLTO.ModuleMap.begin(); | ||||
while (I--) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like there is a way to index into the MapVector's vector, using the begin() iterator. See example at llvm-project/llvm/lib/LTO/LTO.cpp Line 1811 in 030b8cb
|
||||
it++; | ||||
return (*it).first; | ||||
} | ||||
|
||||
private: | ||||
Config Conf; | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if some of this should be moved to saveBuffer which is in a common library and invoked from non-ELF as well? Or at least parts of this?