[LTOBackend] Add -filter-save-modules= for save-temps to only dump specific modules. (#175696)

Only if module's name contains a string in -filter-save-modules, will
its temp BC files be saved. If -filter-save-modules= not set, all
modules' BC files will be saved. This feature is more useful for ThinLto
when huge numbers of modules are built separately. Using
-filter-save-modules= can reduce build time and size of generated files,
even avoid crash if some other unrelated files have issues during BC
files dumping.
This commit is contained in:
Tianle Liu 2026-01-19 09:34:25 +08:00 committed by GitHub
parent 447a1dbc43
commit 7f96336a22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 1 deletions

View File

@ -74,6 +74,12 @@ static cl::opt<bool> ThinLTOAssumeMerged(
cl::desc("Assume the input has already undergone ThinLTO function "
"importing and the other pre-optimization pipeline changes."));
static cl::list<std::string>
SaveModulesList("filter-save-modules", cl::value_desc("module names"),
cl::desc("Only save bitcode for module whose name without "
"path matches this for -save-temps options"),
cl::CommaSeparated, cl::Hidden);
namespace llvm {
extern cl::opt<bool> NoPGOWarnMismatch;
}
@ -102,7 +108,17 @@ Error Config::addSaveTemps(std::string OutputFileName, bool UseInputModulePath,
auto setHook = [&](std::string PathSuffix, ModuleHookFn &Hook) {
// Keep track of the hook provided by the linker, which also needs to run.
ModuleHookFn LinkerHook = Hook;
Hook = [=](unsigned Task, const Module &M) {
Hook = [=, SaveModNames = llvm::SmallVector<std::string, 1>(
SaveModulesList.begin(), SaveModulesList.end())](
unsigned Task, const Module &M) {
// If SaveModulesList is not empty, only do save-temps if the module's
// filename (without path) matches a name in the list.
if (!SaveModNames.empty() &&
!llvm::is_contained(
SaveModNames,
std::string(llvm::sys::path::filename(M.getName()))))
return false;
// If the linker's hook returned false, we need to pass that result
// through.
if (LinkerHook && !LinkerHook(Task, M))

View File

@ -0,0 +1,46 @@
; RUN: rm -rf %t.dir
; RUN: split-file %s %t.dir && cd %t.dir
; RUN: opt -thinlto-bc foo.ll -o foo.o
; RUN: opt -thinlto-bc mul.ll -o mul.o
; RUN: llvm-lto2 run mul.o foo.o -o libmy.so -r mul.o,_Z3mulii,l -r foo.o,_Z3mulii,x -r foo.o,_Z3fool,p -save-temps -filter-save-modules=mul.o
; RUN: ls | FileCheck %s --implicit-check-not=libmy.so.2 --check-prefix=MUL
; RUN: rm -f *.bc
; RUN: llvm-lto2 run mul.o foo.o -o libmy.so -r mul.o,_Z3mulii,l -r foo.o,_Z3mulii,x -r foo.o,_Z3fool,p -save-temps -filter-save-modules=mul.o -filter-save-modules=foo.o
; RUN: ls | FileCheck %s --check-prefix=MUL_FOO
; RUN: rm -f *.bc
; RUN: llvm-lto2 run mul.o foo.o -o libmy.so -r mul.o,_Z3mulii,l -r foo.o,_Z3mulii,x -r foo.o,_Z3fool,p -save-temps
; RUN: ls | FileCheck %s --check-prefix=ALL
; MUL: libmy.so.1.0.preopt.bc
; MUL: libmy.so.1.1.promote.bc
; MUL: libmy.so.1.2.internalize.bc
; MUL: libmy.so.1.3.import.bc
; MUL: libmy.so.1.4.opt.bc
; MUL: libmy.so.1.5.precodegen.bc
; MUL_FOO-COUNT-12: libmy.so.{{1|2}}.{{[0-5]}}.{{preopt|promote|internalize|import|opt|precodegen}}.bc
; ALL-COUNT-12: libmy.so.{{1|2}}.{{[0-5]}}.{{preopt|promote|internalize|import|opt|precodegen}}.bc
;--- mul.ll
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: mustprogress noinline nounwind optnone uwtable
define dso_local noundef i32 @_Z3mulii(i32 noundef %a, i32 noundef %b) {
%c = mul nsw i32 %a, %b
ret i32 %c
}
;--- foo.ll
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: mustprogress noinline optnone uwtable
define dso_local noundef i32 @_Z3fool(i32 noundef %n) {
%n1 = add nsw i32 %n, 1
%mul = call noundef i32 @_Z3mulii(i32 noundef %n, i32 noundef %n1)
ret i32 %mul
}
declare noundef i32 @_Z3mulii(i32 noundef, i32 noundef)