diff --git a/src/Compilation.zig b/src/Compilation.zig index fc2e25febf..be501646a3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5399,8 +5399,10 @@ pub fn addCCArgs( }, } - if (comp.config.lto) { - try argv.append("-flto"); + switch (comp.config.lto) { + .none => try argv.append("-fno-lto"), + .full => try argv.append("-flto=full"), + .thin => try argv.append("-flto=thin"), } // This only works for preprocessed files. Guarded by `FileExt.clangSupportsDepFile`. @@ -6450,7 +6452,7 @@ pub fn build_crt_file( .link_libc = false, .lto = switch (output_mode) { .Lib => comp.config.lto, - .Obj, .Exe => false, + .Obj, .Exe => .none, }, }); const root_mod = try Package.Module.create(arena, .{ diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index baaa6c9f47..e91055709c 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -48,7 +48,7 @@ use_lib_llvm: bool, /// and updates the final binary. use_lld: bool, c_frontend: CFrontend, -lto: bool, +lto: LtoMode, /// WASI-only. Type of WASI execution model ("command" or "reactor"). /// Always set to `command` for non-WASI targets. wasi_exec_model: std.builtin.WasiExecModel, @@ -65,6 +65,8 @@ san_cov_trace_pc_guard: bool, pub const CFrontend = enum { clang, aro }; +pub const LtoMode = enum { none, full, thin }; + pub const DebugFormat = union(enum) { strip, dwarf: std.dwarf.Format, @@ -101,7 +103,7 @@ pub const Options = struct { use_lib_llvm: ?bool = null, use_lld: ?bool = null, use_clang: ?bool = null, - lto: ?bool = null, + lto: ?LtoMode = null, /// WASI-only. Type of WASI execution model ("command" or "reactor"). wasi_exec_model: ?std.builtin.WasiExecModel = null, import_memory: ?bool = null, @@ -258,7 +260,7 @@ pub fn resolve(options: Options) ResolveError!Config { break :b false; } - if (options.lto == true) { + if (options.lto != null and options.lto != .none) { if (options.use_lld == false) return error.LtoRequiresLld; break :b true; } @@ -284,16 +286,16 @@ pub fn resolve(options: Options) ResolveError!Config { break :b .clang; }; - const lto = b: { + const lto: LtoMode = b: { if (!use_lld) { // zig ld LTO support is tracked by // https://github.com/ziglang/zig/issues/8680 - if (options.lto == true) return error.LtoRequiresLld; - break :b false; + if (options.lto != null and options.lto != .none) return error.LtoRequiresLld; + break :b .none; } if (options.lto) |x| break :b x; - if (!options.any_c_source_files) break :b false; + if (!options.any_c_source_files) break :b .none; // https://github.com/llvm/llvm-project/pull/116537 switch (target.abi) { @@ -303,15 +305,15 @@ pub fn resolve(options: Options) ResolveError!Config { .ilp32, .muslabin32, .muslx32, - => break :b false, + => break :b .none, else => {}, } break :b switch (options.output_mode) { - .Lib, .Obj => false, + .Lib, .Obj => .none, .Exe => switch (root_optimize_mode) { - .Debug => false, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => true, + .Debug => .none, + .ReleaseSafe, .ReleaseFast, .ReleaseSmall => .full, }, }; }; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index f14d58459f..fddbd07312 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1056,7 +1056,7 @@ pub const Object = struct { time_report: bool, sanitize_thread: bool, fuzz: bool, - lto: bool, + lto: Compilation.Config.LtoMode, }; pub fn emit(o: *Object, options: EmitOptions) !void { @@ -1338,7 +1338,7 @@ pub const Object = struct { .time_report = options.time_report, .tsan = options.sanitize_thread, .sancov = options.fuzz, - .lto = options.lto, + .lto = options.lto != .none, // https://github.com/ziglang/zig/issues/21215 .allow_fast_isel = !comp.root_mod.resolved_target.result.cpu.arch.isMIPS(), .asm_filename = null, diff --git a/src/libunwind.zig b/src/libunwind.zig index 4b3583e1cd..63e4ac26e0 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -37,7 +37,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .root_strip = comp.compilerRtStrip(), .link_libc = true, // Disable LTO to avoid https://github.com/llvm/llvm-project/issues/56825 - .lto = false, + .lto = .none, }) catch |err| { comp.setMiscFailure( .libunwind, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 6ce9924045..1242385b26 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1859,7 +1859,7 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: if (comp.version) |version| { try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); } - if (comp.config.lto) { + if (comp.config.lto != .none) { switch (optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-OPT:lldlto=2"), diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 4e6bab756c..716a1ee59c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1640,7 +1640,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s // copy when generating relocatables. Normally, we would expect `lld -r` to work. // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails // before even generating the relocatable. - if (output_mode == .Obj and (comp.config.lto or target.cpu.arch.isBpf())) { + if (output_mode == .Obj and (comp.config.lto != .none or target.cpu.arch.isBpf())) { // In this case we must do a simple file copy // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. @@ -1683,7 +1683,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); } - if (comp.config.lto) { + if (comp.config.lto != .none) { switch (comp.root_mod.optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("--lto-O2"), diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index ec13a75f2c..7bb1d8c476 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -3537,7 +3537,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); try argv.append("--error-limit=0"); - if (comp.config.lto) { + if (comp.config.lto != .none) { switch (comp.root_mod.optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-O2"), diff --git a/src/main.zig b/src/main.zig index 36c2ccdad7..7bb51bbd8e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1386,9 +1386,18 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-PIE")) { create_module.opts.pie = false; } else if (mem.eql(u8, arg, "-flto")) { - create_module.opts.lto = true; + create_module.opts.lto = .full; + } else if (mem.startsWith(u8, arg, "-flto=")) { + const mode = arg["-flto=".len..]; + if (mem.eql(u8, mode, "full")) { + create_module.opts.lto = .full; + } else if (mem.eql(u8, mode, "thin")) { + create_module.opts.lto = .thin; + } else { + fatal("Invalid -flto mode: '{s}'. Must be 'full'or 'thin'.", .{mode}); + } } else if (mem.eql(u8, arg, "-fno-lto")) { - create_module.opts.lto = false; + create_module.opts.lto = .none; } else if (mem.eql(u8, arg, "-funwind-tables")) { mod_opts.unwind_tables = .sync; } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) { @@ -1958,8 +1967,20 @@ fn buildOutputType( .no_pic => mod_opts.pic = false, .pie => create_module.opts.pie = true, .no_pie => create_module.opts.pie = false, - .lto => create_module.opts.lto = true, - .no_lto => create_module.opts.lto = false, + .lto => { + if (mem.eql(u8, it.only_arg, "flto") or + mem.eql(u8, it.only_arg, "auto") or + mem.eql(u8, it.only_arg, "full") or + mem.eql(u8, it.only_arg, "jobserver")) + { + create_module.opts.lto = .full; + } else if (mem.eql(u8, it.only_arg, "thin")) { + create_module.opts.lto = .thin; + } else { + fatal("Invalid -flto mode: '{s}'. Must be 'auto', 'full', 'thin', or 'jobserver'.", .{it.only_arg}); + } + }, + .no_lto => create_module.opts.lto = .none, .red_zone => mod_opts.red_zone = true, .no_red_zone => mod_opts.red_zone = false, .omit_frame_pointer => mod_opts.omit_frame_pointer = true,