https://github.com/ilovepi updated https://github.com/llvm/llvm-project/pull/179509
>From 2e3aaeb89a8d5e4abd8dcecf975857acb1517a3c Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 3 Feb 2026 09:02:48 -0800 Subject: [PATCH 01/22] [llvm] Force TLSDESC for all TLS access in Fuchsia code Fuchsia no longer supports TLS access via __tls_get_addr, and only supports the TLSDESC ABI on all target machines. Though we already set Fuchsia as enabling TLSDESC by default, LLD's LTO pipeline is initialized with an empty target triple, and thus does not correctly select the correct codegen options for Fuchsia's ABI. Instead, we can additionally check if Fuchsia is the actual target if the option isn't set, since useTLSDESC() is only called later, when a non-default target triple will be available. The alternative is to rework how LLD initializes the LTO code generation options, so that it selects the correct target, and initializes them correctly. However, that's a more invasive change, and would need some discussion to make sure that is handled correctly across all of LLDs supported formats (e.g. ELF, Mach-O, COFF, etc.). --- llvm/lib/Target/TargetMachine.cpp | 4 +- llvm/test/CodeGen/RISCV/tls-models.ll | 69 +++++++++++++++++++++++++++ llvm/test/CodeGen/X86/tls-desc.ll | 43 +++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index 3494637237c69..ad1d18d09ac69 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -256,7 +256,9 @@ bool TargetMachine::shouldAssumeDSOLocal(const GlobalValue *GV) const { } bool TargetMachine::useEmulatedTLS() const { return Options.EmulatedTLS; } -bool TargetMachine::useTLSDESC() const { return Options.EnableTLSDESC; } +bool TargetMachine::useTLSDESC() const { + return Options.EnableTLSDESC || TargetTriple.isOSFuchsia(); +} TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const { bool IsPIE = GV->getParent()->getPIELevel() != PIELevel::Default; diff --git a/llvm/test/CodeGen/RISCV/tls-models.ll b/llvm/test/CodeGen/RISCV/tls-models.ll index 52c2c31d8fa81..8caa6108ffbe9 100644 --- a/llvm/test/CodeGen/RISCV/tls-models.ll +++ b/llvm/test/CodeGen/RISCV/tls-models.ll @@ -7,10 +7,13 @@ ; RUN: | FileCheck -check-prefix=RV64-PIC %s ; RUN: llc -mtriple=riscv64 -relocation-model=pic -enable-tlsdesc < %s \ ; RUN: | FileCheck -check-prefix=RV64-PIC-TLSDESC %s +; RUN: llc -mtriple=riscv64-unknown-fuchsia -relocation-model=pic < %s \ +; RUN: | FileCheck -check-prefix=RV64-PIC-FUCHSIA %s ; RUN: llc -mtriple=riscv32 < %s | FileCheck -check-prefix=RV32-NOPIC %s ; RUN: llc -mtriple=riscv32 < %s -enable-tlsdesc | FileCheck -check-prefix=RV32-NOPIC-TLSDESC %s ; RUN: llc -mtriple=riscv64 < %s | FileCheck -check-prefix=RV64-NOPIC %s ; RUN: llc -mtriple=riscv64 < %s -enable-tlsdesc | FileCheck -check-prefix=RV64-NOPIC-TLSDESC %s +; RUN: llc -mtriple=riscv64-unknown-fuchsia < %s | FileCheck -check-prefix=RV64-NOPIC-FUCHSIA %s ; Check that TLS symbols are lowered correctly based on the specified ; model. Make sure they're external to avoid them all being optimised to Local @@ -69,6 +72,16 @@ define ptr @f1() nounwind { ; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp ; RV64-PIC-TLSDESC-NEXT: ret ; +; RV64-PIC-FUCHSIA-LABEL: f1: +; RV64-PIC-FUCHSIA: # %bb.0: # %entry +; RV64-PIC-FUCHSIA-NEXT: .Ltlsdesc_hi0: +; RV64-PIC-FUCHSIA-NEXT: auipc a0, %tlsdesc_hi(unspecified) +; RV64-PIC-FUCHSIA-NEXT: ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi0)(a0) +; RV64-PIC-FUCHSIA-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi0) +; RV64-PIC-FUCHSIA-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi0) +; RV64-PIC-FUCHSIA-NEXT: add a0, a0, tp +; RV64-PIC-FUCHSIA-NEXT: ret +; ; RV32-NOPIC-LABEL: f1: ; RV32-NOPIC: # %bb.0: # %entry ; RV32-NOPIC-NEXT: .Lpcrel_hi0: @@ -100,6 +113,14 @@ define ptr @f1() nounwind { ; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0) ; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp ; RV64-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-FUCHSIA-LABEL: f1: +; RV64-NOPIC-FUCHSIA: # %bb.0: # %entry +; RV64-NOPIC-FUCHSIA-NEXT: .Lpcrel_hi0: +; RV64-NOPIC-FUCHSIA-NEXT: auipc a0, %tls_ie_pcrel_hi(unspecified) +; RV64-NOPIC-FUCHSIA-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0) +; RV64-NOPIC-FUCHSIA-NEXT: add a0, a0, tp +; RV64-NOPIC-FUCHSIA-NEXT: ret entry: ret ptr @unspecified } @@ -152,6 +173,16 @@ define ptr @f2() nounwind { ; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp ; RV64-PIC-TLSDESC-NEXT: ret ; +; RV64-PIC-FUCHSIA-LABEL: f2: +; RV64-PIC-FUCHSIA: # %bb.0: # %entry +; RV64-PIC-FUCHSIA-NEXT: .Ltlsdesc_hi1: +; RV64-PIC-FUCHSIA-NEXT: auipc a0, %tlsdesc_hi(ld) +; RV64-PIC-FUCHSIA-NEXT: ld a1, %tlsdesc_load_lo(.Ltlsdesc_hi1)(a0) +; RV64-PIC-FUCHSIA-NEXT: addi a0, a0, %tlsdesc_add_lo(.Ltlsdesc_hi1) +; RV64-PIC-FUCHSIA-NEXT: jalr t0, 0(a1), %tlsdesc_call(.Ltlsdesc_hi1) +; RV64-PIC-FUCHSIA-NEXT: add a0, a0, tp +; RV64-PIC-FUCHSIA-NEXT: ret +; ; RV32-NOPIC-LABEL: f2: ; RV32-NOPIC: # %bb.0: # %entry ; RV32-NOPIC-NEXT: .Lpcrel_hi1: @@ -183,6 +214,14 @@ define ptr @f2() nounwind { ; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi1)(a0) ; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp ; RV64-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-FUCHSIA-LABEL: f2: +; RV64-NOPIC-FUCHSIA: # %bb.0: # %entry +; RV64-NOPIC-FUCHSIA-NEXT: .Lpcrel_hi1: +; RV64-NOPIC-FUCHSIA-NEXT: auipc a0, %tls_ie_pcrel_hi(ld) +; RV64-NOPIC-FUCHSIA-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi1)(a0) +; RV64-NOPIC-FUCHSIA-NEXT: add a0, a0, tp +; RV64-NOPIC-FUCHSIA-NEXT: ret entry: ret ptr @ld } @@ -223,6 +262,14 @@ define ptr @f3() nounwind { ; RV64-PIC-TLSDESC-NEXT: add a0, a0, tp ; RV64-PIC-TLSDESC-NEXT: ret ; +; RV64-PIC-FUCHSIA-LABEL: f3: +; RV64-PIC-FUCHSIA: # %bb.0: # %entry +; RV64-PIC-FUCHSIA-NEXT: .Lpcrel_hi0: +; RV64-PIC-FUCHSIA-NEXT: auipc a0, %tls_ie_pcrel_hi(ie) +; RV64-PIC-FUCHSIA-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi0)(a0) +; RV64-PIC-FUCHSIA-NEXT: add a0, a0, tp +; RV64-PIC-FUCHSIA-NEXT: ret +; ; RV32-NOPIC-LABEL: f3: ; RV32-NOPIC: # %bb.0: # %entry ; RV32-NOPIC-NEXT: .Lpcrel_hi2: @@ -254,6 +301,14 @@ define ptr @f3() nounwind { ; RV64-NOPIC-TLSDESC-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi2)(a0) ; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp ; RV64-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-FUCHSIA-LABEL: f3: +; RV64-NOPIC-FUCHSIA: # %bb.0: # %entry +; RV64-NOPIC-FUCHSIA-NEXT: .Lpcrel_hi2: +; RV64-NOPIC-FUCHSIA-NEXT: auipc a0, %tls_ie_pcrel_hi(ie) +; RV64-NOPIC-FUCHSIA-NEXT: ld a0, %pcrel_lo(.Lpcrel_hi2)(a0) +; RV64-NOPIC-FUCHSIA-NEXT: add a0, a0, tp +; RV64-NOPIC-FUCHSIA-NEXT: ret entry: ret ptr @ie } @@ -290,6 +345,13 @@ define ptr @f4() nounwind { ; RV64-PIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le) ; RV64-PIC-TLSDESC-NEXT: ret ; +; RV64-PIC-FUCHSIA-LABEL: f4: +; RV64-PIC-FUCHSIA: # %bb.0: # %entry +; RV64-PIC-FUCHSIA-NEXT: lui a0, %tprel_hi(le) +; RV64-PIC-FUCHSIA-NEXT: add a0, a0, tp, %tprel_add(le) +; RV64-PIC-FUCHSIA-NEXT: addi a0, a0, %tprel_lo(le) +; RV64-PIC-FUCHSIA-NEXT: ret +; ; RV32-NOPIC-LABEL: f4: ; RV32-NOPIC: # %bb.0: # %entry ; RV32-NOPIC-NEXT: lui a0, %tprel_hi(le) @@ -317,6 +379,13 @@ define ptr @f4() nounwind { ; RV64-NOPIC-TLSDESC-NEXT: add a0, a0, tp, %tprel_add(le) ; RV64-NOPIC-TLSDESC-NEXT: addi a0, a0, %tprel_lo(le) ; RV64-NOPIC-TLSDESC-NEXT: ret +; +; RV64-NOPIC-FUCHSIA-LABEL: f4: +; RV64-NOPIC-FUCHSIA: # %bb.0: # %entry +; RV64-NOPIC-FUCHSIA-NEXT: lui a0, %tprel_hi(le) +; RV64-NOPIC-FUCHSIA-NEXT: add a0, a0, tp, %tprel_add(le) +; RV64-NOPIC-FUCHSIA-NEXT: addi a0, a0, %tprel_lo(le) +; RV64-NOPIC-FUCHSIA-NEXT: ret entry: ret ptr @le } diff --git a/llvm/test/CodeGen/X86/tls-desc.ll b/llvm/test/CodeGen/X86/tls-desc.ll index c73986e69e791..f7dc0ceeeeb32 100644 --- a/llvm/test/CodeGen/X86/tls-desc.ll +++ b/llvm/test/CodeGen/X86/tls-desc.ll @@ -2,6 +2,7 @@ ; RUN: llc < %s -mtriple=i686 --relocation-model=pic -enable-tlsdesc | FileCheck %s --check-prefix=X86 ; RUN: llc < %s -mtriple=x86_64-pc-linux-gnux32 --relocation-model=pic -enable-tlsdesc | FileCheck %s --check-prefix=X32 ; RUN: llc < %s -mtriple=x86_64 --relocation-model=pic -enable-tlsdesc | FileCheck %s --check-prefix=X64 +; RUN: llc < %s -mtriple=x86_64-unknown-fuchsia --relocation-model=pic | FileCheck %s --check-prefix=X64-FUCHSIA @x = thread_local global i32 0, align 4 @y = internal thread_local global i32 1, align 4 @@ -62,6 +63,19 @@ define ptr @f1() nounwind { ; X64-NEXT: #NO_APP ; X64-NEXT: popq %rcx ; X64-NEXT: retq +; +; X64-FUCHSIA-LABEL: f1: +; X64-FUCHSIA: # %bb.0: +; X64-FUCHSIA-NEXT: pushq %rax +; X64-FUCHSIA-NEXT: #APP +; X64-FUCHSIA-NEXT: #NO_APP +; X64-FUCHSIA-NEXT: leaq x@tlsdesc(%rip), %rax +; X64-FUCHSIA-NEXT: callq *x@tlscall(%rax) +; X64-FUCHSIA-NEXT: addq %fs:0, %rax +; X64-FUCHSIA-NEXT: #APP +; X64-FUCHSIA-NEXT: #NO_APP +; X64-FUCHSIA-NEXT: popq %rcx +; X64-FUCHSIA-NEXT: retq %a = call { i32, i32, i32, i32, i32, i32 } asm sideeffect "", "=r,=r,=r,=r,=r,=r,~{dirflag},~{fpsr},~{flags}"() %b = call ptr @llvm.threadlocal.address.p0(ptr @x) %a.0 = extractvalue { i32, i32, i32, i32, i32, i32 } %a, 0 @@ -109,6 +123,15 @@ define i32 @f2() nounwind { ; X64-NEXT: movl (%rax,%rcx), %eax ; X64-NEXT: popq %rcx ; X64-NEXT: retq +; +; X64-FUCHSIA-LABEL: f2: +; X64-FUCHSIA: # %bb.0: +; X64-FUCHSIA-NEXT: pushq %rax +; X64-FUCHSIA-NEXT: leaq x@tlsdesc(%rip), %rax +; X64-FUCHSIA-NEXT: callq *x@tlscall(%rax) +; X64-FUCHSIA-NEXT: movl %fs:(%rax), %eax +; X64-FUCHSIA-NEXT: popq %rcx +; X64-FUCHSIA-NEXT: retq %1 = tail call ptr @llvm.threadlocal.address.p0(ptr @x) %2 = load i32, ptr %1 ret i32 %2 @@ -147,6 +170,15 @@ define ptr @f3() nounwind { ; X64-NEXT: addq %fs:0, %rax ; X64-NEXT: popq %rcx ; X64-NEXT: retq +; +; X64-FUCHSIA-LABEL: f3: +; X64-FUCHSIA: # %bb.0: +; X64-FUCHSIA-NEXT: pushq %rax +; X64-FUCHSIA-NEXT: leaq x@tlsdesc(%rip), %rax +; X64-FUCHSIA-NEXT: callq *x@tlscall(%rax) +; X64-FUCHSIA-NEXT: addq %fs:0, %rax +; X64-FUCHSIA-NEXT: popq %rcx +; X64-FUCHSIA-NEXT: retq %1 = tail call ptr @llvm.threadlocal.address.p0(ptr @x) ret ptr %1 } @@ -192,6 +224,17 @@ define i32 @f4() nounwind { ; X64-NEXT: movl %ecx, %eax ; X64-NEXT: popq %rcx ; X64-NEXT: retq +; +; X64-FUCHSIA-LABEL: f4: +; X64-FUCHSIA: # %bb.0: +; X64-FUCHSIA-NEXT: pushq %rax +; X64-FUCHSIA-NEXT: leaq _TLS_MODULE_BASE_@tlsdesc(%rip), %rax +; X64-FUCHSIA-NEXT: callq *_TLS_MODULE_BASE_@tlscall(%rax) +; X64-FUCHSIA-NEXT: movl %fs:y@DTPOFF(%rax), %ecx +; X64-FUCHSIA-NEXT: addl %fs:z@DTPOFF(%rax), %ecx +; X64-FUCHSIA-NEXT: movl %ecx, %eax +; X64-FUCHSIA-NEXT: popq %rcx +; X64-FUCHSIA-NEXT: retq %1 = load i32, ptr @y, align 4 %2 = load i32, ptr @z, align 4 %3 = add nsw i32 %1, %2 >From 13c7ef77a17c6e8256e4c82a1dc63dd8fa449901 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 5 Feb 2026 14:29:26 -0800 Subject: [PATCH 02/22] Redesign how TargetOptions are used in LTO --- clang/lib/CodeGen/BackendUtil.cpp | 7 +- .../ClangNVLinkWrapper.cpp | 2 - lld/COFF/LTO.cpp | 24 +++--- lld/ELF/LTO.cpp | 79 ++++++++++--------- lld/MachO/LTO.cpp | 8 +- lld/wasm/LTO.cpp | 10 +-- llvm/include/llvm/LTO/Config.h | 4 +- llvm/include/llvm/LTO/LTO.h | 2 +- .../llvm/LTO/legacy/LTOCodeGenerator.h | 1 + llvm/lib/LTO/LTO.cpp | 50 ++++++++---- llvm/lib/LTO/LTOBackend.cpp | 19 +++-- llvm/lib/LTO/LTOCodeGenerator.cpp | 8 +- llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 3 +- llvm/lib/Target/TargetMachine.cpp | 4 +- llvm/tools/llvm-lto2/llvm-lto2.cpp | 2 +- 15 files changed, 135 insertions(+), 88 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 94257fb96fc7f..4456586d052f8 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -25,6 +25,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/Frontend/Driver/CodeGenOptions.h" @@ -51,6 +52,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Program.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" @@ -1350,7 +1352,10 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, assert(OptLevelOrNone && "Invalid optimization level!"); Conf.CGOptLevel = *OptLevelOrNone; Conf.OptLevel = CGOpts.OptimizationLevel; - initTargetOptions(CI, Diags, Conf.Options); + // llvm::codegen::RegisterCodeGenFlags F; + Conf.ModifyTargetOptions = [&](llvm::TargetOptions &TargetOpts)->void { + initTargetOptions(CI, Diags, TargetOpts); + }; Conf.SampleProfile = std::move(SampleProfile); Conf.PTO.LoopUnrolling = CGOpts.UnrollLoops; Conf.PTO.LoopInterchange = CGOpts.InterchangeLoops; diff --git a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp index 3ebd4ea979322..f940951584fab 100644 --- a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp +++ b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp @@ -358,8 +358,6 @@ Expected<std::unique_ptr<lto::LTO>> createLTO(const ArgList &Args) { lto::createInProcessThinBackend(heavyweight_hardware_concurrency(Jobs)); Conf.CPU = Args.getLastArgValue(OPT_arch); - Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple); - Conf.RemarksFilename = Args.getLastArgValue(OPT_opt_remarks_filename, RemarksFilename); Conf.RemarksPasses = diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index d55f95493a85f..de083a356271e 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -46,17 +46,24 @@ std::string BitcodeCompiler::getThinLTOOutputFile(StringRef path) { lto::Config BitcodeCompiler::createConfig() { lto::Config c; - c.Options = initTargetOptionsFromCodeGenFlags(); - c.Options.EmitAddrsig = true; + bool emitAsm = ctx.config.emit == EmitKind::ASM; + c.ModifyTargetOptions = [emitAsm](TargetOptions &options) { + options.EmitAddrsig = true; + // Always emit a section per function/datum with LTO. LLVM LTO should get + // most of the benefit of linker GC, but there are still opportunities for + // ICF. + options.FunctionSections = true; + options.DataSections = true; + + if (emitAsm) { + options.MCOptions.AsmVerbose = true; + } + }; + for (StringRef C : ctx.config.mllvmOpts) c.MllvmArgs.emplace_back(C.str()); - // Always emit a section per function/datum with LTO. LLVM LTO should get most - // of the benefit of linker GC, but there are still opportunities for ICF. - c.Options.FunctionSections = true; - c.Options.DataSections = true; - - // Use static reloc model on 32-bit x86 because it usually results in more + // Use static reloc model on 32-bit x86 because it usually results in more // compact code, and because there are also known code generation bugs when // using the PIC model (see PR34306). if (ctx.config.machine == COFF::IMAGE_FILE_MACHINE_I386) @@ -95,7 +102,6 @@ lto::Config BitcodeCompiler::createConfig() { }; } else if (ctx.config.emit == EmitKind::ASM) { c.CGFileType = CodeGenFileType::AssemblyFile; - c.Options.MCOptions.AsmVerbose = true; } if (!ctx.config.saveTempsArgs.empty()) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 6f916a501a262..692651a8506ca 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -46,47 +46,52 @@ static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) { static lto::Config createConfig(Ctx &ctx) { lto::Config c; - // LLD supports the new relocations and address-significance tables. - c.Options = initTargetOptionsFromCodeGenFlags(); - c.Options.EmitAddrsig = true; - for (StringRef C : ctx.arg.mllvmOpts) - c.MllvmArgs.emplace_back(C.str()); - - // Always emit a section per function/datum with LTO. - c.Options.FunctionSections = true; - c.Options.DataSections = true; - - // Check if basic block sections must be used. - // Allowed values for --lto-basic-block-sections are "all", - // "<file name specifying basic block ids>", or none. This is the equivalent - // of -fbasic-block-sections= flag in clang. - if (!ctx.arg.ltoBasicBlockSections.empty()) { - if (ctx.arg.ltoBasicBlockSections == "all") { - c.Options.BBSections = BasicBlockSection::All; - } else if (ctx.arg.ltoBasicBlockSections == "labels") { - c.Options.BBAddrMap = true; - Warn(ctx) - << "'--lto-basic-block-sections=labels' is deprecated; Please use " - "'--lto-basic-block-address-map' instead"; - } else if (ctx.arg.ltoBasicBlockSections == "none") { - c.Options.BBSections = BasicBlockSection::None; - } else { - ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = - MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); - if (!MBOrErr) { - ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections << ":" - << MBOrErr.getError().message(); + // Set up the callback to modify TargetOptions. + c.ModifyTargetOptions = [&](TargetOptions &Options) -> void { + // LLD supports the new relocations and address-significance tables. + Options.EmitAddrsig = true; + // Always emit a section per function/datum with LTO. + Options.FunctionSections = true; + Options.DataSections = true; + + // Check if basic block sections must be used. + // Allowed values for --lto-basic-block-sections are "all", + // "<file name specifying basic block ids>", or none. This is the + // equivalent of -fbasic-block-sections= flag in clang. + if (!ctx.arg.ltoBasicBlockSections.empty()) { + if (ctx.arg.ltoBasicBlockSections == "all") { + Options.BBSections = BasicBlockSection::All; + } else if (ctx.arg.ltoBasicBlockSections == "labels") { + Options.BBAddrMap = true; + Warn(ctx) + << "'--lto-basic-block-sections=labels' is deprecated; Please use " + "'--lto-basic-block-address-map' instead"; + } else if (ctx.arg.ltoBasicBlockSections == "none") { + Options.BBSections = BasicBlockSection::None; } else { - c.Options.BBSectionsFuncListBuf = std::move(*MBOrErr); + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = + MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); + if (!MBOrErr) { + ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections + << ":" << MBOrErr.getError().message(); + } else { + Options.BBSectionsFuncListBuf = std::move(*MBOrErr); + } + Options.BBSections = BasicBlockSection::List; } - c.Options.BBSections = BasicBlockSection::List; } - } - c.Options.BBAddrMap = ctx.arg.ltoBBAddrMap; + Options.BBAddrMap = ctx.arg.ltoBBAddrMap; - c.Options.UniqueBasicBlockSectionNames = - ctx.arg.ltoUniqueBasicBlockSectionNames; + Options.UniqueBasicBlockSectionNames = + ctx.arg.ltoUniqueBasicBlockSectionNames; + if (ctx.arg.ltoEmitAsm) { + Options.MCOptions.AsmVerbose = true; + } + }; + + for (StringRef C : ctx.arg.mllvmOpts) + c.MllvmArgs.emplace_back(C.str()); if (auto relocModel = getRelocModelFromCMModel()) c.RelocModel = *relocModel; @@ -156,7 +161,7 @@ static lto::Config createConfig(Ctx &ctx) { if (ctx.arg.ltoEmitAsm) { c.CGFileType = CodeGenFileType::AssemblyFile; - c.Options.MCOptions.AsmVerbose = true; + // c.Options.MCOptions.AsmVerbose = true; } if (!ctx.arg.saveTempsArgs.empty()) diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp index 2c360374ef3cc..e25c63e1fce6b 100644 --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -38,8 +38,12 @@ static std::string getThinLTOOutputFile(StringRef modulePath) { static lto::Config createConfig() { lto::Config c; - c.Options = initTargetOptionsFromCodeGenFlags(); - c.Options.EmitAddrsig = config->icfLevel == ICFLevel::safe; + + bool emitAddrsig = config->icfLevel == ICFLevel::safe; + c.ModifyTargetOptions = [emitAddrsig](TargetOptions &options) { + options.EmitAddrsig = emitAddrsig; + }; + for (StringRef C : config->mllvmOpts) c.MllvmArgs.emplace_back(C.str()); for (StringRef pluginFn : config->passPlugins) diff --git a/lld/wasm/LTO.cpp b/lld/wasm/LTO.cpp index 668cdf21ea3ed..f6f69e934a00a 100644 --- a/lld/wasm/LTO.cpp +++ b/lld/wasm/LTO.cpp @@ -42,11 +42,11 @@ static std::string getThinLTOOutputFile(StringRef modulePath) { static lto::Config createConfig() { lto::Config c; - c.Options = initTargetOptionsFromCodeGenFlags(); - - // Always emit a section per function/data with LTO. - c.Options.FunctionSections = true; - c.Options.DataSections = true; + c.ModifyTargetOptions = [&](TargetOptions &options) { + // Always emit a section per function/data with LTO. + options.FunctionSections = true; + options.DataSections = true; + }; c.DisableVerify = ctx.arg.disableVerify; c.DiagHandler = diagnosticHandler; diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h index 566a87ed1a790..29350964fd0cb 100644 --- a/llvm/include/llvm/LTO/Config.h +++ b/llvm/include/llvm/LTO/Config.h @@ -47,7 +47,8 @@ struct Config { // Note: when adding fields here, consider whether they need to be added to // computeLTOCacheKey in LTO.cpp. std::string CPU; - TargetOptions Options; + // Callback to modify the target options once they are instantiated. + std::function<void(TargetOptions& Options)> ModifyTargetOptions = [](TargetOptions&){}; std::vector<std::string> MAttrs; std::vector<std::string> MllvmArgs; std::vector<std::string> PassPlugins; @@ -286,6 +287,7 @@ struct Config { LLVM_ABI Error addSaveTemps(std::string OutputFileName, bool UseInputModulePath = false, const DenseSet<StringRef> &SaveTempsArgs = {}); + }; struct LTOLLVMDiagnosticHandler : public DiagnosticHandler { diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index c49d5a2198efd..91430a6f9da87 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -74,7 +74,7 @@ LLVM_ABI std::string computeLTOCacheKey( StringRef ModuleID, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - const GVSummaryMapTy &DefinedGlobals, + const GVSummaryMapTy &DefinedGlobals, const Triple &TT, const DenseSet<GlobalValue::GUID> &CfiFunctionDefs = {}, const DenseSet<GlobalValue::GUID> &CfiFunctionDecls = {}); diff --git a/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h b/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h index caff198358caa..117269c1b58a1 100644 --- a/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h +++ b/llvm/include/llvm/LTO/legacy/LTOCodeGenerator.h @@ -249,6 +249,7 @@ struct LTOCodeGenerator { std::string SaveIRBeforeOptPath; lto::Config Config; + llvm::TargetOptions TO; }; /// A convenience function that calls cl::ParseCommandLineOptions on the given diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 6c0d7d5bd16e9..5149fc3fcedbd 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -24,6 +24,7 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CGData/CodeGenData.h" #include "llvm/CodeGen/Analysis.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -125,6 +126,7 @@ std::string llvm::computeLTOCacheKey( const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, + const Triple& TT, const DenseSet<GlobalValue::GUID> &CfiFunctionDefs, const DenseSet<GlobalValue::GUID> &CfiFunctionDecls) { // Compute the unique hash for this entry. @@ -158,14 +160,17 @@ std::string llvm::computeLTOCacheKey( Hasher.update(ArrayRef<uint8_t>(&I, 1)); }; AddString(Conf.CPU); + TargetOptions Opts = codegen::InitTargetOptionsFromCodeGenFlags(TT); + Conf.ModifyTargetOptions(Opts); + // FIXME: Hash more of Options. For now all clients initialize Options from // command-line flags (which is unsupported in production), but may set // X86RelaxRelocations. The clang driver can also pass FunctionSections, // DataSections and DebuggerTuning via command line flags. - AddUnsigned(Conf.Options.MCOptions.X86RelaxRelocations); - AddUnsigned(Conf.Options.FunctionSections); - AddUnsigned(Conf.Options.DataSections); - AddUnsigned((unsigned)Conf.Options.DebuggerTuning); + AddUnsigned(Opts.MCOptions.X86RelaxRelocations); + AddUnsigned(Opts.FunctionSections); + AddUnsigned(Opts.DataSections); + AddUnsigned((unsigned)Opts.DebuggerTuning); for (auto &A : Conf.MAttrs) AddString(A); if (Conf.RelocModel) @@ -1557,10 +1562,10 @@ class InProcessThinBackend : public CGThinBackend { const GVSummaryMapTy &DefinedGlobals, MapVector<StringRef, BitcodeModule> &ModuleMap) { auto ModuleID = BM.getModuleIdentifier(); + LTOLLVMContext BackendContext(Conf); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (in-process)", ModuleID); auto RunThinBackend = [&](AddStreamFn AddStream) { - LTOLLVMContext BackendContext(Conf); Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext); if (!MOrErr) return MOrErr.takeError(); @@ -1581,10 +1586,15 @@ class InProcessThinBackend : public CGThinBackend { // no module hash. return RunThinBackend(AddStream); + auto Mod = ModuleMap.front().second.parseModule(BackendContext); + if (!Mod) + return Mod.takeError(); + Triple TT = (*Mod)->getTargetTriple(); + // The module may be cached, this helps handling it. std::string Key = computeLTOCacheKey( Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, - DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls); + DefinedGlobals, TT, CfiFunctionDefs, CfiFunctionDecls); Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, Key, ModuleID); if (Error Err = CacheAddStreamOrErr.takeError()) return Err; @@ -1672,9 +1682,9 @@ class FirstRoundThinBackend : public InProcessThinBackend { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)", ModuleID); + LTOLLVMContext BackendContext(Conf); auto RunThinBackend = [&](AddStreamFn CGAddStream, AddStreamFn IRAddStream) { - LTOLLVMContext BackendContext(Conf); Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext); if (!MOrErr) return MOrErr.takeError(); @@ -1700,10 +1710,15 @@ class FirstRoundThinBackend : public InProcessThinBackend { // no module hash. return RunThinBackend(CGAddStream, IRAddStream); + auto Mod = ModuleMap.front().second.parseModule(BackendContext); + if (!Mod) + return Mod.takeError(); + Triple TT = (*Mod)->getTargetTriple(); + // Get CGKey for caching object in CGCache. std::string CGKey = computeLTOCacheKey( Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, - DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls); + DefinedGlobals, TT, CfiFunctionDefs, CfiFunctionDecls); Expected<AddStreamFn> CacheCGAddStreamOrErr = CGCache(Task, CGKey, ModuleID); if (Error Err = CacheCGAddStreamOrErr.takeError()) @@ -1769,8 +1784,8 @@ class SecondRoundThinBackend : public InProcessThinBackend { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (second round)", ModuleID); + LTOLLVMContext BackendContext(Conf); auto RunThinBackend = [&](AddStreamFn AddStream) { - LTOLLVMContext BackendContext(Conf); std::unique_ptr<Module> LoadedModule = cgdata::loadModuleForTwoRounds(BM, Task, BackendContext, *IRFiles); @@ -1785,11 +1800,16 @@ class SecondRoundThinBackend : public InProcessThinBackend { // no module hash. return RunThinBackend(AddStream); + auto Mod = ModuleMap.front().second.parseModule(BackendContext); + if (!Mod) + return Mod.takeError(); + Triple TT = (*Mod)->getTargetTriple(); + // Get Key for caching the final object file in Cache with the combined // CGData hash. std::string Key = computeLTOCacheKey( Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, - DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls); + DefinedGlobals, TT, CfiFunctionDefs, CfiFunctionDecls); Key = recomputeLTOCacheKey(Key, /*ExtraID=*/std::to_string(CombinedCGDataHash)); Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, Key, ModuleID); @@ -2362,7 +2382,7 @@ class OutOfProcessThinBackend : public CGThinBackend { // The module may be cached, this helps handling it. J.CacheKey = computeLTOCacheKey(Conf, CombinedIndex, J.ModuleID, ImportList, ExportList, ResolvedODR, DefinedGlobals, - CfiFunctionDefs, CfiFunctionDecls); + Triple, CfiFunctionDefs, CfiFunctionDecls); // The module may be cached, this helps handling it. auto CacheAddStreamExp = Cache(J.Task, J.CacheKey, J.ModuleID); @@ -2458,12 +2478,14 @@ class OutOfProcessThinBackend : public CGThinBackend { auto &Ops = CodegenOptions; Ops.push_back(Saver.save("-O" + Twine(C.OptLevel))); + TargetOptions TO = codegen::InitTargetOptionsFromCodeGenFlags(Triple); + C.ModifyTargetOptions(TO); - if (C.Options.EmitAddrsig) + if (TO.EmitAddrsig) Ops.push_back("-faddrsig"); - if (C.Options.FunctionSections) + if (TO.FunctionSections) Ops.push_back("-ffunction-sections"); - if (C.Options.DataSections) + if (TO.DataSections) Ops.push_back("-fdata-sections"); if (C.RelocModel == Reloc::PIC_) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 43e5c3b398372..cd3b476ba4ccf 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -22,6 +22,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CGData/CodeGenData.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PassManager.h" @@ -215,6 +216,9 @@ static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins, } } +// Required to call InitTargetOptionsFromCodeGenFlags(). +static codegen::RegisterCodeGenFlags F; + static std::unique_ptr<TargetMachine> createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { const Triple &TheTriple = M.getTargetTriple(); @@ -236,7 +240,10 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { else CodeModel = M.getCodeModel(); - TargetOptions TargetOpts = Conf.Options; + TargetOptions TargetOpts = + codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); + Conf.ModifyTargetOptions(TargetOpts); + if (TargetOpts.MCOptions.ABIName.empty()) { TargetOpts.MCOptions.ABIName = M.getTargetABIFromMD(); } @@ -413,7 +420,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } -static void codegen(const Config &Conf, TargetMachine *TM, +static void startCodegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream, unsigned Task, Module &Mod, const ModuleSummaryIndex &CombinedIndex) { llvm::TimeTraceScope timeScope("codegen"); @@ -526,7 +533,7 @@ static void splitCodeGen(const Config &C, TargetMachine *TM, std::unique_ptr<TargetMachine> TM = createTargetMachine(C, T, *MPartInCtx); - codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx, + startCodegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx, CombinedIndex); }, // Pass BC using std::move to ensure that it get moved rather than @@ -591,7 +598,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream, } if (ParallelCodeGenParallelismLevel == 1) { - codegen(C, TM.get(), AddStream, 0, Mod, CombinedIndex); + startCodegen(C, TM.get(), AddStream, 0, Mod, CombinedIndex); } else { splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, Mod, CombinedIndex); @@ -652,7 +659,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, if (CodeGenOnly) { // If CodeGenOnly is set, we only perform code generation and skip // optimization. This value may differ from Conf.CodeGenOnly. - codegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex); + startCodegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex); return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } @@ -675,7 +682,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, if (IRAddStream) cgdata::saveModuleForTwoRounds(Mod, Task, IRAddStream); - codegen(Conf, TM, AddStream, Task, Mod, CombinedIndex); + startCodegen(Conf, TM, AddStream, Task, Mod, CombinedIndex); return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); }; diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index 46be71da5a092..218048b3a0873 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -166,7 +166,7 @@ void LTOCodeGenerator::setModule(std::unique_ptr<LTOModule> Mod) { } void LTOCodeGenerator::setTargetOptions(const TargetOptions &Options) { - Config.Options = Options; + TO = Options; } void LTOCodeGenerator::setDebugInfo(lto_debug_model Debug) { @@ -230,7 +230,7 @@ bool LTOCodeGenerator::writeMergedModules(StringRef Path) { bool LTOCodeGenerator::useAIXSystemAssembler() { const auto &Triple = TargetMach->getTargetTriple(); - return Triple.isOSAIX() && Config.Options.DisableIntegratedAS; + return Triple.isOSAIX() && TO.DisableIntegratedAS; } bool LTOCodeGenerator::runAIXSystemAssembler(SmallString<128> &AssemblyFile) { @@ -397,7 +397,7 @@ bool LTOCodeGenerator::determineTarget() { // If data-sections is not explicitly set or unset, set data-sections by // default to match the behaviour of lld and gold plugin. if (!codegen::getExplicitDataSections()) - Config.Options.DataSections = true; + TO.DataSections = true; TargetMach = createTargetMachine(); assert(TargetMach && "Unable to create target machine"); @@ -408,7 +408,7 @@ bool LTOCodeGenerator::determineTarget() { std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() { assert(MArch && "MArch is not set!"); return std::unique_ptr<TargetMachine>(MArch->createTargetMachine( - MergedModule->getTargetTriple(), Config.CPU, FeatureStr, Config.Options, + MergedModule->getTargetTriple(), Config.CPU, FeatureStr,TO, Config.RelocModel, std::nullopt, Config.CGOptLevel)); } diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index 93b672ae7840c..22c53660f0a36 100644 --- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -374,7 +374,6 @@ class ModuleCacheEntry { llvm::lto::Config Conf; Conf.OptLevel = OptLevel; - Conf.Options = TMBuilder.Options; Conf.CPU = TMBuilder.MCpu; Conf.MAttrs.push_back(TMBuilder.MAttr); Conf.RelocModel = TMBuilder.RelocModel; @@ -382,7 +381,7 @@ class ModuleCacheEntry { Conf.Freestanding = Freestanding; std::string Key = computeLTOCacheKey(Conf, Index, ModuleID, ImportList, ExportList, - ResolvedODR, DefinedGVSummaries); + ResolvedODR, DefinedGVSummaries, TMBuilder.TheTriple); // This choice of file name allows the cache to be pruned (see pruneCache() // in include/llvm/Support/CachePruning.h). diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index ad1d18d09ac69..3494637237c69 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -256,9 +256,7 @@ bool TargetMachine::shouldAssumeDSOLocal(const GlobalValue *GV) const { } bool TargetMachine::useEmulatedTLS() const { return Options.EmulatedTLS; } -bool TargetMachine::useTLSDESC() const { - return Options.EnableTLSDESC || TargetTriple.isOSFuchsia(); -} +bool TargetMachine::useTLSDESC() const { return Options.EnableTLSDESC; } TLSModel::Model TargetMachine::getTLSModel(const GlobalValue *GV) const { bool IsPIE = GV->getParent()->getPIELevel() != PIELevel::Default; diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp index 955c1130e9f4c..87ca7810d5486 100644 --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -334,7 +334,7 @@ static int run(int argc, char **argv) { Conf.TimeTraceGranularity = TimeTraceGranularity; } Conf.CPU = codegen::getMCPU(); - Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple()); + Conf.ModifyTargetOptions = [](llvm::TargetOptions &TO) {}; Conf.MAttrs = codegen::getMAttrs(); if (auto RM = codegen::getExplicitRelocModel()) Conf.RelocModel = *RM; >From 0595b0c748ea074e5d0ac19d04fdb53d4ea9a238 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 5 Feb 2026 14:36:34 -0800 Subject: [PATCH 03/22] clang format --- clang/lib/CodeGen/BackendUtil.cpp | 2 +- lld/COFF/LTO.cpp | 2 +- llvm/include/llvm/LTO/Config.h | 4 ++-- llvm/lib/LTO/LTO.cpp | 5 ++--- llvm/lib/LTO/LTOBackend.cpp | 8 ++++---- llvm/lib/LTO/LTOCodeGenerator.cpp | 2 +- llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 6 +++--- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 4456586d052f8..0de8d3ba69991 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1353,7 +1353,7 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, Conf.CGOptLevel = *OptLevelOrNone; Conf.OptLevel = CGOpts.OptimizationLevel; // llvm::codegen::RegisterCodeGenFlags F; - Conf.ModifyTargetOptions = [&](llvm::TargetOptions &TargetOpts)->void { + Conf.ModifyTargetOptions = [&](llvm::TargetOptions &TargetOpts) -> void { initTargetOptions(CI, Diags, TargetOpts); }; Conf.SampleProfile = std::move(SampleProfile); diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index de083a356271e..f0dfe47a1d4d5 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -63,7 +63,7 @@ lto::Config BitcodeCompiler::createConfig() { for (StringRef C : ctx.config.mllvmOpts) c.MllvmArgs.emplace_back(C.str()); - // Use static reloc model on 32-bit x86 because it usually results in more + // Use static reloc model on 32-bit x86 because it usually results in more // compact code, and because there are also known code generation bugs when // using the PIC model (see PR34306). if (ctx.config.machine == COFF::IMAGE_FILE_MACHINE_I386) diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h index 29350964fd0cb..4af8b4af5f177 100644 --- a/llvm/include/llvm/LTO/Config.h +++ b/llvm/include/llvm/LTO/Config.h @@ -48,7 +48,8 @@ struct Config { // computeLTOCacheKey in LTO.cpp. std::string CPU; // Callback to modify the target options once they are instantiated. - std::function<void(TargetOptions& Options)> ModifyTargetOptions = [](TargetOptions&){}; + std::function<void(TargetOptions &Options)> ModifyTargetOptions = + [](TargetOptions &) {}; std::vector<std::string> MAttrs; std::vector<std::string> MllvmArgs; std::vector<std::string> PassPlugins; @@ -287,7 +288,6 @@ struct Config { LLVM_ABI Error addSaveTemps(std::string OutputFileName, bool UseInputModulePath = false, const DenseSet<StringRef> &SaveTempsArgs = {}); - }; struct LTOLLVMDiagnosticHandler : public DiagnosticHandler { diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 5149fc3fcedbd..2a4935b619c6a 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -125,8 +125,7 @@ std::string llvm::computeLTOCacheKey( const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - const GVSummaryMapTy &DefinedGlobals, - const Triple& TT, + const GVSummaryMapTy &DefinedGlobals, const Triple &TT, const DenseSet<GlobalValue::GUID> &CfiFunctionDefs, const DenseSet<GlobalValue::GUID> &CfiFunctionDecls) { // Compute the unique hash for this entry. @@ -1682,7 +1681,7 @@ class FirstRoundThinBackend : public InProcessThinBackend { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)", ModuleID); - LTOLLVMContext BackendContext(Conf); + LTOLLVMContext BackendContext(Conf); auto RunThinBackend = [&](AddStreamFn CGAddStream, AddStreamFn IRAddStream) { Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext); diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index cd3b476ba4ccf..09d9f40567ed7 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -217,7 +217,7 @@ static void RegisterPassPlugins(ArrayRef<std::string> PassPlugins, } // Required to call InitTargetOptionsFromCodeGenFlags(). -static codegen::RegisterCodeGenFlags F; +static codegen::RegisterCodeGenFlags F; static std::unique_ptr<TargetMachine> createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { @@ -421,8 +421,8 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, } static void startCodegen(const Config &Conf, TargetMachine *TM, - AddStreamFn AddStream, unsigned Task, Module &Mod, - const ModuleSummaryIndex &CombinedIndex) { + AddStreamFn AddStream, unsigned Task, Module &Mod, + const ModuleSummaryIndex &CombinedIndex) { llvm::TimeTraceScope timeScope("codegen"); if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) return; @@ -534,7 +534,7 @@ static void splitCodeGen(const Config &C, TargetMachine *TM, createTargetMachine(C, T, *MPartInCtx); startCodegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx, - CombinedIndex); + CombinedIndex); }, // Pass BC using std::move to ensure that it get moved rather than // copied into the thread's context. diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index 218048b3a0873..2826bb240b8e7 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -408,7 +408,7 @@ bool LTOCodeGenerator::determineTarget() { std::unique_ptr<TargetMachine> LTOCodeGenerator::createTargetMachine() { assert(MArch && "MArch is not set!"); return std::unique_ptr<TargetMachine>(MArch->createTargetMachine( - MergedModule->getTargetTriple(), Config.CPU, FeatureStr,TO, + MergedModule->getTargetTriple(), Config.CPU, FeatureStr, TO, Config.RelocModel, std::nullopt, Config.CGOptLevel)); } diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index 22c53660f0a36..da7d2c0b1955d 100644 --- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -379,9 +379,9 @@ class ModuleCacheEntry { Conf.RelocModel = TMBuilder.RelocModel; Conf.CGOptLevel = TMBuilder.CGOptLevel; Conf.Freestanding = Freestanding; - std::string Key = - computeLTOCacheKey(Conf, Index, ModuleID, ImportList, ExportList, - ResolvedODR, DefinedGVSummaries, TMBuilder.TheTriple); + std::string Key = computeLTOCacheKey( + Conf, Index, ModuleID, ImportList, ExportList, ResolvedODR, + DefinedGVSummaries, TMBuilder.TheTriple); // This choice of file name allows the cache to be pruned (see pruneCache() // in include/llvm/Support/CachePruning.h). >From 77b14eacb757f1e07ef7c6b0a8e97920898f1856 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 10 Feb 2026 14:09:09 -0800 Subject: [PATCH 04/22] Address minor review comments Cleanup stale comments and formatting. --- clang/lib/CodeGen/BackendUtil.cpp | 1 - lld/COFF/LTO.cpp | 3 +-- lld/Common/TargetOptionsCommandFlags.cpp | 4 ---- lld/ELF/LTO.cpp | 1 - lld/include/lld/Common/TargetOptionsCommandFlags.h | 1 - 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 0de8d3ba69991..967b80430e9be 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1352,7 +1352,6 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, assert(OptLevelOrNone && "Invalid optimization level!"); Conf.CGOptLevel = *OptLevelOrNone; Conf.OptLevel = CGOpts.OptimizationLevel; - // llvm::codegen::RegisterCodeGenFlags F; Conf.ModifyTargetOptions = [&](llvm::TargetOptions &TargetOpts) -> void { initTargetOptions(CI, Diags, TargetOpts); }; diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index f0dfe47a1d4d5..aff38392dbcff 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -55,9 +55,8 @@ lto::Config BitcodeCompiler::createConfig() { options.FunctionSections = true; options.DataSections = true; - if (emitAsm) { + if (emitAsm) options.MCOptions.AsmVerbose = true; - } }; for (StringRef C : ctx.config.mllvmOpts) diff --git a/lld/Common/TargetOptionsCommandFlags.cpp b/lld/Common/TargetOptionsCommandFlags.cpp index 0860e8ff8ef8e..5eb08e6e54e30 100644 --- a/lld/Common/TargetOptionsCommandFlags.cpp +++ b/lld/Common/TargetOptionsCommandFlags.cpp @@ -12,10 +12,6 @@ #include "llvm/TargetParser/Triple.h" #include <optional> -llvm::TargetOptions lld::initTargetOptionsFromCodeGenFlags() { - return llvm::codegen::InitTargetOptionsFromCodeGenFlags(llvm::Triple()); -} - std::optional<llvm::Reloc::Model> lld::getRelocModelFromCMModel() { return llvm::codegen::getExplicitRelocModel(); } diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 692651a8506ca..4460781ce465e 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -161,7 +161,6 @@ static lto::Config createConfig(Ctx &ctx) { if (ctx.arg.ltoEmitAsm) { c.CGFileType = CodeGenFileType::AssemblyFile; - // c.Options.MCOptions.AsmVerbose = true; } if (!ctx.arg.saveTempsArgs.empty()) diff --git a/lld/include/lld/Common/TargetOptionsCommandFlags.h b/lld/include/lld/Common/TargetOptionsCommandFlags.h index 9bc22d441e183..4897126c90a79 100644 --- a/lld/include/lld/Common/TargetOptionsCommandFlags.h +++ b/lld/include/lld/Common/TargetOptionsCommandFlags.h @@ -18,7 +18,6 @@ #include <optional> namespace lld { -llvm::TargetOptions initTargetOptionsFromCodeGenFlags(); std::optional<llvm::Reloc::Model> getRelocModelFromCMModel(); std::optional<llvm::CodeModel::Model> getCodeModelFromCMModel(); std::string getCPUStr(); >From 399f357a6628430aa5ce08fa39e79a502a94ebe0 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 10 Feb 2026 14:10:42 -0800 Subject: [PATCH 05/22] Plumb the Triple through runThinLTO APIs --- llvm/include/llvm/LTO/LTO.h | 2 +- llvm/lib/LTO/LTO.cpp | 38 ++++++++++++------------------------- 2 files changed, 13 insertions(+), 27 deletions(-) diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index 91430a6f9da87..fe0e044ade8fb 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -274,7 +274,7 @@ class ThinBackendProc { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap) = 0; + MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) = 0; virtual Error wait() { BackendThreadPool.wait(); if (Err) diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 2a4935b619c6a..9f3bd1a19806a 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1559,7 +1559,7 @@ class InProcessThinBackend : public CGThinBackend { const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap) { + MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) { auto ModuleID = BM.getModuleIdentifier(); LTOLLVMContext BackendContext(Conf); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (in-process)", @@ -1585,15 +1585,10 @@ class InProcessThinBackend : public CGThinBackend { // no module hash. return RunThinBackend(AddStream); - auto Mod = ModuleMap.front().second.parseModule(BackendContext); - if (!Mod) - return Mod.takeError(); - Triple TT = (*Mod)->getTargetTriple(); - // The module may be cached, this helps handling it. std::string Key = computeLTOCacheKey( Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, - DefinedGlobals, TT, CfiFunctionDefs, CfiFunctionDecls); + DefinedGlobals, TheTriple, CfiFunctionDefs, CfiFunctionDecls); Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, Key, ModuleID); if (Error Err = CacheAddStreamOrErr.takeError()) return Err; @@ -1609,7 +1604,7 @@ class InProcessThinBackend : public CGThinBackend { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); assert(ModuleToDefinedGVSummaries.count(ModulePath)); const GVSummaryMapTy &DefinedGlobals = @@ -1627,7 +1622,7 @@ class InProcessThinBackend : public CGThinBackend { "thin backend"); Error E = runThinLTOBackendThread( AddStream, Cache, Task, BM, CombinedIndex, ImportList, ExportList, - ResolvedODR, DefinedGlobals, ModuleMap); + ResolvedODR, DefinedGlobals, ModuleMap, TheTriple); if (E) { std::unique_lock<std::mutex> L(ErrMu); if (Err) @@ -1677,7 +1672,7 @@ class FirstRoundThinBackend : public InProcessThinBackend { const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)", ModuleID); @@ -1709,15 +1704,10 @@ class FirstRoundThinBackend : public InProcessThinBackend { // no module hash. return RunThinBackend(CGAddStream, IRAddStream); - auto Mod = ModuleMap.front().second.parseModule(BackendContext); - if (!Mod) - return Mod.takeError(); - Triple TT = (*Mod)->getTargetTriple(); - // Get CGKey for caching object in CGCache. std::string CGKey = computeLTOCacheKey( Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, - DefinedGlobals, TT, CfiFunctionDefs, CfiFunctionDecls); + DefinedGlobals, TheTriple, CfiFunctionDefs, CfiFunctionDecls); Expected<AddStreamFn> CacheCGAddStreamOrErr = CGCache(Task, CGKey, ModuleID); if (Error Err = CacheCGAddStreamOrErr.takeError()) @@ -1779,7 +1769,7 @@ class SecondRoundThinBackend : public InProcessThinBackend { const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (second round)", ModuleID); @@ -1799,16 +1789,11 @@ class SecondRoundThinBackend : public InProcessThinBackend { // no module hash. return RunThinBackend(AddStream); - auto Mod = ModuleMap.front().second.parseModule(BackendContext); - if (!Mod) - return Mod.takeError(); - Triple TT = (*Mod)->getTargetTriple(); - // Get Key for caching the final object file in Cache with the combined // CGData hash. std::string Key = computeLTOCacheKey( Conf, CombinedIndex, ModuleID, ImportList, ExportList, ResolvedODR, - DefinedGlobals, TT, CfiFunctionDefs, CfiFunctionDecls); + DefinedGlobals, TheTriple, CfiFunctionDefs, CfiFunctionDecls); Key = recomputeLTOCacheKey(Key, /*ExtraID=*/std::to_string(CombinedCGDataHash)); Expected<AddStreamFn> CacheAddStreamOrErr = Cache(Task, Key, ModuleID); @@ -1901,7 +1886,7 @@ class WriteIndexesThinBackend : public ThinBackendProc { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); // The contents of this file may be used as input to a native link, and must @@ -2130,6 +2115,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, ThinLTO.ModulesToCompile ? *ThinLTO.ModulesToCompile : ThinLTO.ModuleMap; auto RunBackends = [&](ThinBackendProc *BackendProcess) -> Error { + Triple TheTriple = RegularLTO.CombinedModule->getTargetTriple(); auto ProcessOneModule = [&](int I) -> Error { auto &Mod = *(ModuleMap.begin() + I); // Tasks 0 through ParallelCodeGenParallelismLevel-1 are reserved for @@ -2137,7 +2123,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, return BackendProcess->start( RegularLTO.ParallelCodeGenParallelismLevel + I, Mod.second, ImportLists[Mod.first], ExportLists[Mod.first], - ResolvedODR[Mod.first], ThinLTO.ModuleMap); + ResolvedODR[Mod.first], ThinLTO.ModuleMap, TheTriple); }; BackendProcess->setup(ModuleMap.size(), @@ -2407,7 +2393,7 @@ class OutOfProcessThinBackend : public CGThinBackend { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, class Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); >From 5099c7f8e0ea347c4d6e7525c558e809047aad42 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 10 Feb 2026 14:11:15 -0800 Subject: [PATCH 06/22] Fix formatting --- .../lld/Common/TargetOptionsCommandFlags.h | 2 +- llvm/lib/LTO/LTO.cpp | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lld/include/lld/Common/TargetOptionsCommandFlags.h b/lld/include/lld/Common/TargetOptionsCommandFlags.h index 4897126c90a79..8b8ecba11f796 100644 --- a/lld/include/lld/Common/TargetOptionsCommandFlags.h +++ b/lld/include/lld/Common/TargetOptionsCommandFlags.h @@ -22,6 +22,6 @@ std::optional<llvm::Reloc::Model> getRelocModelFromCMModel(); std::optional<llvm::CodeModel::Model> getCodeModelFromCMModel(); std::string getCPUStr(); std::vector<std::string> getMAttrs(); -} +} // namespace lld #endif diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 9f3bd1a19806a..cecf2b59a1572 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1604,7 +1604,8 @@ class InProcessThinBackend : public CGThinBackend { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, + Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); assert(ModuleToDefinedGVSummaries.count(ModulePath)); const GVSummaryMapTy &DefinedGlobals = @@ -1672,7 +1673,8 @@ class FirstRoundThinBackend : public InProcessThinBackend { const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, + Triple TheTriple) override { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)", ModuleID); @@ -1769,7 +1771,8 @@ class SecondRoundThinBackend : public InProcessThinBackend { const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, + Triple TheTriple) override { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (second round)", ModuleID); @@ -1886,7 +1889,8 @@ class WriteIndexesThinBackend : public ThinBackendProc { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, + Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); // The contents of this file may be used as input to a native link, and must @@ -2393,7 +2397,8 @@ class OutOfProcessThinBackend : public CGThinBackend { const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, - MapVector<StringRef, BitcodeModule> &ModuleMap, class Triple TheTriple) override { + MapVector<StringRef, BitcodeModule> &ModuleMap, + class Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); >From 409c1d5e73040bbd985865e186680495fb8bfcc6 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 10 Feb 2026 14:53:45 -0800 Subject: [PATCH 07/22] Restore static API name in LTOBackend.cpp --- llvm/lib/LTO/LTOBackend.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 09d9f40567ed7..20310e2ebf855 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -420,7 +420,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } -static void startCodegen(const Config &Conf, TargetMachine *TM, +static void codegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream, unsigned Task, Module &Mod, const ModuleSummaryIndex &CombinedIndex) { llvm::TimeTraceScope timeScope("codegen"); @@ -533,7 +533,7 @@ static void splitCodeGen(const Config &C, TargetMachine *TM, std::unique_ptr<TargetMachine> TM = createTargetMachine(C, T, *MPartInCtx); - startCodegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx, + ::codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx, CombinedIndex); }, // Pass BC using std::move to ensure that it get moved rather than @@ -598,7 +598,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream, } if (ParallelCodeGenParallelismLevel == 1) { - startCodegen(C, TM.get(), AddStream, 0, Mod, CombinedIndex); + ::codegen(C, TM.get(), AddStream, 0, Mod, CombinedIndex); } else { splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, Mod, CombinedIndex); @@ -659,7 +659,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, if (CodeGenOnly) { // If CodeGenOnly is set, we only perform code generation and skip // optimization. This value may differ from Conf.CodeGenOnly. - startCodegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex); + ::codegen(Conf, TM.get(), AddStream, Task, Mod, CombinedIndex); return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } @@ -682,7 +682,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, if (IRAddStream) cgdata::saveModuleForTwoRounds(Mod, Task, IRAddStream); - startCodegen(Conf, TM, AddStream, Task, Mod, CombinedIndex); + ::codegen(Conf, TM, AddStream, Task, Mod, CombinedIndex); return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); }; >From 28d4f33f4339ec4ef65820ebd209732bce9213bc Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 10 Feb 2026 15:30:01 -0800 Subject: [PATCH 08/22] Clang Format --- llvm/lib/LTO/LTOBackend.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 20310e2ebf855..e6d249754db40 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -421,8 +421,8 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, } static void codegen(const Config &Conf, TargetMachine *TM, - AddStreamFn AddStream, unsigned Task, Module &Mod, - const ModuleSummaryIndex &CombinedIndex) { + AddStreamFn AddStream, unsigned Task, Module &Mod, + const ModuleSummaryIndex &CombinedIndex) { llvm::TimeTraceScope timeScope("codegen"); if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) return; @@ -534,7 +534,7 @@ static void splitCodeGen(const Config &C, TargetMachine *TM, createTargetMachine(C, T, *MPartInCtx); ::codegen(C, TM.get(), AddStream, ThreadId, *MPartInCtx, - CombinedIndex); + CombinedIndex); }, // Pass BC using std::move to ensure that it get moved rather than // copied into the thread's context. >From 70e9d486e3e0320c06bdd7ea7053a1ae51b32d42 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Wed, 11 Feb 2026 10:18:58 -0800 Subject: [PATCH 09/22] Use ModifyTargetOptions to update DataSections --- llvm/lib/LTO/LTOCodeGenerator.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index 2826bb240b8e7..b4e9c9787a0d3 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -394,10 +394,12 @@ bool LTOCodeGenerator::determineTarget() { if (Config.CPU.empty()) Config.CPU = lto::getThinLTODefaultCPU(MergedModule->getTargetTriple()); - // If data-sections is not explicitly set or unset, set data-sections by - // default to match the behaviour of lld and gold plugin. - if (!codegen::getExplicitDataSections()) - TO.DataSections = true; + Config.ModifyTargetOptions = [](TargetOptions &Options) { + // If data-sections is not explicitly set or unset, set data-sections by + // default to match the behaviour of lld and gold plugin. + if (!codegen::getExplicitDataSections()) + Options.DataSections = true; + }; TargetMach = createTargetMachine(); assert(TargetMach && "Unable to create target machine"); >From e83d3eba1c4c10f1005757a4abfe866d7c530177 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Wed, 11 Feb 2026 10:55:47 -0800 Subject: [PATCH 10/22] Save work --- lld/ELF/LTO.cpp | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 4460781ce465e..007ffda6153a6 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -46,8 +46,26 @@ static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) { static lto::Config createConfig(Ctx &ctx) { lto::Config c; + std::shared_ptr<MemoryBuffer> MBPtr; + if (!ctx.arg.ltoBasicBlockSections.empty()) { + if (ctx.arg.ltoBasicBlockSections == "all") { + } else if (ctx.arg.ltoBasicBlockSections == "labels") { + } else if (ctx.arg.ltoBasicBlockSections == "none") { + } else { + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = + MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); + if (!MBOrErr) { + ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections << ":" + << MBOrErr.getError().message(); + } else { + MBPtr = std::move(*MBOrErr); + } + } + } + // Set up the callback to modify TargetOptions. - c.ModifyTargetOptions = [&](TargetOptions &Options) -> void { + c.ModifyTargetOptions = + [&ctx, MB = std::move(MBPtr)](TargetOptions &Options) -> void { // LLD supports the new relocations and address-significance tables. Options.EmitAddrsig = true; // Always emit a section per function/datum with LTO. @@ -69,14 +87,7 @@ static lto::Config createConfig(Ctx &ctx) { } else if (ctx.arg.ltoBasicBlockSections == "none") { Options.BBSections = BasicBlockSection::None; } else { - ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = - MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); - if (!MBOrErr) { - ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections - << ":" << MBOrErr.getError().message(); - } else { - Options.BBSectionsFuncListBuf = std::move(*MBOrErr); - } + Options.BBSectionsFuncListBuf = std::move(MB); Options.BBSections = BasicBlockSection::List; } } >From 0426036fb6ebef560d2ea2afdd6a595d89d4de32 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Wed, 11 Feb 2026 11:12:40 -0800 Subject: [PATCH 11/22] Preallocate MemoryBuffer for callback --- lld/ELF/LTO.cpp | 57 +++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 007ffda6153a6..995584488892f 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -43,34 +43,35 @@ static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) { ctx.arg.thinLTOPrefixReplaceNew); } +static std::shared_ptr<MemoryBuffer> getMemoryBuffer(Ctx &ctx) { + if (ctx.arg.ltoBasicBlockSections.empty() || + ctx.arg.ltoBasicBlockSections == "all" || + ctx.arg.ltoBasicBlockSections == "labels" || + ctx.arg.ltoBasicBlockSections == "none") + return nullptr; + + ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = + MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); + if (!mbOrErr) { + ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections << ":" + << mbOrErr.getError().message(); + } + return std::move(*mbOrErr); +} + static lto::Config createConfig(Ctx &ctx) { lto::Config c; - std::shared_ptr<MemoryBuffer> MBPtr; - if (!ctx.arg.ltoBasicBlockSections.empty()) { - if (ctx.arg.ltoBasicBlockSections == "all") { - } else if (ctx.arg.ltoBasicBlockSections == "labels") { - } else if (ctx.arg.ltoBasicBlockSections == "none") { - } else { - ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = - MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); - if (!MBOrErr) { - ErrAlways(ctx) << "cannot open " << ctx.arg.ltoBasicBlockSections << ":" - << MBOrErr.getError().message(); - } else { - MBPtr = std::move(*MBOrErr); - } - } - } + std::shared_ptr<MemoryBuffer> mbPtr = getMemoryBuffer(ctx); // Set up the callback to modify TargetOptions. c.ModifyTargetOptions = - [&ctx, MB = std::move(MBPtr)](TargetOptions &Options) -> void { + [&ctx, mb = std::move(mbPtr)](TargetOptions &options) -> void { // LLD supports the new relocations and address-significance tables. - Options.EmitAddrsig = true; + options.EmitAddrsig = true; // Always emit a section per function/datum with LTO. - Options.FunctionSections = true; - Options.DataSections = true; + options.FunctionSections = true; + options.DataSections = true; // Check if basic block sections must be used. // Allowed values for --lto-basic-block-sections are "all", @@ -78,26 +79,26 @@ static lto::Config createConfig(Ctx &ctx) { // equivalent of -fbasic-block-sections= flag in clang. if (!ctx.arg.ltoBasicBlockSections.empty()) { if (ctx.arg.ltoBasicBlockSections == "all") { - Options.BBSections = BasicBlockSection::All; + options.BBSections = BasicBlockSection::All; } else if (ctx.arg.ltoBasicBlockSections == "labels") { - Options.BBAddrMap = true; + options.BBAddrMap = true; Warn(ctx) << "'--lto-basic-block-sections=labels' is deprecated; Please use " "'--lto-basic-block-address-map' instead"; } else if (ctx.arg.ltoBasicBlockSections == "none") { - Options.BBSections = BasicBlockSection::None; + options.BBSections = BasicBlockSection::None; } else { - Options.BBSectionsFuncListBuf = std::move(MB); - Options.BBSections = BasicBlockSection::List; + options.BBSectionsFuncListBuf = std::move(mb); + options.BBSections = BasicBlockSection::List; } } - Options.BBAddrMap = ctx.arg.ltoBBAddrMap; + options.BBAddrMap = ctx.arg.ltoBBAddrMap; - Options.UniqueBasicBlockSectionNames = + options.UniqueBasicBlockSectionNames = ctx.arg.ltoUniqueBasicBlockSectionNames; if (ctx.arg.ltoEmitAsm) { - Options.MCOptions.AsmVerbose = true; + options.MCOptions.AsmVerbose = true; } }; >From 25ded121bd5591412116fbf6d1aafaa391fe615c Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Wed, 11 Feb 2026 15:20:15 -0800 Subject: [PATCH 12/22] Update comment and reuse local variable --- llvm/lib/LTO/LTO.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index cecf2b59a1572..57518fba526a6 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -162,10 +162,12 @@ std::string llvm::computeLTOCacheKey( TargetOptions Opts = codegen::InitTargetOptionsFromCodeGenFlags(TT); Conf.ModifyTargetOptions(Opts); - // FIXME: Hash more of Options. For now all clients initialize Options from - // command-line flags (which is unsupported in production), but may set - // X86RelaxRelocations. The clang driver can also pass FunctionSections, - // DataSections and DebuggerTuning via command line flags. + // FIXME: Hash more of TargetOptions. For now all clients initialize + // TargetOptions from command-line flags (which is unsupported in production), + // but may set X86RelaxRelocations. The clang driver can also pass + // FunctionSections, DataSections and DebuggerTuning via command line flags. + // Alternatively, we could store these options in the IR, instead, which has + // other trade-offs. AddUnsigned(Opts.MCOptions.X86RelaxRelocations); AddUnsigned(Opts.FunctionSections); AddUnsigned(Opts.DataSections); @@ -2119,7 +2121,8 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, ThinLTO.ModulesToCompile ? *ThinLTO.ModulesToCompile : ThinLTO.ModuleMap; auto RunBackends = [&](ThinBackendProc *BackendProcess) -> Error { - Triple TheTriple = RegularLTO.CombinedModule->getTargetTriple(); + const Triple &TheTriple = RegularLTO.CombinedModule->getTargetTriple(); + assert(!TheTriple.getTriple().empty() && "Empty TargetTriple for ThinLTO!"); auto ProcessOneModule = [&](int I) -> Error { auto &Mod = *(ModuleMap.begin() + I); // Tasks 0 through ParallelCodeGenParallelismLevel-1 are reserved for @@ -2132,7 +2135,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, BackendProcess->setup(ModuleMap.size(), RegularLTO.ParallelCodeGenParallelismLevel, - RegularLTO.CombinedModule->getTargetTriple()); + TheTriple); if (BackendProcess->getThreadCount() == 1 || BackendProcess->isSensitiveToInputOrder()) { >From c8f51f03bc75108388756116ee672943da2b5d71 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 12 Feb 2026 13:33:19 -0800 Subject: [PATCH 13/22] Rename helper function for clarity --- lld/ELF/LTO.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 995584488892f..be83f10eaa981 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -43,7 +43,7 @@ static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) { ctx.arg.thinLTOPrefixReplaceNew); } -static std::shared_ptr<MemoryBuffer> getMemoryBuffer(Ctx &ctx) { +static std::shared_ptr<MemoryBuffer> getBBSectionsMemoryBuffer(Ctx &ctx) { if (ctx.arg.ltoBasicBlockSections.empty() || ctx.arg.ltoBasicBlockSections == "all" || ctx.arg.ltoBasicBlockSections == "labels" || @@ -62,7 +62,7 @@ static std::shared_ptr<MemoryBuffer> getMemoryBuffer(Ctx &ctx) { static lto::Config createConfig(Ctx &ctx) { lto::Config c; - std::shared_ptr<MemoryBuffer> mbPtr = getMemoryBuffer(ctx); + std::shared_ptr<MemoryBuffer> mbPtr = getBBSectionsMemoryBuffer(ctx); // Set up the callback to modify TargetOptions. c.ModifyTargetOptions = >From a5463d568424e3e35c6ecada4a492264d66ac3d4 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 12 Feb 2026 13:34:13 -0800 Subject: [PATCH 14/22] Don't issue warning in callback --- lld/ELF/LTO.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index be83f10eaa981..4f10474c26fd5 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -46,10 +46,16 @@ static std::string getThinLTOOutputFile(Ctx &ctx, StringRef modulePath) { static std::shared_ptr<MemoryBuffer> getBBSectionsMemoryBuffer(Ctx &ctx) { if (ctx.arg.ltoBasicBlockSections.empty() || ctx.arg.ltoBasicBlockSections == "all" || - ctx.arg.ltoBasicBlockSections == "labels" || ctx.arg.ltoBasicBlockSections == "none") return nullptr; + if (ctx.arg.ltoBasicBlockSections == "labels") { + Warn(ctx) + << "'--lto-basic-block-sections=labels' is deprecated; Please use " + "'--lto-basic-block-address-map' instead"; + return nullptr; + } + ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = MemoryBuffer::getFile(ctx.arg.ltoBasicBlockSections.str()); if (!mbOrErr) { @@ -82,9 +88,6 @@ static lto::Config createConfig(Ctx &ctx) { options.BBSections = BasicBlockSection::All; } else if (ctx.arg.ltoBasicBlockSections == "labels") { options.BBAddrMap = true; - Warn(ctx) - << "'--lto-basic-block-sections=labels' is deprecated; Please use " - "'--lto-basic-block-address-map' instead"; } else if (ctx.arg.ltoBasicBlockSections == "none") { options.BBSections = BasicBlockSection::None; } else { >From 7b891c62619b9314e90b1a2adf3f4291b26bdec0 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 12 Feb 2026 13:35:37 -0800 Subject: [PATCH 15/22] Ensure callback behaves consistently across calls Using std::move() could make this unsafe to call multiple times, so avoid that. --- lld/ELF/LTO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 4f10474c26fd5..528c34c2f8c50 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -91,7 +91,7 @@ static lto::Config createConfig(Ctx &ctx) { } else if (ctx.arg.ltoBasicBlockSections == "none") { options.BBSections = BasicBlockSection::None; } else { - options.BBSectionsFuncListBuf = std::move(mb); + options.BBSectionsFuncListBuf = mb; options.BBSections = BasicBlockSection::List; } } >From 24acb8c7e568ca5e1d0968fb8edfcf66e0631400 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 12 Feb 2026 13:38:20 -0800 Subject: [PATCH 16/22] Remove redundant code --- llvm/tools/llvm-lto2/llvm-lto2.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp index 87ca7810d5486..166ce882945a0 100644 --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -334,7 +334,6 @@ static int run(int argc, char **argv) { Conf.TimeTraceGranularity = TimeTraceGranularity; } Conf.CPU = codegen::getMCPU(); - Conf.ModifyTargetOptions = [](llvm::TargetOptions &TO) {}; Conf.MAttrs = codegen::getMAttrs(); if (auto RM = codegen::getExplicitRelocModel()) Conf.RelocModel = *RM; >From 180ef3b3af120468caac9236d017d9387b30e61d Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Fri, 13 Feb 2026 09:31:37 -0800 Subject: [PATCH 17/22] Move BackendContext back into lambda --- llvm/lib/LTO/LTO.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 57518fba526a6..3c744ebbde382 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1563,10 +1563,10 @@ class InProcessThinBackend : public CGThinBackend { const GVSummaryMapTy &DefinedGlobals, MapVector<StringRef, BitcodeModule> &ModuleMap, Triple TheTriple) { auto ModuleID = BM.getModuleIdentifier(); - LTOLLVMContext BackendContext(Conf); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (in-process)", ModuleID); auto RunThinBackend = [&](AddStreamFn AddStream) { + LTOLLVMContext BackendContext(Conf); Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext); if (!MOrErr) return MOrErr.takeError(); @@ -1680,9 +1680,9 @@ class FirstRoundThinBackend : public InProcessThinBackend { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)", ModuleID); - LTOLLVMContext BackendContext(Conf); auto RunThinBackend = [&](AddStreamFn CGAddStream, AddStreamFn IRAddStream) { + LTOLLVMContext BackendContext(Conf); Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext); if (!MOrErr) return MOrErr.takeError(); @@ -1778,8 +1778,8 @@ class SecondRoundThinBackend : public InProcessThinBackend { auto ModuleID = BM.getModuleIdentifier(); llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (second round)", ModuleID); - LTOLLVMContext BackendContext(Conf); auto RunThinBackend = [&](AddStreamFn AddStream) { + LTOLLVMContext BackendContext(Conf); std::unique_ptr<Module> LoadedModule = cgdata::loadModuleForTwoRounds(BM, Task, BackendContext, *IRFiles); @@ -2401,7 +2401,7 @@ class OutOfProcessThinBackend : public CGThinBackend { const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, MapVector<StringRef, BitcodeModule> &ModuleMap, - class Triple TheTriple) override { + llvm::Triple TheTriple) override { StringRef ModulePath = BM.getModuleIdentifier(); >From c4d89591988ef2715004ccfc6288a9f063f9b1ca Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Fri, 13 Feb 2026 16:14:15 -0800 Subject: [PATCH 18/22] Update callback to return TargetOptions --- clang/lib/CodeGen/BackendUtil.cpp | 5 ++++- lld/COFF/LTO.cpp | 5 ++++- lld/ELF/LTO.cpp | 6 ++++-- lld/MachO/LTO.cpp | 4 +++- lld/wasm/LTO.cpp | 4 +++- llvm/include/llvm/LTO/Config.h | 7 +++++-- llvm/lib/LTO/LTO.cpp | 6 ++---- llvm/lib/LTO/LTOBackend.cpp | 4 +--- llvm/lib/LTO/LTOCodeGenerator.cpp | 6 ++++-- 9 files changed, 30 insertions(+), 17 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 967b80430e9be..39505bd82b6ee 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1352,8 +1352,11 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, assert(OptLevelOrNone && "Invalid optimization level!"); Conf.CGOptLevel = *OptLevelOrNone; Conf.OptLevel = CGOpts.OptimizationLevel; - Conf.ModifyTargetOptions = [&](llvm::TargetOptions &TargetOpts) -> void { + Conf.InitTargetOptions = [&](llvm::Triple TheTriple) -> llvm::TargetOptions { + llvm::TargetOptions TargetOpts = + llvm::codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); initTargetOptions(CI, Diags, TargetOpts); + return TargetOpts; }; Conf.SampleProfile = std::move(SampleProfile); Conf.PTO.LoopUnrolling = CGOpts.UnrollLoops; diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index aff38392dbcff..33e61cb9e5866 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -24,6 +24,7 @@ #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/Support/Caching.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/MemoryBuffer.h" @@ -47,7 +48,8 @@ std::string BitcodeCompiler::getThinLTOOutputFile(StringRef path) { lto::Config BitcodeCompiler::createConfig() { lto::Config c; bool emitAsm = ctx.config.emit == EmitKind::ASM; - c.ModifyTargetOptions = [emitAsm](TargetOptions &options) { + c.InitTargetOptions = [emitAsm](const Triple &TT) { + TargetOptions options = codegen::InitTargetOptionsFromCodeGenFlags(TT); options.EmitAddrsig = true; // Always emit a section per function/datum with LTO. LLVM LTO should get // most of the benefit of linker GC, but there are still opportunities for @@ -57,6 +59,7 @@ lto::Config BitcodeCompiler::createConfig() { if (emitAsm) options.MCOptions.AsmVerbose = true; + return options; }; for (StringRef C : ctx.config.mllvmOpts) diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 528c34c2f8c50..0b9fd008240cc 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -71,8 +71,9 @@ static lto::Config createConfig(Ctx &ctx) { std::shared_ptr<MemoryBuffer> mbPtr = getBBSectionsMemoryBuffer(ctx); // Set up the callback to modify TargetOptions. - c.ModifyTargetOptions = - [&ctx, mb = std::move(mbPtr)](TargetOptions &options) -> void { + c.InitTargetOptions = + [&ctx, mb = std::move(mbPtr)](const Triple &TT) -> TargetOptions { + TargetOptions options = codegen::InitTargetOptionsFromCodeGenFlags(TT); // LLD supports the new relocations and address-significance tables. options.EmitAddrsig = true; // Always emit a section per function/datum with LTO. @@ -103,6 +104,7 @@ static lto::Config createConfig(Ctx &ctx) { if (ctx.arg.ltoEmitAsm) { options.MCOptions.AsmVerbose = true; } + return options; }; for (StringRef C : ctx.arg.mllvmOpts) diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp index e25c63e1fce6b..37de954e54b46 100644 --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -40,8 +40,10 @@ static lto::Config createConfig() { lto::Config c; bool emitAddrsig = config->icfLevel == ICFLevel::safe; - c.ModifyTargetOptions = [emitAddrsig](TargetOptions &options) { + c.InitTargetOptions = [emitAddrsig](const Triple &TT) { + TargetOptions options = codegen::InitTargetOptionsFromCodeGenFlags(TT); options.EmitAddrsig = emitAddrsig; + return options; }; for (StringRef C : config->mllvmOpts) diff --git a/lld/wasm/LTO.cpp b/lld/wasm/LTO.cpp index f6f69e934a00a..3a5f0116ee6f8 100644 --- a/lld/wasm/LTO.cpp +++ b/lld/wasm/LTO.cpp @@ -42,10 +42,12 @@ static std::string getThinLTOOutputFile(StringRef modulePath) { static lto::Config createConfig() { lto::Config c; - c.ModifyTargetOptions = [&](TargetOptions &options) { + c.InitTargetOptions = [&](const Triple &TT) { + TargetOptions options = codegen::InitTargetOptionsFromCodeGenFlags(TT); // Always emit a section per function/data with LTO. options.FunctionSections = true; options.DataSections = true; + return options; }; c.DisableVerify = ctx.arg.disableVerify; diff --git a/llvm/include/llvm/LTO/Config.h b/llvm/include/llvm/LTO/Config.h index 4af8b4af5f177..dccb83b50aec6 100644 --- a/llvm/include/llvm/LTO/Config.h +++ b/llvm/include/llvm/LTO/Config.h @@ -15,6 +15,7 @@ #define LLVM_LTO_CONFIG_H #include "llvm/ADT/DenseSet.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/GlobalValue.h" @@ -48,8 +49,10 @@ struct Config { // computeLTOCacheKey in LTO.cpp. std::string CPU; // Callback to modify the target options once they are instantiated. - std::function<void(TargetOptions &Options)> ModifyTargetOptions = - [](TargetOptions &) {}; + std::function<TargetOptions(const Triple &TheTriple)> InitTargetOptions = + [](const Triple &TheTriple) { + return codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); + }; std::vector<std::string> MAttrs; std::vector<std::string> MllvmArgs; std::vector<std::string> PassPlugins; diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 3c744ebbde382..3b1364d0ff30e 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -159,8 +159,7 @@ std::string llvm::computeLTOCacheKey( Hasher.update(ArrayRef<uint8_t>(&I, 1)); }; AddString(Conf.CPU); - TargetOptions Opts = codegen::InitTargetOptionsFromCodeGenFlags(TT); - Conf.ModifyTargetOptions(Opts); + TargetOptions Opts = Conf.InitTargetOptions(TT); // FIXME: Hash more of TargetOptions. For now all clients initialize // TargetOptions from command-line flags (which is unsupported in production), @@ -2471,8 +2470,7 @@ class OutOfProcessThinBackend : public CGThinBackend { auto &Ops = CodegenOptions; Ops.push_back(Saver.save("-O" + Twine(C.OptLevel))); - TargetOptions TO = codegen::InitTargetOptionsFromCodeGenFlags(Triple); - C.ModifyTargetOptions(TO); + TargetOptions TO = C.InitTargetOptions(Triple); if (TO.EmitAddrsig) Ops.push_back("-faddrsig"); diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index e6d249754db40..206346c13aa87 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -240,9 +240,7 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { else CodeModel = M.getCodeModel(); - TargetOptions TargetOpts = - codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); - Conf.ModifyTargetOptions(TargetOpts); + TargetOptions TargetOpts = Conf.InitTargetOptions(TheTriple); if (TargetOpts.MCOptions.ABIName.empty()) { TargetOpts.MCOptions.ABIName = M.getTargetABIFromMD(); diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index b4e9c9787a0d3..c32d1ac815c8f 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -394,11 +394,13 @@ bool LTOCodeGenerator::determineTarget() { if (Config.CPU.empty()) Config.CPU = lto::getThinLTODefaultCPU(MergedModule->getTargetTriple()); - Config.ModifyTargetOptions = [](TargetOptions &Options) { + Config.InitTargetOptions = [](const Triple& TT) { + TargetOptions TO = codegen::InitTargetOptionsFromCodeGenFlags(TT); // If data-sections is not explicitly set or unset, set data-sections by // default to match the behaviour of lld and gold plugin. if (!codegen::getExplicitDataSections()) - Options.DataSections = true; + TO.DataSections = true; + return TO; }; TargetMach = createTargetMachine(); >From 68cbdbbf0e0f44bd1ee9db4cae55434d12d957a8 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 17 Feb 2026 12:41:18 -0800 Subject: [PATCH 19/22] Use const reference --- clang/lib/CodeGen/BackendUtil.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 39505bd82b6ee..3fd97a620fd8d 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1352,7 +1352,8 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex, assert(OptLevelOrNone && "Invalid optimization level!"); Conf.CGOptLevel = *OptLevelOrNone; Conf.OptLevel = CGOpts.OptimizationLevel; - Conf.InitTargetOptions = [&](llvm::Triple TheTriple) -> llvm::TargetOptions { + Conf.InitTargetOptions = + [&](const llvm::Triple &TheTriple) -> llvm::TargetOptions { llvm::TargetOptions TargetOpts = llvm::codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); initTargetOptions(CI, Diags, TargetOpts); >From 1a37ff60b8d157cd6dac14e80433940a32393220 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 17 Feb 2026 12:48:28 -0800 Subject: [PATCH 20/22] Formatting --- lld/COFF/LTO.cpp | 2 +- lld/ELF/LTO.cpp | 1 - llvm/lib/LTO/LTO.cpp | 3 +-- llvm/lib/LTO/LTOBackend.cpp | 1 - llvm/lib/LTO/LTOCodeGenerator.cpp | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index 33e61cb9e5866..537260d0d4a0b 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -20,11 +20,11 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/CodeGen/CommandFlags.h" #include "llvm/DTLTO/DTLTO.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" -#include "llvm/CodeGen/CommandFlags.h" #include "llvm/Support/Caching.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp index 0b9fd008240cc..4852bf3648291 100644 --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -67,7 +67,6 @@ static std::shared_ptr<MemoryBuffer> getBBSectionsMemoryBuffer(Ctx &ctx) { static lto::Config createConfig(Ctx &ctx) { lto::Config c; - std::shared_ptr<MemoryBuffer> mbPtr = getBBSectionsMemoryBuffer(ctx); // Set up the callback to modify TargetOptions. diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 3b1364d0ff30e..7011b925cc7b7 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -2468,10 +2468,9 @@ class OutOfProcessThinBackend : public CGThinBackend { void buildCommonRemoteCompilerOptions() { const lto::Config &C = Conf; auto &Ops = CodegenOptions; - Ops.push_back(Saver.save("-O" + Twine(C.OptLevel))); - TargetOptions TO = C.InitTargetOptions(Triple); + TargetOptions TO = C.InitTargetOptions(Triple); if (TO.EmitAddrsig) Ops.push_back("-faddrsig"); if (TO.FunctionSections) diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 206346c13aa87..df654bc06b095 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -241,7 +241,6 @@ createTargetMachine(const Config &Conf, const Target *TheTarget, Module &M) { CodeModel = M.getCodeModel(); TargetOptions TargetOpts = Conf.InitTargetOptions(TheTriple); - if (TargetOpts.MCOptions.ABIName.empty()) { TargetOpts.MCOptions.ABIName = M.getTargetABIFromMD(); } diff --git a/llvm/lib/LTO/LTOCodeGenerator.cpp b/llvm/lib/LTO/LTOCodeGenerator.cpp index c32d1ac815c8f..f491921a85aad 100644 --- a/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -394,7 +394,7 @@ bool LTOCodeGenerator::determineTarget() { if (Config.CPU.empty()) Config.CPU = lto::getThinLTODefaultCPU(MergedModule->getTargetTriple()); - Config.InitTargetOptions = [](const Triple& TT) { + Config.InitTargetOptions = [](const Triple &TT) { TargetOptions TO = codegen::InitTargetOptionsFromCodeGenFlags(TT); // If data-sections is not explicitly set or unset, set data-sections by // default to match the behaviour of lld and gold plugin. >From 8e2ac0d7953ac49c646dc488ab27afa33af1b846 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Tue, 17 Feb 2026 16:35:00 -0800 Subject: [PATCH 21/22] Fix gold plugin support for non-default Triple --- llvm/lib/LTO/LTO.cpp | 10 +++++++++- llvm/tools/gold/gold-plugin.cpp | 29 +++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 7011b925cc7b7..9e2ac7e75c012 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -2119,8 +2119,16 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, auto &ModuleMap = ThinLTO.ModulesToCompile ? *ThinLTO.ModulesToCompile : ThinLTO.ModuleMap; + auto GetTripleFromConf = [&]() -> Triple { + if (!Conf.OverrideTriple.empty()) + return Triple(Conf.OverrideTriple); + if (!RegularLTO.CombinedModule->getTargetTriple().empty()) + return RegularLTO.CombinedModule->getTargetTriple(); + return Triple(Conf.DefaultTriple); + }; + auto RunBackends = [&](ThinBackendProc *BackendProcess) -> Error { - const Triple &TheTriple = RegularLTO.CombinedModule->getTargetTriple(); + Triple TheTriple = GetTripleFromConf(); assert(!TheTriple.getTriple().empty() && "Empty TargetTriple for ThinLTO!"); auto ProcessOneModule = [&](int I) -> Error { auto &Mod = *(ModuleMap.begin() + I); diff --git a/llvm/tools/gold/gold-plugin.cpp b/llvm/tools/gold/gold-plugin.cpp index ba2a1699aaea9..342bcc1e2d2eb 100644 --- a/llvm/tools/gold/gold-plugin.cpp +++ b/llvm/tools/gold/gold-plugin.cpp @@ -878,17 +878,23 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite, ThinBackend Backend; Conf.CPU = options::mcpu; - Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple()); - - // Disable the new X86 relax relocations since gold might not support them. - // FIXME: Check the gold version or add a new option to enable them. - Conf.Options.MCOptions.X86RelaxRelocations = false; - - // Toggle function/data sections. - if (!codegen::getExplicitFunctionSections()) - Conf.Options.FunctionSections = SplitSections; - if (!codegen::getExplicitDataSections()) - Conf.Options.DataSections = SplitSections; + Conf.InitTargetOptions = [](const Triple &TheTriple) { + TargetOptions Options = + codegen::InitTargetOptionsFromCodeGenFlags(TheTriple); + + // Disable the new X86 relax relocations since gold might not support them. + // FIXME: Check the gold version or add a new option to enable them. + Options.MCOptions.X86RelaxRelocations = false; + + // Toggle function/data sections. + if (!codegen::getExplicitFunctionSections()) + Options.FunctionSections = SplitSections; + if (!codegen::getExplicitDataSections()) + Options.DataSections = SplitSections; + if (options::TheOutputType == options::OT_ASM_ONLY) + Options.MCOptions.AsmVerbose = true; + return Options; + }; Conf.MAttrs = codegen::getMAttrs(); Conf.RelocModel = RelocationModel; @@ -952,7 +958,6 @@ static std::unique_ptr<LTO> createLTO(IndexWriteCallback OnIndexWrite, break; case options::OT_ASM_ONLY: Conf.CGFileType = CodeGenFileType::AssemblyFile; - Conf.Options.MCOptions.AsmVerbose = true; break; } >From f5162523b086a9a740d26718096727bbeaf48987 Mon Sep 17 00:00:00 2001 From: Paul Kirth <[email protected]> Date: Thu, 19 Feb 2026 16:35:37 -0800 Subject: [PATCH 22/22] Add LTO tests that exercise TargetOptions --- llvm/test/LTO/X86/default-tlsdesc.ll | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 llvm/test/LTO/X86/default-tlsdesc.ll diff --git a/llvm/test/LTO/X86/default-tlsdesc.ll b/llvm/test/LTO/X86/default-tlsdesc.ll new file mode 100644 index 0000000000000..c8a4e66fac03d --- /dev/null +++ b/llvm/test/LTO/X86/default-tlsdesc.ll @@ -0,0 +1,26 @@ +;; Test that Fuchsia enables TLSDESC by default during LTO. +; RUN: opt -mtriple=x86_64-unknown-fuchsia < %s > %t.bc +; RUN: llvm-lto -exported-symbol=f -relocation-model=pic -o %t.o %t.bc +; RUN: llvm-readelf -r %t.o | FileCheck %s --check-prefix=FUCHSIA + +; RUN: opt -mtriple=x86_64-unknown-fuchsia -module-summary -o %t.thin.bc %s +; RUN: llvm-lto2 run -r %t.thin.bc,f,plx -r %t.thin.bc,x, -relocation-model=pic -o %t.thin.o %t.thin.bc +; RUN: llvm-readelf -r %t.thin.o.1 | FileCheck %s --check-prefix=FUCHSIA + +;; Test that Linux does not enable TLSDESC by default during LTO. +; RUN: llvm-lto2 run -r %t.thin.bc,f,plx -r %t.thin.bc,x, -override-triple=x86_64-unknown-linux -relocation-model=pic -o %t.linux.o %t.thin.bc +; RUN: llvm-readelf -r %t.linux.o.1 | FileCheck %s --check-prefix=LINUX + +declare ptr @llvm.threadlocal.address.p0(ptr) + +@x = external thread_local global i32, align 4 + +define ptr @f() { +entry: + %1 = tail call ptr @llvm.threadlocal.address.p0(ptr @x) + ; FUCHSIA: R_X86_64_GOTPC32_TLSDESC + ; FUCHSIA: R_X86_64_TLSDESC_CALL + ; LINUX: R_X86_64_TLSGD + ; LINUX: R_X86_64_PLT32 {{.*}}__tls_get_addr + ret ptr %1 +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
