[LTO] Include debug options in legacy ThinLTO cache keys (#211474)

Legacy ThinLTO omits -mllvm options from cache keys, which can cause it
to reuse objects built with different code-generation settings.

Include these options in cache keys, matching modern ThinLTO behavior.
This commit is contained in:
Xiaoyang Gong 2026-07-25 16:01:24 +08:00 committed by GitHub
parent 43da8ef8d0
commit f539edf74b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 61 additions and 3 deletions

View file

@ -236,6 +236,11 @@ public:
/// Enable or disable debug output for the new pass manager.
void setDebugPassManager(unsigned Enabled) { DebugPassManager = Enabled; }
/// Set the -mllvm arguments to include in the cache key.
void setMllvmArgs(ArrayRef<std::string> Args) {
MllvmArgs.assign(Args.begin(), Args.end());
}
/// Disable CodeGen, only run the stages till codegen and stop. The output
/// will be bitcode.
void disableCodeGen(bool Disable) { DisableCodeGen = Disable; }
@ -356,6 +361,9 @@ private:
/// Flag to indicate whether debug output should be enabled for the new pass
/// manager.
bool DebugPassManager = false;
/// -mllvm arguments included in the cache key.
std::vector<std::string> MllvmArgs;
};
}
#endif

View file

@ -379,7 +379,8 @@ public:
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGVSummaries, unsigned OptLevel,
bool Freestanding, const TargetMachineBuilder &TMBuilder) {
bool Freestanding, const TargetMachineBuilder &TMBuilder,
ArrayRef<std::string> MllvmArgs) {
if (CachePath.empty())
return;
@ -400,6 +401,7 @@ public:
Conf.RelocModel = TMBuilder.RelocModel;
Conf.CGOptLevel = TMBuilder.CGOptLevel;
Conf.Freestanding = Freestanding;
append_range(Conf.MllvmArgs, MllvmArgs);
std::string Key =
computeLTOCacheKey(Conf, Index, ModuleID, ImportList, ExportList,
ResolvedODR, DefinedGVSummaries);
@ -1152,7 +1154,7 @@ void ThinLTOCodeGenerator::run() {
ImportLists[ModuleIdentifier], ExportList,
ResolvedODR[ModuleIdentifier],
DefinedGVSummaries, OptLevel, Freestanding,
TMBuilder);
TMBuilder, MllvmArgs);
auto CacheEntryPath = CacheEntry.getEntryPath();
{

View file

@ -0,0 +1,43 @@
; Verify that legacy ThinLTO includes -mllvm arguments in its cache keys.
; Cache an unoutlined object, enable outlining, then reuse the first
; configuration. The products and cache-entry count must match each option set.
; RUN: opt -module-summary -module-hash %s -o %t.o
; RUN: rm -rf %t.cache && mkdir %t.cache
; Populate the cache with an unoutlined object.
; RUN: %ld64 -lto_library %llvmshlibdir/libLTO.dylib -arch x86_64 -macosx_version_min 10.8.0 -dylib -cache_path_lto %t.cache -o %t.not-outlined.dylib %t.o -lSystem
; RUN: llvm-nm --no-llvm-bc %t.not-outlined.dylib | FileCheck --check-prefix=NO-OUTLINED %s
; RUN: ls %t.cache/llvmcache-* | count 1
; Enabling the outliner must miss the existing entry and create a distinct one.
; RUN: %ld64 -lto_library %llvmshlibdir/libLTO.dylib -arch x86_64 -macosx_version_min 10.8.0 -dylib -cache_path_lto %t.cache -o %t.outlined.dylib %t.o -lSystem -mllvm -enable-machine-outliner
; RUN: llvm-nm --no-llvm-bc %t.outlined.dylib | FileCheck --check-prefix=OUTLINED %s
; RUN: ls %t.cache/llvmcache-* | count 2
; Omitting the option again must reuse the unoutlined cache entry.
; RUN: %ld64 -lto_library %llvmshlibdir/libLTO.dylib -arch x86_64 -macosx_version_min 10.8.0 -dylib -cache_path_lto %t.cache -o %t.not-outlined.dylib %t.o -lSystem
; RUN: llvm-nm --no-llvm-bc %t.not-outlined.dylib | FileCheck --check-prefix=NO-OUTLINED %s
; RUN: ls %t.cache/llvmcache-* | count 2
; OUTLINED: OUTLINED_FUNCTION_
; NO-OUTLINED-NOT: OUTLINED_FUNCTION_
target triple = "x86_64-apple-macosx10.8.0"
define void @outline_me() #0 {
%slot = alloca i32, align 4
; Two copies form a profitable outlining candidate.
store i32 1, ptr %slot, align 4
store i32 2, ptr %slot, align 4
store i32 3, ptr %slot, align 4
store i32 4, ptr %slot, align 4
store i32 1, ptr %slot, align 4
store i32 2, ptr %slot, align 4
store i32 3, ptr %slot, align 4
store i32 4, ptr %slot, align 4
ret void
}
; Preserve the stores and make outlining profitable.
attributes #0 = { noinline optnone noredzone "frame-pointer"="all" }

View file

@ -95,6 +95,9 @@ static enum class OptParsingState {
static LLVMContext *LTOContext = nullptr;
// Records -mllvm arguments parsed through the legacy debug-option APIs.
static std::vector<std::string> ThinLTOMllvmArgs;
struct LTOToolDiagnosticHandler : public DiagnosticHandler {
bool handleDiagnostics(const DiagnosticInfo &DI) override {
if (DI.getSeverity() != DS_Error) {
@ -554,6 +557,7 @@ lto_bool_t lto_module_has_ctor_dtor(lto_module_t mod) {
thinlto_code_gen_t thinlto_create_codegen(void) {
lto_initialize();
ThinLTOCodeGenerator *CodeGen = new ThinLTOCodeGenerator();
CodeGen->setMllvmArgs(ThinLTOMllvmArgs);
CodeGen->setTargetOptions(
codegen::InitTargetOptionsFromCodeGenFlags(Triple()));
CodeGen->setFreestanding(EnableFreestanding);
@ -630,11 +634,12 @@ void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg,
}
void thinlto_debug_options(const char *const *options, int number) {
// if options were requested, set them
// If options were requested, parse and retain them.
if (number && options) {
std::vector<const char *> CodegenArgv(1, "libLTO");
append_range(CodegenArgv, ArrayRef<const char *>(options, number));
cl::ParseCommandLineOptions(CodegenArgv.size(), CodegenArgv.data());
ThinLTOMllvmArgs.assign(options, options + number);
}
}