From 12de7e3472cb2292e75578d33a8b8cc91f1ef0b0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Dec 2023 15:25:06 -0700 Subject: WIP: move many global settings to become per-Module Much of the logic from Compilation.create() is extracted into Compilation.Config.resolve() which accepts many optional settings and produces concrete settings. This separate step is needed by API users of Compilation so that they can pass the resolved global settings to the Module creation function, which itself needs to resolve per-Module settings. Since the target and other things are no longer global settings, I did not want them stored in link.File (in the `options` field). That options field was already a kludge; those options should be resolved into concrete settings. This commit also starts to work on that, deleting link.Options, moving the fields into Compilation and ObjectFormat-specific structs instead. Some fields were ephemeral and should not have been stored at all, such as symbol_size_hint. The link.File object of Compilation is now a `?*link.File` and `null` when -fno-emit-bin is passed. It is now arena-allocated along with Compilation itself, avoiding some messy cleanup code that was there before. On the command line, it is now possible to configure the standard library itself by using `--mod std` just like any other module. This meant that the CLI needed to create the standard library module rather than having Compilation create it. There are a lot of changes in this commit and it's still not done. I didn't realize how quickly this changeset was going to balloon out of control, and there are still many lines that need to be changed before it even compiles successfully. * introduce std.Build.Cache.HashHelper.oneShot * add error_tracing to std.Build.Module * extract build.zig file generation into src/Builtin.zig * each CSourceFile and RcSourceFile now has a Module owner, which determines some of the C compiler flags. --- src/codegen/llvm.zig | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 70eab9489c..cf6f38a53e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -853,16 +853,9 @@ pub const Object = struct { /// want to iterate over it while adding entries to it. pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); - pub fn create(gpa: Allocator, options: link.Options) !*Object { - const obj = try gpa.create(Object); - errdefer gpa.destroy(obj); - obj.* = try Object.init(gpa, options); - return obj; - } - - pub fn init(gpa: Allocator, options: link.Options) !Object { - const llvm_target_triple = try targetTriple(gpa, options.target); - defer gpa.free(llvm_target_triple); + pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object { + const gpa = options.comp.gpa; + const llvm_target_triple = try targetTriple(arena, options.target); var builder = try Builder.init(.{ .allocator = gpa, @@ -899,19 +892,14 @@ pub const Object = struct { // TODO: the only concern I have with this is WASI as either host or target, should // we leave the paths as relative then? const compile_unit_dir_z = blk: { - var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; if (options.module) |mod| m: { - const d = try mod.root_mod.root.joinStringZ(builder.gpa, ""); + const d = try mod.root_mod.root.joinStringZ(arena, ""); if (d.len == 0) break :m; if (std.fs.path.isAbsolute(d)) break :blk d; - const abs = std.fs.realpath(d, &buf) catch break :blk d; - builder.gpa.free(d); - break :blk try builder.gpa.dupeZ(u8, abs); + break :blk std.fs.realpathAlloc(arena, d) catch d; } - const cwd = try std.process.getCwd(&buf); - break :blk try builder.gpa.dupeZ(u8, cwd); + break :blk try std.process.getCwdAlloc(arena); }; - defer builder.gpa.free(compile_unit_dir_z); builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit( DW.LANG.C99, @@ -989,7 +977,8 @@ pub const Object = struct { } } - return .{ + const obj = try arena.create(Object); + obj.* = .{ .gpa = gpa, .builder = builder, .module = options.module.?, @@ -1009,9 +998,11 @@ pub const Object = struct { .null_opt_usize = .no_init, .struct_field_map = .{}, }; + return obj; } - pub fn deinit(self: *Object, gpa: Allocator) void { + pub fn deinit(self: *Object) void { + const gpa = self.gpa; self.di_map.deinit(gpa); self.di_type_map.deinit(gpa); if (self.builder.useLibLlvm()) { @@ -1028,11 +1019,6 @@ pub const Object = struct { self.* = undefined; } - pub fn destroy(self: *Object, gpa: Allocator) void { - self.deinit(gpa); - gpa.destroy(self); - } - fn locPath( arena: Allocator, opt_loc: ?Compilation.EmitLoc, @@ -2899,7 +2885,7 @@ pub const Object = struct { fn getStackTraceType(o: *Object) Allocator.Error!Type { const mod = o.module; - const std_mod = mod.main_mod.deps.get("std").?; + const std_mod = mod.std_mod; const std_file = (mod.importPkg(std_mod) catch unreachable).file; const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin"); -- cgit v1.2.3 From 2bef0715c740024c515dce73d267ead5af49d1a9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Dec 2023 21:16:49 -0700 Subject: move a large chunk of linker logic away from "options" These options are only supposed to be provided to the initialization functions, resolved, and then computed values stored in the appropriate place (base struct or the object-format-specific structs). Many more to go... --- src/Compilation.zig | 94 +++--- src/Compilation/Config.zig | 36 ++- src/codegen/llvm.zig | 74 +++-- src/link.zig | 133 ++++++--- src/link/C.zig | 54 ++-- src/link/Coff.zig | 25 +- src/link/Coff/lld.zig | 32 +- src/link/Elf.zig | 322 ++++++++++---------- src/link/Elf/ZigObject.zig | 101 ++++--- src/link/MachO.zig | 145 +++++---- src/link/MachO/zld.zig | 159 +++++----- src/link/NvPtx.zig | 48 +-- src/link/Plan9.zig | 152 ++++++---- src/link/SpirV.zig | 59 ++-- src/link/Wasm.zig | 719 +++++++++++++++++++++++++-------------------- src/main.zig | 44 ++- src/musl.zig | 2 +- src/target.zig | 8 + 18 files changed, 1245 insertions(+), 962 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index ca43e2da07..b7cf3c5276 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -69,6 +69,8 @@ root_name: [:0]const u8, cache_mode: CacheMode, include_compiler_rt: bool, objects: []Compilation.LinkObject, +/// Needed only for passing -F args to clang. +framework_dirs: []const []const u8, /// These are *always* dynamically linked. Static libraries will be /// provided as positional arguments. system_libs: std.StringArrayHashMapUnmanaged(SystemLib), @@ -133,6 +135,7 @@ verbose_llvm_ir: ?[]const u8, verbose_llvm_bc: ?[]const u8, verbose_cimport: bool, verbose_llvm_cpu_features: bool, +verbose_link: bool, disable_c_depfile: bool, time_report: bool, stack_report: bool, @@ -220,6 +223,8 @@ emit_llvm_bc: ?EmitLoc, work_queue_wait_group: WaitGroup = .{}, astgen_wait_group: WaitGroup = .{}, +llvm_opt_bisect_limit: c_int, + pub const Emit = struct { /// Where the output will go. directory: Directory, @@ -340,7 +345,7 @@ const Job = union(enum) { /// one of WASI libc static objects wasi_libc_crt_file: wasi_libc.CRTFile, - /// The value is the index into `link.File.Options.system_libs`. + /// The value is the index into `system_libs`. windows_import_lib: usize, }; @@ -819,6 +824,20 @@ pub const cache_helpers = struct { addEmitLoc(hh, optional_emit_loc orelse return); } + pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?link.File.DebugFormat) void { + hh.add(x != null); + addDebugFormat(hh, x orelse return); + } + + pub fn addDebugFormat(hh: *Cache.HashHelper, x: link.File.DebugFormat) void { + const tag: @typeInfo(link.File.DebugFormat).Union.tag_type.? = x; + hh.add(tag); + switch (x) { + .strip, .code_view => {}, + .dwarf => |f| hh.add(f), + } + } + pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void { _ = try self.addFile(c_source.src_path, null); // Hash the extra flags, with special care to call addFile for file parameters. @@ -846,7 +865,7 @@ pub const ClangPreprocessorMode = enum { stdout, }; -pub const Framework = link.Framework; +pub const Framework = link.File.MachO.Framework; pub const SystemLib = link.SystemLib; pub const CacheMode = link.CacheMode; @@ -952,7 +971,7 @@ pub const InitOptions = struct { linker_print_gc_sections: bool = false, linker_print_icf_sections: bool = false, linker_print_map: bool = false, - linker_opt_bisect_limit: i32 = -1, + llvm_opt_bisect_limit: i32 = -1, each_lib_rpath: ?bool = null, build_id: ?std.zig.BuildId = null, disable_c_depfile: bool = false, @@ -994,7 +1013,7 @@ pub const InitOptions = struct { hash_style: link.HashStyle = .both, entry: ?[]const u8 = null, force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{}, - stack_size_override: ?u64 = null, + stack_size: ?u64 = null, image_base_override: ?u64 = null, version: ?std.SemanticVersion = null, compatibility_version: ?std.SemanticVersion = null, @@ -1007,7 +1026,7 @@ pub const InitOptions = struct { test_name_prefix: ?[]const u8 = null, test_runner_path: ?[]const u8 = null, subsystem: ?std.Target.SubSystem = null, - dwarf_format: ?std.dwarf.Format = null, + debug_format: ?link.File.DebugFormat = null, /// (Zig compiler development) Enable dumping linker's state as JSON. enable_link_snapshots: bool = false, /// (Darwin) Install name of the dylib @@ -1297,7 +1316,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { cache.hash.add(options.config.link_libcpp); cache.hash.add(options.config.link_libunwind); cache.hash.add(output_mode); - cache.hash.addOptional(options.dwarf_format); + cache_helpers.addOptionalDebugFormat(&cache.hash, options.debug_format); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs); @@ -1596,6 +1615,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .verbose_llvm_bc = options.verbose_llvm_bc, .verbose_cimport = options.verbose_cimport, .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features, + .verbose_link = options.verbose_link, .disable_c_depfile = options.disable_c_depfile, .owned_link_dir = owned_link_dir, .color = options.color, @@ -1617,6 +1637,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .libc_installation = libc_dirs.libc_installation, .include_compiler_rt = include_compiler_rt, .objects = options.link_objects, + .framework_dirs = options.framework_dirs, + .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, }; if (bin_file_emit) |emit| { @@ -1636,7 +1658,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .z_max_page_size = options.linker_z_max_page_size, .darwin_sdk_layout = libc_dirs.darwin_sdk_layout, .frameworks = options.frameworks, - .framework_dirs = options.framework_dirs, .wasi_emulated_libs = options.wasi_emulated_libs, .lib_dirs = options.lib_dirs, .rpath_list = options.rpath_list, @@ -1659,13 +1680,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .print_gc_sections = options.linker_print_gc_sections, .print_icf_sections = options.linker_print_icf_sections, .print_map = options.linker_print_map, - .opt_bisect_limit = options.linker_opt_bisect_limit, .tsaware = options.linker_tsaware, .nxcompat = options.linker_nxcompat, .dynamicbase = options.linker_dynamicbase, .major_subsystem_version = options.major_subsystem_version, .minor_subsystem_version = options.minor_subsystem_version, - .stack_size_override = options.stack_size_override, + .stack_size = options.stack_size, .image_base_override = options.image_base_override, .version_script = options.version_script, .gc_sections = options.linker_gc_sections, @@ -1674,7 +1694,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .rdynamic = options.rdynamic, .soname = options.soname, .compatibility_version = options.compatibility_version, - .verbose_link = options.verbose_link, .dll_export_fns = dll_export_fns, .skip_linker_dependencies = options.skip_linker_dependencies, .parent_compilation_link_libc = options.parent_compilation_link_libc, @@ -1682,7 +1701,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .build_id = build_id, .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, .subsystem = options.subsystem, - .dwarf_format = options.dwarf_format, + .debug_format = options.debug_format, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, .install_name = options.install_name, @@ -1826,7 +1845,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { // When linking mingw-w64 there are some import libs we always need. for (mingw.always_link_libs) |name| { - try comp.bin_file.options.system_libs.put(comp.gpa, name, .{ + try comp.system_libs.put(comp.gpa, name, .{ .needed = false, .weak = false, .path = null, @@ -1835,7 +1854,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } // Generate Windows import libs. if (target.os.tag == .windows) { - const count = comp.bin_file.options.system_libs.count(); + const count = comp.system_libs.count(); try comp.work_queue.ensureUnusedCapacity(count); for (0..count) |i| { comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i }); @@ -2450,7 +2469,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc); - man.hash.addOptional(comp.bin_file.options.stack_size_override); + man.hash.add(comp.bin_file.stack_size); man.hash.addOptional(comp.bin_file.options.image_base_override); man.hash.addOptional(comp.bin_file.options.gc_sections); man.hash.add(comp.bin_file.options.eh_frame_hdr); @@ -2460,7 +2479,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.addListOfBytes(comp.bin_file.options.rpath_list); man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); man.hash.add(comp.bin_file.options.each_lib_rpath); - man.hash.add(comp.bin_file.options.build_id); + man.hash.add(comp.bin_file.build_id); man.hash.add(comp.bin_file.options.skip_linker_dependencies); man.hash.add(comp.bin_file.options.z_nodelete); man.hash.add(comp.bin_file.options.z_notext); @@ -2488,9 +2507,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes } man.hash.addOptionalBytes(comp.bin_file.options.soname); man.hash.addOptional(comp.bin_file.options.version); - try link.hashAddSystemLibs(man, comp.bin_file.options.system_libs); + try link.hashAddSystemLibs(man, comp.system_libs); man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys()); - man.hash.addOptional(comp.bin_file.options.allow_shlib_undefined); + man.hash.addOptional(comp.bin_file.allow_shlib_undefined); man.hash.add(comp.bin_file.options.bind_global_refs_locally); man.hash.add(comp.bin_file.options.tsan); man.hash.addOptionalBytes(comp.bin_file.options.sysroot); @@ -2505,7 +2524,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.addOptional(comp.bin_file.options.global_base); // Mach-O specific stuff - man.hash.addListOfBytes(comp.bin_file.options.framework_dirs); + man.hash.addListOfBytes(comp.framework_dirs); try link.hashAddFrameworks(man, comp.bin_file.options.frameworks); try man.addOptionalFile(comp.bin_file.options.entitlements); man.hash.addOptional(comp.bin_file.options.pagezero_size); @@ -3561,7 +3580,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v const named_frame = tracy.namedFrame("windows_import_lib"); defer named_frame.end(); - const link_lib = comp.bin_file.options.system_libs.keys()[index]; + const link_lib = comp.system_libs.keys()[index]; mingw.buildImportLib(comp, link_lib) catch |err| { // TODO Surface more error details. comp.lockAndSetMiscFailure( @@ -4964,7 +4983,7 @@ pub fn addCCArgs( try argv.appendSlice(&.{ "-iframework", framework_dir }); } - for (comp.bin_file.options.framework_dirs) |framework_dir| { + for (comp.framework_dirs) |framework_dir| { try argv.appendSlice(&.{ "-F", framework_dir }); } @@ -5219,22 +5238,21 @@ pub fn addCCArgs( }, } - if (!comp.bin_file.options.strip) { - switch (target.ofmt) { - .coff => { - // -g is required here because -gcodeview doesn't trigger debug info - // generation, it only changes the type of information generated. - try argv.appendSlice(&.{ "-g", "-gcodeview" }); - }, - .elf, .macho => { - try argv.append("-gdwarf-4"); - if (comp.bin_file.options.dwarf_format) |f| switch (f) { - .@"32" => try argv.append("-gdwarf32"), - .@"64" => try argv.append("-gdwarf64"), - }; - }, - else => try argv.append("-g"), - } + try argv.ensureUnusedCapacity(2); + switch (comp.bin_file.debug_format) { + .strip => {}, + .code_view => { + // -g is required here because -gcodeview doesn't trigger debug info + // generation, it only changes the type of information generated. + argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" }); + }, + .dwarf => |f| { + argv.appendAssumeCapacity("-gdwarf-4"); + switch (f) { + .@"32" => argv.appendAssumeCapacity("-gdwarf32"), + .@"64" => argv.appendAssumeCapacity("-gdwarf64"), + } + }, } if (target_util.llvmMachineAbi(target)) |mabi| { @@ -6306,7 +6324,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { // This happens when an `extern "foo"` function is referenced. // If we haven't seen this library yet and we're targeting Windows, we need // to queue up a work item to produce the DLL import library for this. - const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name); + const gop = try comp.system_libs.getOrPut(comp.gpa, lib_name); if (!gop.found_existing and comp.getTarget().os.tag == .windows) { gop.value_ptr.* = .{ .needed = true, @@ -6314,7 +6332,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { .path = null, }; try comp.work_queue.writeItem(.{ - .windows_import_lib = comp.bin_file.options.system_libs.count() - 1, + .windows_import_lib = comp.system_libs.count() - 1, }); } } diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 0b9c70fc42..fe33a18c0a 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -137,7 +137,11 @@ pub fn resolve(options: Options) !Config { const use_llvm = b: { // If emitting to LLVM bitcode object format, must use LLVM backend. if (options.emit_llvm_ir or options.emit_llvm_bc) { - if (options.use_llvm == false) return error.EmittingLlvmModuleRequiresLlvmBackend; + if (options.use_llvm == false) + return error.EmittingLlvmModuleRequiresLlvmBackend; + if (!target_util.hasLlvmSupport(target, target.ofmt)) + return error.LlvmLacksTargetSupport; + break :b true; } @@ -147,6 +151,12 @@ pub fn resolve(options: Options) !Config { break :b false; } + // If Zig does not support the target, then we can't use it. + if (target_util.zigBackend(target, false) == .other) { + if (options.use_llvm == false) return error.ZigLacksTargetSupport; + break :b true; + } + if (options.use_llvm) |x| break :b x; // If we have no zig code to compile, no need for LLVM. @@ -166,16 +176,23 @@ pub fn resolve(options: Options) !Config { break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target); }; - if (!use_lib_llvm and use_llvm and options.emit_bin) { - // Explicit request to use LLVM to produce an object file, but without - // using LLVM libraries. Impossible. - return error.EmittingBinaryRequiresLlvmLibrary; + if (options.emit_bin) { + if (!use_lib_llvm and use_llvm) { + // Explicit request to use LLVM to produce an object file, but without + // using LLVM libraries. Impossible. + return error.EmittingBinaryRequiresLlvmLibrary; + } + + if (target_util.zigBackend(target, use_llvm) == .other) { + // There is no compiler backend available for this target. + return error.ZigLacksTargetSupport; + } } // Make a decision on whether to use LLD or our own linker. const use_lld = b: { - if (target.isDarwin()) { - if (options.use_lld == true) return error.LldIncompatibleOs; + if (!target_util.hasLldSupport(target.ofmt)) { + if (options.use_lld == true) return error.LldIncompatibleObjectFormat; break :b false; } @@ -184,11 +201,6 @@ pub fn resolve(options: Options) !Config { break :b false; } - if (target.ofmt == .c) { - if (options.use_lld == true) return error.LldIncompatibleObjectFormat; - break :b false; - } - if (options.lto == true) { if (options.use_lld == false) return error.LtoRequiresLld; break :b true; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index cf6f38a53e..57e5770d89 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -854,15 +854,21 @@ pub const Object = struct { pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object { - const gpa = options.comp.gpa; - const llvm_target_triple = try targetTriple(arena, options.target); + if (build_options.only_c) unreachable; + const comp = options.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; + const llvm_target_triple = try targetTriple(arena, target); + const strip = comp.root_mod.strip; + const optimize_mode = comp.root_mod.optimize_mode; + const pic = comp.root_mod.pic; var builder = try Builder.init(.{ .allocator = gpa, - .use_lib_llvm = options.use_lib_llvm, - .strip = options.strip or !options.use_lib_llvm, // TODO - .name = options.root_name, - .target = options.target, + .use_lib_llvm = comp.config.use_lib_llvm, + .strip = strip or !comp.config.use_lib_llvm, // TODO + .name = comp.root_name, + .target = target, .triple = llvm_target_triple, }); errdefer builder.deinit(); @@ -870,10 +876,18 @@ pub const Object = struct { var target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void = undefined; var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined; if (builder.useLibLlvm()) { - if (!options.strip) { - switch (options.target.ofmt) { - .coff => builder.llvm.module.?.addModuleCodeViewFlag(), - else => builder.llvm.module.?.addModuleDebugInfoFlag(options.dwarf_format == std.dwarf.Format.@"64"), + debug_info: { + const debug_format = options.debug_format orelse b: { + if (strip) break :b .strip; + break :b switch (target.ofmt) { + .coff => .code_view, + else => .{ .dwarf = .@"32" }, + }; + }; + switch (debug_format) { + .strip => break :debug_info, + .code_view => builder.llvm.module.?.addModuleCodeViewFlag(), + .dwarf => |f| builder.llvm.module.?.addModuleDebugInfoFlag(f == .@"64"), } builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true); @@ -892,8 +906,8 @@ pub const Object = struct { // TODO: the only concern I have with this is WASI as either host or target, should // we leave the paths as relative then? const compile_unit_dir_z = blk: { - if (options.module) |mod| m: { - const d = try mod.root_mod.root.joinStringZ(arena, ""); + if (comp.module) |zcu| m: { + const d = try zcu.root_mod.root.joinStringZ(arena, ""); if (d.len == 0) break :m; if (std.fs.path.isAbsolute(d)) break :blk d; break :blk std.fs.realpathAlloc(arena, d) catch d; @@ -903,9 +917,9 @@ pub const Object = struct { builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit( DW.LANG.C99, - builder.llvm.di_builder.?.createFile(options.root_name, compile_unit_dir_z), + builder.llvm.di_builder.?.createFile(comp.root_name, compile_unit_dir_z), producer.slice(&builder).?, - options.optimize_mode != .Debug, + optimize_mode != .Debug, "", // flags 0, // runtime version "", // split name @@ -914,19 +928,19 @@ pub const Object = struct { ); } - const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) + const opt_level: llvm.CodeGenOptLevel = if (optimize_mode == .Debug) .None else .Aggressive; - const reloc_mode: llvm.RelocMode = if (options.pic) + const reloc_mode: llvm.RelocMode = if (pic) .PIC - else if (options.link_mode == .Dynamic) + else if (comp.config.link_mode == .Dynamic) llvm.RelocMode.DynamicNoPIC else .Static; - const code_model: llvm.CodeModel = switch (options.machine_code_model) { + const code_model: llvm.CodeModel = switch (comp.root_mod.code_model) { .default => .Default, .tiny => .Tiny, .small => .Small, @@ -941,15 +955,15 @@ pub const Object = struct { target_machine = llvm.TargetMachine.create( builder.llvm.target.?, builder.target_triple.slice(&builder).?, - if (options.target.cpu.model.llvm_name) |s| s.ptr else null, - options.llvm_cpu_features, + if (target.cpu.model.llvm_name) |s| s.ptr else null, + comp.root_mod.resolved_target.llvm_cpu_features.?, opt_level, reloc_mode, code_model, - options.function_sections, - options.data_sections, + options.function_sections orelse false, + options.data_sections orelse false, float_abi, - if (target_util.llvmMachineAbi(options.target)) |s| s.ptr else null, + if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, ); errdefer target_machine.dispose(); @@ -958,15 +972,15 @@ pub const Object = struct { builder.llvm.module.?.setModuleDataLayout(target_data); - if (options.pic) builder.llvm.module.?.setModulePICLevel(); - if (options.pie) builder.llvm.module.?.setModulePIELevel(); + if (pic) builder.llvm.module.?.setModulePICLevel(); + if (comp.config.pie) builder.llvm.module.?.setModulePIELevel(); if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model); - if (options.opt_bisect_limit >= 0) { - builder.llvm.context.setOptBisectLimit(std.math.lossyCast(c_int, options.opt_bisect_limit)); + if (comp.llvm_opt_bisect_limit >= 0) { + builder.llvm.context.setOptBisectLimit(comp.llvm_opt_bisect_limit); } - builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = options.target }}); + builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = target }}); if (std.debug.runtime_safety) { const rep = target_data.stringRep(); defer llvm.disposeMessage(rep); @@ -981,13 +995,13 @@ pub const Object = struct { obj.* = .{ .gpa = gpa, .builder = builder, - .module = options.module.?, + .module = comp.module.?, .di_map = .{}, .di_builder = if (builder.useLibLlvm()) builder.llvm.di_builder else null, // TODO .di_compile_unit = if (builder.useLibLlvm()) builder.llvm.di_compile_unit else null, .target_machine = target_machine, .target_data = target_data, - .target = options.target, + .target = target, .decl_map = .{}, .anon_decl_map = .{}, .named_enum_map = .{}, diff --git a/src/link.zig b/src/link.zig index 46dab1b6ed..9685cea391 100644 --- a/src/link.zig +++ b/src/link.zig @@ -32,13 +32,6 @@ pub const SystemLib = struct { path: ?[]const u8, }; -/// When adding a new field, remember to update `hashAddFrameworks`. -pub const Framework = struct { - needed: bool = false, - weak: bool = false, - path: []const u8, -}; - pub const SortSection = enum { name, alignment }; pub const CacheMode = enum { incremental, whole }; @@ -56,14 +49,6 @@ pub fn hashAddSystemLibs( } } -pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void { - for (hm) |value| { - man.hash.add(value.needed); - man.hash.add(value.weak); - _ = try man.addFile(value.path, null); - } -} - pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version; pub const HashStyle = enum { sysv, gnu, both }; @@ -81,6 +66,19 @@ pub const File = struct { /// When linking with LLD, this linker code will output an object file only at /// this location, and then this path can be placed on the LLD linker line. intermediary_basename: ?[]const u8 = null, + disable_lld_caching: bool, + gc_sections: bool, + build_id: std.zig.BuildId, + rpath_list: []const []const u8, + /// List of symbols forced as undefined in the symbol table + /// thus forcing their resolution by the linker. + /// Corresponds to `-u ` for ELF/MachO and `/include:` for COFF/PE. + force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), + allow_shlib_undefined: bool, + stack_size: u64, + debug_format: DebugFormat, + function_sections: bool, + data_sections: bool, /// Prevents other processes from clobbering files in the output directory /// of this linking operation. @@ -88,6 +86,12 @@ pub const File = struct { child_pid: ?std.ChildProcess.Id = null, + pub const DebugFormat = union(enum) { + strip, + dwarf: std.dwarf.Format, + code_view, + }; + pub const OpenOptions = struct { comp: *Compilation, emit: Compilation.Emit, @@ -97,7 +101,7 @@ pub const File = struct { /// Virtual address of the entry point procedure relative to image base. entry_addr: ?u64, - stack_size_override: ?u64, + stack_size: ?u64, image_base_override: ?u64, function_sections: bool, data_sections: bool, @@ -128,7 +132,6 @@ pub const File = struct { max_memory: ?u64, export_symbol_names: []const []const u8, global_base: ?u64, - verbose_link: bool, dll_export_fns: bool, skip_linker_dependencies: bool, parent_compilation_link_libc: bool, @@ -139,7 +142,7 @@ pub const File = struct { sort_section: ?SortSection, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, - gc_sections: ?bool = null, + gc_sections: ?bool, allow_shlib_undefined: ?bool, subsystem: ?std.Target.SubSystem, version_script: ?[]const u8, @@ -147,11 +150,7 @@ pub const File = struct { print_gc_sections: bool, print_icf_sections: bool, print_map: bool, - opt_bisect_limit: i32, - /// List of symbols forced as undefined in the symbol table - /// thus forcing their resolution by the linker. - /// Corresponds to `-u ` for ELF/MachO and `/include:` for COFF/PE. force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), /// Use a wrapper function for symbol. Any undefined reference to symbol /// will be resolved to __wrap_symbol. Any undefined reference to @@ -163,7 +162,7 @@ pub const File = struct { compatibility_version: ?std.SemanticVersion, - dwarf_format: ?std.dwarf.Format, + debug_format: ?DebugFormat, // TODO: remove this. libraries are resolved by the frontend. lib_dirs: []const []const u8, @@ -184,8 +183,7 @@ pub const File = struct { headerpad_max_install_names: bool, /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols dead_strip_dylibs: bool, - framework_dirs: []const []const u8, - frameworks: []const Framework, + frameworks: []const MachO.Framework, darwin_sdk_layout: ?MachO.SdkLayout, /// (Windows) PDB source path prefix to instruct the linker how to resolve relative @@ -228,7 +226,7 @@ pub const File = struct { .coff, .elf, .macho, .plan9, .wasm => { if (build_options.only_c) unreachable; if (base.file != null) return; - const emit = base.options.emit orelse return; + const emit = base.emit; if (base.child_pid) |pid| { if (builtin.os.tag == .windows) { base.cast(Coff).?.ptraceAttach(pid) catch |err| { @@ -256,10 +254,13 @@ pub const File = struct { } } } + const use_lld = build_options.have_llvm and base.comp.config.use_lld; + const output_mode = base.comp.config.output_mode; + const link_mode = base.comp.config.link_mode; base.file = try emit.directory.handle.createFile(emit.sub_path, .{ .truncate = false, .read = true, - .mode = determineMode(base.options), + .mode = determineMode(use_lld, output_mode, link_mode), }); }, .c, .spirv, .nvptx => {}, @@ -267,9 +268,13 @@ pub const File = struct { } pub fn makeExecutable(base: *File) !void { - switch (base.options.output_mode) { + const output_mode = base.comp.config.output_mode; + const link_mode = base.comp.config.link_mode; + const use_lld = build_options.have_llvm and base.comp.config.use_lld; + + switch (output_mode) { .Obj => return, - .Lib => switch (base.options.link_mode) { + .Lib => switch (link_mode) { .Static => return, .Dynamic => {}, }, @@ -278,7 +283,6 @@ pub const File = struct { switch (base.tag) { .elf => if (base.file) |f| { if (build_options.only_c) unreachable; - const use_lld = build_options.have_llvm and base.options.use_lld; if (base.intermediary_basename != null and use_lld) { // The file we have open is not the final file that we want to // make executable, so we don't have to close it. @@ -596,7 +600,7 @@ pub const File = struct { return @fieldParentPtr(C, "base", base).flush(comp, prog_node); } if (comp.clang_preprocessor_mode == .yes) { - const emit = base.options.emit orelse return; // -fno-emit-bin + const emit = base.emit; // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) // Until then, we do `lld -r -o output.o input.o` even though the output is the same // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file @@ -610,8 +614,10 @@ pub const File = struct { return; } - const use_lld = build_options.have_llvm and base.options.use_lld; - if (use_lld and base.options.output_mode == .Lib and base.options.link_mode == .Static) { + const use_lld = build_options.have_llvm and base.comp.config.use_lld; + const output_mode = base.comp.config.output_mode; + const link_mode = base.comp.config.link_mode; + if (use_lld and output_mode == .Lib and link_mode == .Static) { return base.linkAsArchive(comp, prog_node); } switch (base.tag) { @@ -845,8 +851,6 @@ pub const File = struct { } pub fn linkAsArchive(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void { - const emit = base.options.emit orelse return; - const tracy = trace(@src()); defer tracy.end(); @@ -854,22 +858,23 @@ pub const File = struct { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const directory = emit.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{emit.sub_path}); + const directory = base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); const full_out_path_z = try arena.dupeZ(u8, full_out_path); + const opt_zcu = base.comp.module; // If there is no Zig code to compile, then we should skip flushing the output file // because it will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (base.options.module != null) blk: { + const zcu_obj_path: ?[]const u8 = if (opt_zcu != null) blk: { try base.flushModule(comp, prog_node); const dirname = fs.path.dirname(full_out_path_z) orelse "."; break :blk try fs.path.join(arena, &.{ dirname, base.intermediary_basename.? }); } else null; - log.debug("module_obj_path={s}", .{if (module_obj_path) |s| s else "(null)"}); + log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"}); - const compiler_rt_path: ?[]const u8 = if (base.options.include_compiler_rt) + const compiler_rt_path: ?[]const u8 = if (base.comp.include_compiler_rt) comp.compiler_rt_obj.?.full_object_path else null; @@ -881,17 +886,19 @@ pub const File = struct { const id_symlink_basename = "llvm-ar.id"; var man: Cache.Manifest = undefined; - defer if (!base.options.disable_lld_caching) man.deinit(); + defer if (!base.disable_lld_caching) man.deinit(); + + const objects = base.comp.objects; var digest: [Cache.hex_digest_len]u8 = undefined; - if (!base.options.disable_lld_caching) { + if (!base.disable_lld_caching) { man = comp.cache_parent.obtain(); // We are about to obtain this lock, so here we give other processes a chance first. base.releaseLock(); - for (base.options.objects) |obj| { + for (objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); man.hash.add(obj.loption); @@ -904,7 +911,7 @@ pub const File = struct { _ = try man.addFile(key.status.success.res_path, null); } } - try man.addOptionalFile(module_obj_path); + try man.addOptionalFile(zcu_obj_path); try man.addOptionalFile(compiler_rt_path); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. @@ -934,11 +941,11 @@ pub const File = struct { } const win32_resource_table_len = if (build_options.only_core_functionality) 0 else comp.win32_resource_table.count(); - const num_object_files = base.options.objects.len + comp.c_object_table.count() + win32_resource_table_len + 2; + const num_object_files = objects.len + comp.c_object_table.count() + win32_resource_table_len + 2; var object_files = try std.ArrayList([*:0]const u8).initCapacity(base.allocator, num_object_files); defer object_files.deinit(); - for (base.options.objects) |obj| { + for (objects) |obj| { object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj.path)); } for (comp.c_object_table.keys()) |key| { @@ -949,14 +956,14 @@ pub const File = struct { object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path)); } } - if (module_obj_path) |p| { + if (zcu_obj_path) |p| { object_files.appendAssumeCapacity(try arena.dupeZ(u8, p)); } if (compiler_rt_path) |p| { object_files.appendAssumeCapacity(try arena.dupeZ(u8, p)); } - if (base.options.verbose_link) { + if (comp.verbose_link) { std.debug.print("ar rcs {s}", .{full_out_path_z}); for (object_files.items) |arg| { std.debug.print(" {s}", .{arg}); @@ -972,7 +979,7 @@ pub const File = struct { const bad = llvm_bindings.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_tag); if (bad) return error.UnableToWriteArchive; - if (!base.options.disable_lld_caching) { + if (!base.disable_lld_caching) { Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { log.warn("failed to save archive hash digest file: {s}", .{@errorName(err)}); }; @@ -1090,6 +1097,34 @@ pub const File = struct { } } + pub fn isStatic(self: File) bool { + return self.base.options.link_mode == .Static; + } + + pub fn isObject(self: File) bool { + const output_mode = self.comp.config.output_mode; + return output_mode == .Obj; + } + + pub fn isExe(self: File) bool { + const output_mode = self.comp.config.output_mode; + return output_mode == .Exe; + } + + pub fn isStaticLib(self: File) bool { + const output_mode = self.comp.config.output_mode; + return output_mode == .Lib and self.isStatic(); + } + + pub fn isRelocatable(self: File) bool { + return self.isObject() or self.isStaticLib(); + } + + pub fn isDynLib(self: File) bool { + const output_mode = self.comp.config.output_mode; + return output_mode == .Lib and !self.isStatic(); + } + pub const C = @import("link/C.zig"); pub const Coff = @import("link/Coff.zig"); pub const Plan9 = @import("link/Plan9.zig"); diff --git a/src/link/C.zig b/src/link/C.zig index 85d13bf7ec..4e40addcf7 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -5,6 +5,7 @@ const Allocator = std.mem.Allocator; const fs = std.fs; const C = @This(); +const build_options = @import("build_options"); const Module = @import("../Module.zig"); const InternPool = @import("../InternPool.zig"); const Alignment = InternPool.Alignment; @@ -91,28 +92,40 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String { }; } -pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C { +pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { assert(options.target.ofmt == .c); + const optimize_mode = options.comp.root_mod.optimize_mode; + const use_lld = build_options.have_llvm and options.comp.config.use_lld; + const use_llvm = options.comp.config.use_llvm; - if (options.use_llvm) return error.LLVMHasNoCBackend; - if (options.use_lld) return error.LLDHasNoCBackend; + // These are caught by `Compilation.Config.resolve`. + assert(!use_lld); + assert(!use_llvm); - const file = try options.emit.?.directory.handle.createFile(sub_path, .{ + const emit = options.emit; + + const file = try emit.directory.handle.createFile(emit.sub_path, .{ // Truncation is done on `flush`. .truncate = false, .mode = link.determineMode(options), }); errdefer file.close(); - const c_file = try gpa.create(C); - errdefer gpa.destroy(c_file); + const c_file = try arena.create(C); c_file.* = .{ .base = .{ .tag = .c, - .options = options, + .comp = options.comp, + .emit = emit, + .gc_sections = options.gc_sections orelse optimize_mode != .Debug, + .stack_size = options.stack_size orelse 16777216, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = file, - .allocator = gpa, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, }, }; @@ -120,7 +133,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C } pub fn deinit(self: *C) void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; for (self.decl_table.values()) |*db| { db.deinit(gpa); @@ -141,7 +154,7 @@ pub fn deinit(self: *C) void { } pub fn freeDecl(self: *C, decl_index: InternPool.DeclIndex) void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; if (self.decl_table.fetchSwapRemove(decl_index)) |kv| { var decl_block = kv.value; decl_block.deinit(gpa); @@ -155,7 +168,7 @@ pub fn updateFunc( air: Air, liveness: Liveness, ) !void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const func = module.funcInfo(func_index); const decl_index = func.owner_decl; @@ -223,7 +236,7 @@ pub fn updateFunc( } fn updateAnonDecl(self: *C, module: *Module, i: usize) !void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const anon_decl = self.anon_decls.keys()[i]; const fwd_decl = &self.fwd_decl_buf; @@ -285,7 +298,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: InternPool.DeclIndex) ! const tracy = trace(@src()); defer tracy.end(); - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const gop = try self.decl_table.getOrPut(gpa, decl_index); if (!gop.found_existing) { @@ -352,7 +365,8 @@ pub fn flush(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) !void } fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { - var defines = std.ArrayList(u8).init(self.base.allocator); + const gpa = self.base.comp.gpa; + var defines = std.ArrayList(u8).init(gpa); errdefer defines.deinit(); const writer = defines.writer(); switch (target.abi) { @@ -371,7 +385,7 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo sub_prog_node.activate(); defer sub_prog_node.end(); - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const module = self.base.options.module.?; { @@ -520,7 +534,7 @@ fn flushCTypes( pass: codegen.DeclGen.Pass, decl_ctypes: codegen.CType.Store, ) FlushDeclError!void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const mod = self.base.options.module.?; const decl_ctypes_len = decl_ctypes.count(); @@ -601,7 +615,7 @@ fn flushCTypes( } fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const fwd_decl = &self.lazy_fwd_decl_buf; const code = &self.lazy_code_buf; @@ -643,7 +657,7 @@ fn flushLazyFn( ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMap.Entry, ) FlushDeclError!void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const fwd_decl = &self.lazy_fwd_decl_buf; const code = &self.lazy_code_buf; @@ -683,7 +697,7 @@ fn flushLazyFn( } fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(lazy_fns.count())); var it = lazy_fns.iterator(); @@ -702,7 +716,7 @@ fn flushDeclBlock( export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void), extern_symbol_name: InternPool.OptionalNullTerminatedString, ) FlushDeclError!void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; try self.flushLazyFns(f, decl_block.lazy_fns); try f.all_buffers.ensureUnusedCapacity(gpa, 1); fwd_decl: { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index e477aeffcf..2541d62eac 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -232,7 +232,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff { errdefer self.base.destroy(); const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = build_options.have_llvm and options.comp.config.use_llvm; + const use_llvm = options.comp.config.use_llvm; if (use_lld and use_llvm) { // LLVM emits the object file; LLD links it into the final product. @@ -353,6 +353,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff { pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { const target = options.comp.root_mod.resolved_target.result; + const optimize_mode = options.comp.root_mod.optimize_mode; const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 0...32 => .p32, 33...64 => .p64, @@ -367,14 +368,24 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { .tag = .coff, .comp = options.comp, .emit = options.emit, + .stack_size = options.stack_size orelse 16777216, + .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .code_view, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .ptr_width = ptr_width, .page_size = page_size, .data_directories = comptime mem.zeroes([coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory), }; - const use_llvm = build_options.have_llvm and options.comp.config.use_llvm; + const use_llvm = options.comp.config.use_llvm; if (use_llvm and options.comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, options); } @@ -1494,8 +1505,6 @@ pub fn updateExports( if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports); - if (self.base.options.emit == null) return; - const gpa = self.base.comp.gpa; const metadata = switch (exported) { @@ -1645,13 +1654,7 @@ fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void { } pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { - if (self.base.options.emit == null) { - if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp, prog_node); - } - return; - } - const use_lld = build_options.have_llvm and self.base.options.use_lld; + const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; if (use_lld) { return lld.linkWithLLD(self, comp, prog_node); } diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index 573a85e167..4d4dd840cf 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -25,8 +25,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); + const directory = self.base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. @@ -50,6 +50,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib; const target = self.base.options.target; + const optimize_mode = self.base.comp.root_mod.optimize_mode; // See link/Elf.zig for comments on how this mechanism works. const id_symlink_basename = "lld.id"; @@ -79,7 +80,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } try man.addOptionalFile(module_obj_path); man.hash.addOptionalBytes(self.base.options.entry); - man.hash.addOptional(self.base.options.stack_size_override); + man.hash.add(self.base.stack_size); man.hash.addOptional(self.base.options.image_base_override); man.hash.addListOfBytes(self.base.options.lib_dirs); man.hash.add(self.base.options.skip_linker_dependencies); @@ -93,14 +94,14 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } } - try link.hashAddSystemLibs(&man, self.base.options.system_libs); + try link.hashAddSystemLibs(&man, self.base.comp.system_libs); man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys()); man.hash.addOptional(self.base.options.subsystem); man.hash.add(self.base.options.is_test); man.hash.add(self.base.options.tsaware); man.hash.add(self.base.options.nxcompat); man.hash.add(self.base.options.dynamicbase); - man.hash.addOptional(self.base.options.allow_shlib_undefined); + man.hash.addOptional(self.base.allow_shlib_undefined); // strip does not need to go into the linker hash because it is part of the hash namespace man.hash.addOptional(self.base.options.major_subsystem_version); man.hash.addOptional(self.base.options.minor_subsystem_version); @@ -185,15 +186,14 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); } if (self.base.options.lto) { - switch (self.base.options.optimize_mode) { + switch (optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-OPT:lldlto=2"), .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), } } if (self.base.options.output_mode == .Exe) { - const stack_size = self.base.options.stack_size_override orelse 16777216; - try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size})); + try argv.append(try allocPrint(arena, "-STACK:{d}", .{self.base.stack_size})); } if (self.base.options.image_base_override) |image_base| { try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{image_base})); @@ -232,10 +232,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (!self.base.options.dynamicbase) { try argv.append("-dynamicbase:NO"); } - if (self.base.options.allow_shlib_undefined) |allow_shlib_undefined| { - if (allow_shlib_undefined) { - try argv.append("-FORCE:UNRESOLVED"); - } + if (self.base.allow_shlib_undefined) { + try argv.append("-FORCE:UNRESOLVED"); } try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); @@ -419,7 +417,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib")); for (mingw.always_link_libs) |name| { - if (!self.base.options.system_libs.contains(name)) { + if (!self.base.comp.system_libs.contains(name)) { const lib_basename = try allocPrint(arena, "{s}.lib", .{name}); try argv.append(try comp.get_libc_crt_file(arena, lib_basename)); } @@ -429,7 +427,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod .Dynamic => "", .Static => "lib", }; - const d_str = switch (self.base.options.optimize_mode) { + const d_str = switch (optimize_mode) { .Debug => "d", else => "", }; @@ -489,8 +487,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path); } - try argv.ensureUnusedCapacity(self.base.options.system_libs.count()); - for (self.base.options.system_libs.keys()) |key| { + try argv.ensureUnusedCapacity(self.base.comp.system_libs.count()); + for (self.base.comp.system_libs.keys()) |key| { const lib_basename = try allocPrint(arena, "{s}.lib", .{key}); if (comp.crt_files.get(lib_basename)) |crt_file| { argv.appendAssumeCapacity(crt_file.full_object_path); @@ -516,7 +514,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod return error.DllImportLibraryNotFound; } - if (self.base.options.verbose_link) { + if (self.base.comp.verbose_link) { // Skip over our own name so that the LLD linker name is the first argv item. Compilation.dump_argv(argv.items[1..]); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ef25c63e32..2bab459582 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -206,7 +206,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { assert(target.ofmt == .elf); const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = build_options.have_llvm and options.comp.config.use_llvm; + const use_llvm = options.comp.config.use_llvm; + const opt_zcu = options.comp.module; + const output_mode = options.comp.config.output_mode; + const link_mode = options.comp.config.link_mode; const self = try createEmpty(arena, options); errdefer self.base.destroy(); @@ -216,8 +219,8 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { return self; } - const is_obj = options.output_mode == .Obj; - const is_obj_or_ar = is_obj or (options.output_mode == .Lib and options.link_mode == .Static); + const is_obj = output_mode == .Obj; + const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .Static); const sub_path = if (!use_lld) options.emit.sub_path else p: { // Open a temporary object file, not the final output file because we @@ -229,10 +232,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { break :p o_file_path; }; - self.base.file = try options.emit.?.directory.handle.createFile(sub_path, .{ + self.base.file = try options.emit.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, - .mode = link.determineMode(options), + .mode = link.File.determineMode(use_lld, output_mode, link_mode), }); const gpa = options.comp.gpa; @@ -292,24 +295,34 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { }); } - if (options.module != null and !options.use_llvm) { - const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); - self.files.set(index, .{ .zig_object = .{ - .index = index, - .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem( - options.module.?.main_mod.root_src_path, - )}), - } }); - self.zig_object_index = index; - try self.zigObjectPtr().?.init(self); - try self.initMetadata(); + if (opt_zcu) |zcu| { + if (!use_llvm) { + const index: File.Index = @intCast(try self.files.addOne(gpa)); + self.files.set(index, .{ .zig_object = .{ + .index = index, + .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem( + zcu.main_mod.root_src_path, + )}), + } }); + self.zig_object_index = index; + try self.zigObjectPtr().?.init(self); + try self.initMetadata(.{ + .symbol_count_hint = options.symbol_count_hint, + .program_code_size_hint = options.program_code_size_hint, + }); + } } return self; } pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { + const use_llvm = options.comp.config.use_llvm; + const optimize_mode = options.comp.root_mod.optimize_mode; const target = options.comp.root_mod.resolved_target.result; + const output_mode = options.comp.config.output_mode; + const link_mode = options.comp.config.link_mode; + const is_native_os = options.comp.root_mod.resolved_target.is_native_os; const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 0...32 => .p32, 33...64 => .p64, @@ -322,7 +335,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .sparc64 => 0x2000, else => 0x1000, }; - const is_dyn_lib = options.output_mode == .Lib and options.link_mode == .Dynamic; + const is_dyn_lib = output_mode == .Lib and link_mode == .Dynamic; const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or options.rdynamic) elf.VER_NDX_GLOBAL else @@ -333,13 +346,23 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .tag = .elf, .comp = options.comp, .emit = options.emit, + .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .stack_size = options.stack_size orelse 16777216, + .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os, .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .ptr_width = ptr_width, .page_size = page_size, .default_sym_version = default_sym_version, }; - if (options.use_llvm and options.comp.config.have_zcu) { + if (use_llvm and options.comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, options); } @@ -504,8 +527,13 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 { return start; } +pub const InitMetadataOptions = struct { + symbol_count_hint: u64, + program_code_size_hint: u64, +}; + /// TODO move to ZigObject -pub fn initMetadata(self: *Elf) !void { +pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void { const gpa = self.base.comp.gpa; const ptr_size = self.ptrWidthBytes(); const target = self.base.comp.root_mod.resolved_target.result; @@ -515,7 +543,7 @@ pub fn initMetadata(self: *Elf) !void { const fillSection = struct { fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void { - if (elf_file.isRelocatable()) { + if (elf_file.base.isRelocatable()) { const off = elf_file.findFreeSpace(size, shdr.sh_addralign); shdr.sh_offset = off; shdr.sh_size = size; @@ -530,9 +558,9 @@ pub fn initMetadata(self: *Elf) !void { comptime assert(number_of_zig_segments == 5); - if (!self.isRelocatable()) { + if (!self.base.isRelocatable()) { if (self.phdr_zig_load_re_index == null) { - const filesz = self.base.options.program_code_size_hint; + const filesz = options.program_code_size_hint; const off = self.findFreeSpace(filesz, self.page_size); self.phdr_zig_load_re_index = try self.addPhdr(.{ .type = elf.PT_LOAD, @@ -549,7 +577,7 @@ pub fn initMetadata(self: *Elf) !void { // We really only need ptr alignment but since we are using PROGBITS, linux requires // page align. const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); - const filesz = @as(u64, ptr_size) * self.base.options.symbol_count_hint; + const filesz = @as(u64, ptr_size) * options.symbol_count_hint; const off = self.findFreeSpace(filesz, alignment); self.phdr_zig_got_index = try self.addPhdr(.{ .type = elf.PT_LOAD, @@ -613,8 +641,8 @@ pub fn initMetadata(self: *Elf) !void { .offset = std.math.maxInt(u64), }); const shdr = &self.shdrs.items[self.zig_text_section_index.?]; - fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index); - if (self.isRelocatable()) { + fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index); + if (self.base.isRelocatable()) { const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?); try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{ .shndx = rela_shndx, @@ -630,7 +658,7 @@ pub fn initMetadata(self: *Elf) !void { try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); } - if (self.zig_got_section_index == null and !self.isRelocatable()) { + if (self.zig_got_section_index == null and !self.base.isRelocatable()) { self.zig_got_section_index = try self.addSection(.{ .name = ".got.zig", .type = elf.SHT_PROGBITS, @@ -661,7 +689,7 @@ pub fn initMetadata(self: *Elf) !void { }); const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?]; fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index); - if (self.isRelocatable()) { + if (self.base.isRelocatable()) { const rela_shndx = try self.addRelaShdr( ".rela.data.rel.ro.zig", self.zig_data_rel_ro_section_index.?, @@ -690,7 +718,7 @@ pub fn initMetadata(self: *Elf) !void { }); const shdr = &self.shdrs.items[self.zig_data_section_index.?]; fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index); - if (self.isRelocatable()) { + if (self.base.isRelocatable()) { const rela_shndx = try self.addRelaShdr( ".rela.data.zig", self.zig_data_section_index.?, @@ -930,13 +958,7 @@ pub fn markDirty(self: *Elf, shdr_index: u16) void { } pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { - if (self.base.options.emit == null) { - if (self.llvm_object) |llvm_object| { - try llvm_object.flushModule(comp, prog_node); - } - return; - } - const use_lld = build_options.have_llvm and self.base.options.use_lld; + const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; if (use_lld) { return self.linkWithLLD(comp, prog_node); } @@ -950,7 +972,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node if (self.llvm_object) |llvm_object| { try llvm_object.flushModule(comp, prog_node); - const use_lld = build_options.have_llvm and self.base.options.use_lld; + const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; if (use_lld) return; } @@ -959,13 +981,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node sub_prog_node.activate(); defer sub_prog_node.end(); - var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); const target = self.base.comp.root_mod.resolved_target.result; - const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); + const link_mode = self.base.comp.config.link_mode; + const directory = self.base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: { if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, path }); @@ -973,10 +996,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node break :blk path; } } else null; - const gc_sections = self.base.options.gc_sections orelse false; + const gc_sections = self.base.gc_sections; // --verbose-link - if (self.base.options.verbose_link) try self.dumpArgv(comp); + if (self.base.comp.verbose_link) try self.dumpArgv(comp); const csu = try CsuObjects.init(arena, self.base.options, comp); const compiler_rt_path: ?[]const u8 = blk: { @@ -986,8 +1009,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node }; if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); - if (self.isStaticLib()) return self.flushStaticLib(comp, module_obj_path); - if (self.isObject()) return self.flushObject(comp, module_obj_path); + if (self.base.isStaticLib()) return self.flushStaticLib(comp, module_obj_path); + if (self.base.isObject()) return self.flushObject(comp, module_obj_path); // Here we will parse input positional and library files (if referenced). // This will roughly match in any linker backend we support. @@ -1011,7 +1034,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node if (module_obj_path) |path| try positionals.append(.{ .path = path }); // rpaths - var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator); + var rpath_table = std.StringArrayHashMap(void).init(gpa); defer rpath_table.deinit(); for (self.base.options.rpath_list) |rpath| { @@ -1019,10 +1042,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } if (self.base.options.each_lib_rpath) { - var test_path = std.ArrayList(u8).init(self.base.allocator); + var test_path = std.ArrayList(u8).init(gpa); defer test_path.deinit(); for (self.base.options.lib_dirs) |lib_dir_path| { - for (self.base.options.system_libs.keys()) |link_lib| { + for (self.base.comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; _ = try rpath_table.put(lib_dir_path, {}); @@ -1064,8 +1087,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node var system_libs = std.ArrayList(SystemLib).init(arena); - try system_libs.ensureUnusedCapacity(self.base.options.system_libs.values().len); - for (self.base.options.system_libs.values()) |lib_info| { + try system_libs.ensureUnusedCapacity(self.base.comp.system_libs.values().len); + for (self.base.comp.system_libs.values()) |lib_info| { system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? }); } @@ -1127,7 +1150,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"), }); } else if (target.isMusl()) { - const path = try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { + const path = try comp.get_libc_crt_file(arena, switch (link_mode) { .Static => "libc.a", .Dynamic => "libc.so", }); @@ -1224,7 +1247,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node if (self.entry_index == null) { const entry: ?[]const u8 = entry: { if (self.base.options.entry) |entry| break :entry entry; - if (!self.isDynLib()) break :entry "_start"; + if (!self.base.isDynLib()) break :entry "_start"; break :entry null; }; self.entry_index = if (entry) |name| self.globalByName(name) else null; @@ -1301,7 +1324,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try self.writeAtoms(); try self.writeSyntheticSections(); - if (self.entry_index == null and self.isExe()) { + if (self.entry_index == null and self.base.isExe()) { log.debug("flushing. no_entry_point_found = true", .{}); self.error_flags.no_entry_point_found = true; } else { @@ -1531,13 +1554,15 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) /// --verbose-link output fn dumpArgv(self: *Elf, comp: *Compilation) !void { - var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); + const gpa = self.base.comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); const target = self.base.comp.root_mod.resolved_target.result; - const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); + const link_mode = self.base.comp.config.link_mode; + const directory = self.base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: { if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, path }); @@ -1545,7 +1570,6 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { break :blk path; } } else null; - const gc_sections = self.base.options.gc_sections orelse false; const csu = try CsuObjects.init(arena, self.base.options, comp); const compiler_rt_path: ?[]const u8 = blk: { @@ -1558,20 +1582,20 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("zig"); - if (self.isStaticLib()) { + if (self.base.isStaticLib()) { try argv.append("ar"); } else { try argv.append("ld"); } - if (self.isObject()) { + if (self.base.isObject()) { try argv.append("-r"); } try argv.append("-o"); try argv.append(full_out_path); - if (self.isRelocatable()) { + if (self.base.isRelocatable()) { for (self.base.options.objects) |obj| { try argv.append(obj.path); } @@ -1591,7 +1615,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } } - if (self.isDynLib()) { + if (self.base.isDynLib()) { if (self.base.options.soname) |name| { try argv.append("-soname"); try argv.append(name); @@ -1624,16 +1648,16 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } } - if (self.base.options.stack_size_override) |ss| { - try argv.append("-z"); - try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss})); - } + try argv.appendSlice(&.{ + "-z", + try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}), + }); if (self.base.options.image_base_override) |image_base| { try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base})); } - if (gc_sections) { + if (self.base.gc_sections) { try argv.append("--gc-sections"); } @@ -1666,11 +1690,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { if (self.isStatic()) { try argv.append("-static"); - } else if (self.isDynLib()) { + } else if (self.base.isDynLib()) { try argv.append("-shared"); } - if (self.base.options.pie and self.isExe()) { + if (self.base.options.pie and self.base.isExe()) { try argv.append("-pie"); } @@ -1741,11 +1765,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { // Shared libraries. // Worst-case, we need an --as-needed argument for every lib, as well // as one before and one after. - try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2); + try argv.ensureUnusedCapacity(self.base.comp.system_libs.keys().len * 2 + 2); argv.appendAssumeCapacity("--as-needed"); var as_needed = true; - for (self.base.options.system_libs.values()) |lib_info| { + for (self.base.comp.system_libs.values()) |lib_info| { const lib_as_needed = !lib_info.needed; switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { 0b00, 0b11 => {}, @@ -1780,7 +1804,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { // libc dep if (self.base.options.link_libc) { if (self.base.options.libc_installation != null) { - const needs_grouping = self.base.options.link_mode == .Static; + const needs_grouping = link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); try argv.appendSlice(target_util.libcFullLinkFlags(target)); if (needs_grouping) try argv.append("--end-group"); @@ -1793,7 +1817,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a")); } else if (target.isMusl()) { - try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { + try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) { .Static => "libc.a", .Dynamic => "libc.so", })); @@ -2006,6 +2030,7 @@ fn accessLibPath( lib_name: []const u8, link_mode: ?std.builtin.LinkMode, ) !bool { + const gpa = self.base.comp.gpa; const sep = fs.path.sep_str; const target = self.base.comp.root_mod.resolved_target.result; test_path.clearRetainingCapacity(); @@ -2021,7 +2046,7 @@ fn accessLibPath( suffix, }); if (checked_paths) |cpaths| { - try cpaths.append(try self.base.allocator.dupe(u8, test_path.items)); + try cpaths.append(try gpa.dupe(u8, test_path.items)); } fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { error.FileNotFound => return false, @@ -2150,7 +2175,7 @@ fn markImportsExports(self: *Elf) void { } if (file_ptr.index() == file_index) { global.flags.@"export" = true; - if (elf_file.isDynLib() and vis != .PROTECTED) { + if (elf_file.base.isDynLib() and vis != .PROTECTED) { global.flags.import = true; } } @@ -2158,7 +2183,7 @@ fn markImportsExports(self: *Elf) void { } }.mark; - if (!self.isDynLib()) { + if (!self.base.isDynLib()) { for (self.shared_objects.items) |index| { for (self.file(index).?.globals()) |global_index| { const global = self.symbol(global_index); @@ -2274,12 +2299,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const tracy = trace(@src()); defer tracy.end(); - var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); + const gpa = self.base.comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); + const directory = self.base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. @@ -2298,16 +2324,15 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v sub_prog_node.context.refresh(); defer sub_prog_node.end(); - const is_obj = self.base.options.output_mode == .Obj; - const is_lib = self.base.options.output_mode == .Lib; - const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; - const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe; + const output_mode = self.base.comp.config.output_mode; + const is_obj = output_mode == .Obj; + const is_lib = output_mode == .Lib; + const link_mode = self.base.comp.config.link_mode; + const is_dyn_lib = link_mode == .Dynamic and is_lib; + const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; const have_dynamic_linker = self.base.options.link_libc and - self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib; + link_mode == .Dynamic and is_exe_or_dyn_lib; const target = self.base.comp.root_mod.resolved_target.result; - const gc_sections = self.base.options.gc_sections orelse !is_obj; - const stack_size = self.base.options.stack_size_override orelse 16777216; - const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os; const compiler_rt_path: ?[]const u8 = blk: { if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; @@ -2354,7 +2379,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // installation sources because they are always a product of the compiler version + target information. man.hash.addOptionalBytes(self.base.options.entry); man.hash.addOptional(self.base.options.image_base_override); - man.hash.add(gc_sections); + man.hash.add(self.base.gc_sections); man.hash.addOptional(self.base.options.sort_section); man.hash.add(self.base.options.eh_frame_hdr); man.hash.add(self.base.options.emit_relocs); @@ -2362,9 +2387,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.addListOfBytes(self.base.options.lib_dirs); man.hash.addListOfBytes(self.base.options.rpath_list); man.hash.add(self.base.options.each_lib_rpath); - if (self.base.options.output_mode == .Exe) { - man.hash.add(stack_size); - man.hash.add(self.base.options.build_id); + if (output_mode == .Exe) { + man.hash.add(self.base.stack_size); + man.hash.add(self.base.build_id); } man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); man.hash.add(self.base.options.skip_linker_dependencies); @@ -2390,9 +2415,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } man.hash.addOptionalBytes(self.base.options.soname); man.hash.addOptional(self.base.options.version); - try link.hashAddSystemLibs(&man, self.base.options.system_libs); + try link.hashAddSystemLibs(&man, self.base.comp.system_libs); man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys()); - man.hash.add(allow_shlib_undefined); + man.hash.add(self.base.allow_shlib_undefined); man.hash.add(self.base.options.bind_global_refs_locally); man.hash.add(self.base.options.compress_debug_sections); man.hash.add(self.base.options.tsan); @@ -2432,7 +2457,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // 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 (self.base.options.output_mode == .Obj and + if (output_mode == .Obj and (self.base.options.lto or target.isBpfFreestanding())) { // In this case we must do a simple file copy @@ -2459,7 +2484,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } else { // Create an LLD command line and invoke it. - var argv = std.ArrayList([]const u8).init(self.base.allocator); + var argv = std.ArrayList([]const u8).init(gpa); defer argv.deinit(); // We will invoke ourselves as a child process to gain access to LLD. // This is necessary because LLD does not behave properly as a library - @@ -2503,15 +2528,17 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v .both => {}, // this is the default } - if (self.base.options.output_mode == .Exe) { - try argv.append("-z"); - try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); + if (output_mode == .Exe) { + try argv.appendSlice(&.{ + "-z", + try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}), + }); - switch (self.base.options.build_id) { + switch (self.base.build_id) { .none => {}, .fast, .uuid, .sha1, .md5 => { try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ - @tagName(self.base.options.build_id), + @tagName(self.base.build_id), })); }, .hexstring => |hs| { @@ -2536,7 +2563,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(arg); } - if (gc_sections) { + if (self.base.gc_sections) { try argv.append("--gc-sections"); } @@ -2615,7 +2642,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(arg); } - if (self.base.options.link_mode == .Static) { + if (link_mode == .Static) { if (target.cpu.arch.isArmOrThumb()) { try argv.append("-Bstatic"); } else { @@ -2625,7 +2652,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("-shared"); } - if (self.base.options.pie and self.base.options.output_mode == .Exe) { + if (self.base.options.pie and output_mode == .Exe) { try argv.append("-pie"); } @@ -2648,7 +2675,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v if (csu.crtbegin) |v| try argv.append(v); // rpaths - var rpath_table = std.StringHashMap(void).init(self.base.allocator); + var rpath_table = std.StringHashMap(void).init(gpa); defer rpath_table.deinit(); for (self.base.options.rpath_list) |rpath| { if ((try rpath_table.fetchPut(rpath, {})) == null) { @@ -2664,7 +2691,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v if (self.base.options.each_lib_rpath) { var test_path = std.ArrayList(u8).init(arena); for (self.base.options.lib_dirs) |lib_dir_path| { - for (self.base.options.system_libs.keys()) |link_lib| { + for (self.base.comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) { @@ -2763,8 +2790,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // Shared libraries. if (is_exe_or_dyn_lib) { - const system_libs = self.base.options.system_libs.keys(); - const system_libs_values = self.base.options.system_libs.values(); + const system_libs = self.base.comp.system_libs.keys(); + const system_libs_values = self.base.comp.system_libs.values(); // Worst-case, we need an --as-needed argument for every lib, as well // as one before and one after. @@ -2813,7 +2840,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v self.error_flags.missing_libc = false; if (self.base.options.link_libc) { if (self.base.options.libc_installation != null) { - const needs_grouping = self.base.options.link_mode == .Static; + const needs_grouping = link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); try argv.appendSlice(target_util.libcFullLinkFlags(target)); if (needs_grouping) try argv.append("--end-group"); @@ -2826,7 +2853,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a")); } else if (target.isMusl()) { - try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { + try argv.append(try comp.get_libc_crt_file(arena, switch (link_mode) { .Static => "libc.a", .Dynamic => "libc.so", })); @@ -2847,7 +2874,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v if (csu.crtend) |v| try argv.append(v); if (csu.crtn) |v| try argv.append(v); - if (allow_shlib_undefined) { + if (self.base.allow_shlib_undefined) { try argv.append("--allow-shlib-undefined"); } @@ -2861,7 +2888,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("-Bsymbolic"); } - if (self.base.options.verbose_link) { + if (self.base.comp.verbose_link) { // Skip over our own name so that the LLD linker name is the first argv item. Compilation.dump_argv(argv.items[1..]); } @@ -3087,10 +3114,12 @@ fn writeElfHeader(self: *Elf) !void { assert(index == 16); - const elf_type: elf.ET = switch (self.base.options.output_mode) { + const output_mode = self.base.comp.config.output_mode; + const link_mode = self.base.comp.config.link_mode; + const elf_type: elf.ET = switch (output_mode) { .Exe => if (self.base.options.pie) .DYN else .EXEC, .Obj => .REL, - .Lib => switch (self.base.options.link_mode) { + .Lib => switch (link_mode) { .Static => @as(elf.ET, .REL), .Dynamic => .DYN, }, @@ -3216,7 +3245,6 @@ pub fn updateExports( @panic("Attempted to compile for object format that was disabled by build configuration"); } if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports); - if (self.base.options.emit == null) return; return self.zigObjectPtr().?.updateExports(self, mod, exported, exports); } @@ -3280,6 +3308,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void { } fn allocateLinkerDefinedSymbols(self: *Elf) void { + const link_mode = self.base.comp.config.link_mode; + // _DYNAMIC if (self.dynamic_section_index) |shndx| { const shdr = &self.shdrs.items[shndx]; @@ -3362,7 +3392,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { // __rela_iplt_start, __rela_iplt_end if (self.rela_dyn_section_index) |shndx| blk: { - if (self.base.options.link_mode != .Static or self.base.options.pie) break :blk; + if (link_mode != .Static or self.base.options.pie) break :blk; const shdr = &self.shdrs.items[shndx]; const end_addr = shdr.sh_addr + shdr.sh_size; const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); @@ -3531,7 +3561,7 @@ fn initSyntheticSections(self: *Elf) !void { }); } - if (self.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) { + if (self.base.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) { self.dynstrtab_section_index = try self.addSection(.{ .name = ".dynstr", .flags = elf.SHF_ALLOC, @@ -3716,7 +3746,7 @@ fn initSpecialPhdrs(self: *Elf) !void { self.phdr_gnu_stack_index = try self.addPhdr(.{ .type = elf.PT_GNU_STACK, .flags = elf.PF_W | elf.PF_R, - .memsz = self.base.options.stack_size_override orelse 0, + .memsz = self.base.stack_size, .@"align" = 1, }); @@ -3822,7 +3852,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void { try self.dynamic.addNeeded(shared_object, self); } - if (self.isDynLib()) { + if (self.base.isDynLib()) { if (self.base.options.soname) |soname| { try self.dynamic.setSoname(soname, self); } @@ -3837,8 +3867,9 @@ fn sortDynamicSymtab(self: *Elf) void { } fn setVersionSymtab(self: *Elf) !void { + const gpa = self.base.comp.gpa; if (self.versym_section_index == null) return; - try self.versym.resize(self.base.allocator, self.dynsym.count()); + try self.versym.resize(gpa, self.dynsym.count()); self.versym.items[0] = elf.VER_NDX_LOCAL; for (self.dynsym.entries.items, 1..) |entry, i| { const sym = self.symbol(entry.symbol_index); @@ -5597,38 +5628,14 @@ const CsuObjects = struct { }; pub fn calcImageBase(self: Elf) u64 { - if (self.isDynLib()) return 0; - if (self.isExe() and self.base.options.pie) return 0; + if (self.base.isDynLib()) return 0; + if (self.base.isExe() and self.base.options.pie) return 0; return self.base.options.image_base_override orelse switch (self.ptr_width) { .p32 => 0x1000, .p64 => 0x1000000, }; } -pub fn isStatic(self: Elf) bool { - return self.base.options.link_mode == .Static; -} - -pub fn isObject(self: Elf) bool { - return self.base.options.output_mode == .Obj; -} - -pub fn isExe(self: Elf) bool { - return self.base.options.output_mode == .Exe; -} - -pub fn isStaticLib(self: Elf) bool { - return self.base.options.output_mode == .Lib and self.isStatic(); -} - -pub fn isRelocatable(self: Elf) bool { - return self.isObject() or self.isStaticLib(); -} - -pub fn isDynLib(self: Elf) bool { - return self.base.options.output_mode == .Lib and !self.isStatic(); -} - pub fn isZigSection(self: Elf, shndx: u16) bool { inline for (&[_]?u16{ self.zig_text_section_index, @@ -5668,8 +5675,9 @@ fn addPhdr(self: *Elf, opts: struct { filesz: u64 = 0, memsz: u64 = 0, }) error{OutOfMemory}!u16 { + const gpa = self.base.comp.gpa; const index = @as(u16, @intCast(self.phdrs.items.len)); - try self.phdrs.append(self.base.allocator, .{ + try self.phdrs.append(gpa, .{ .p_type = opts.type, .p_flags = opts.flags, .p_offset = opts.offset, @@ -5818,8 +5826,9 @@ pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom { } pub fn addAtom(self: *Elf) !Atom.Index { + const gpa = self.base.comp.gpa; const index = @as(Atom.Index, @intCast(self.atoms.items.len)); - const atom_ptr = try self.atoms.addOne(self.base.allocator); + const atom_ptr = try self.atoms.addOne(gpa); atom_ptr.* = .{ .atom_index = index }; return index; } @@ -5841,7 +5850,8 @@ pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol { } pub fn addSymbol(self: *Elf) !Symbol.Index { - try self.symbols.ensureUnusedCapacity(self.base.allocator, 1); + const gpa = self.base.comp.gpa; + try self.symbols.ensureUnusedCapacity(gpa, 1); const index = blk: { if (self.symbols_free_list.popOrNull()) |index| { log.debug(" (reusing symbol index {d})", .{index}); @@ -5858,8 +5868,9 @@ pub fn addSymbol(self: *Elf) !Symbol.Index { } pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 { + const gpa = self.base.comp.gpa; const fields = @typeInfo(Symbol.Extra).Struct.fields; - try self.symbols_extra.ensureUnusedCapacity(self.base.allocator, fields.len); + try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len); return self.addSymbolExtraAssumeCapacity(extra); } @@ -5959,8 +5970,9 @@ pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateC } pub fn addComdatGroup(self: *Elf) !ComdatGroup.Index { + const gpa = self.base.comp.gpa; const index = @as(ComdatGroup.Index, @intCast(self.comdat_groups.items.len)); - _ = try self.comdat_groups.addOne(self.base.allocator); + _ = try self.comdat_groups.addOne(gpa); return index; } @@ -6023,14 +6035,16 @@ const ErrorWithNotes = struct { }; pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { - try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1); + const gpa = self.base.comp.gpa; + try self.misc_errors.ensureUnusedCapacity(gpa, 1); return self.addErrorWithNotesAssumeCapacity(note_count); } fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { + const gpa = self.base.comp.gpa; const index = self.misc_errors.items.len; const err = self.misc_errors.addOneAssumeCapacity(); - err.* = .{ .msg = undefined, .notes = try self.base.allocator.alloc(link.File.ErrorMsg, note_count) }; + err.* = .{ .msg = undefined, .notes = try gpa.alloc(link.File.ErrorMsg, note_count) }; return .{ .index = index }; } @@ -6040,9 +6054,10 @@ pub fn getShString(self: Elf, off: u32) [:0]const u8 { } pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 { + const gpa = self.base.comp.gpa; const off = @as(u32, @intCast(self.shstrtab.items.len)); - try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1); - self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable; + try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1); + self.shstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable; return off; } @@ -6052,9 +6067,10 @@ pub fn getDynString(self: Elf, off: u32) [:0]const u8 { } pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 { + const gpa = self.base.comp.gpa; const off = @as(u32, @intCast(self.dynstrtab.items.len)); - try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1); - self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable; + try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1); + self.dynstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable; return off; } diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 7a1fa21435..15ae3bb943 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -76,7 +76,7 @@ pub const symbol_mask: u32 = 0x7fffffff; pub const SHN_ATOM: u16 = 0x100; pub fn init(self: *ZigObject, elf_file: *Elf) !void { - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; try self.atoms.append(gpa, 0); // null input section try self.relocs.append(gpa, .{}); // null relocs section @@ -96,7 +96,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { esym.st_shndx = elf.SHN_ABS; symbol_ptr.esym_index = esym_index; - if (!elf_file.base.options.strip) { + if (elf_file.base.debug_format != .strip) { self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32); } } @@ -155,13 +155,13 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void { // Handle any lazy symbols that were emitted by incremental compilation. if (self.lazy_syms.getPtr(.none)) |metadata| { - const module = elf_file.base.options.module.?; + const zcu = elf_file.base.comp.module.?; // Most lazy symbols can be updated on first use, but // anyerror needs to wait for everything to be flushed. if (metadata.text_state != .unused) self.updateLazySymbol( elf_file, - link.File.LazySymbol.initDecl(.code, null, module), + link.File.LazySymbol.initDecl(.code, null, zcu), metadata.text_symbol_index, ) catch |err| return switch (err) { error.CodegenFail => error.FlushFailure, @@ -169,7 +169,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void { }; if (metadata.rodata_state != .unused) self.updateLazySymbol( elf_file, - link.File.LazySymbol.initDecl(.const_data, null, module), + link.File.LazySymbol.initDecl(.const_data, null, zcu), metadata.rodata_symbol_index, ) catch |err| return switch (err) { error.CodegenFail => error.FlushFailure, @@ -182,7 +182,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void { } if (self.dwarf) |*dw| { - try dw.flushModule(elf_file.base.options.module.?); + const zcu = elf_file.base.comp.module.?; + try dw.flushModule(zcu); // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections // extracted from input object files correctly. @@ -195,7 +196,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void { const text_shdr = elf_file.shdrs.items[elf_file.zig_text_section_index.?]; const low_pc = text_shdr.sh_addr; const high_pc = text_shdr.sh_addr + text_shdr.sh_size; - try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc); + try dw.writeDbgInfoHeader(zcu, low_pc, high_pc); self.debug_info_header_dirty = false; } @@ -268,7 +269,7 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index { } pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index { - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; const atom_index = try elf_file.addAtom(); const symbol_index = try elf_file.addSymbol(); const esym_index = try self.addLocalEsym(gpa); @@ -411,6 +412,7 @@ pub fn allocateTlvAtoms(self: ZigObject, elf_file: *Elf) void { } pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { + const gpa = elf_file.base.comp.gpa; for (self.atoms.items) |atom_index| { const atom = elf_file.atom(atom_index) orelse continue; if (!atom.flags.alive) continue; @@ -421,7 +423,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { // Perhaps it would make sense to save the code until flushModule where we // would free all of generated code? const code = try self.codeAlloc(elf_file, atom_index); - defer elf_file.base.allocator.free(code); + defer gpa.free(code); try atom.scanRelocs(elf_file, code, undefs); } else try atom.scanRelocs(elf_file, null, undefs); } @@ -447,7 +449,7 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void { /// We need this so that we can write to an archive. /// TODO implement writing ZigObject data directly to a buffer instead. pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void { - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; const shsize: u64 = switch (elf_file.ptr_width) { .p32 => @sizeOf(elf.Elf32_Shdr), .p64 => @sizeOf(elf.Elf64_Shdr), @@ -465,7 +467,7 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void { } pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void { - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len); @@ -508,7 +510,7 @@ pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void { const out_shdr = elf_file.shdrs.items[out_shndx]; if (out_shdr.sh_type == elf.SHT_NOBITS) continue; - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; const sec = elf_file.output_rela_sections.getPtr(out_shndx).?; try sec.atom_list.append(gpa, atom_index); } @@ -602,7 +604,7 @@ pub fn asFile(self: *ZigObject) File { /// Returns atom's code. /// Caller owns the memory. pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; const atom = elf_file.atom(atom_index).?; assert(atom.file_index == self.index); const shdr = &elf_file.shdrs.items[atom.outputShndx().?]; @@ -668,8 +670,8 @@ pub fn lowerAnonDecl( explicit_alignment: InternPool.Alignment, src_loc: Module.SrcLoc, ) !codegen.Result { - const gpa = elf_file.base.allocator; - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); const decl_alignment = switch (explicit_alignment) { .none => ty.abiAlignment(mod), @@ -716,8 +718,8 @@ pub fn getOrCreateMetadataForLazySymbol( elf_file: *Elf, lazy_sym: link.File.LazySymbol, ) !Symbol.Index { - const gpa = elf_file.base.allocator; - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod)); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; @@ -752,25 +754,28 @@ pub fn getOrCreateMetadataForLazySymbol( } fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void { + const gpa = elf_file.base.comp.gpa; const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return; for (unnamed_consts.items) |sym_index| { self.freeDeclMetadata(elf_file, sym_index); } - unnamed_consts.clearAndFree(elf_file.base.allocator); + unnamed_consts.clearAndFree(gpa); } fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void { _ = self; + const gpa = elf_file.base.comp.gpa; const sym = elf_file.symbol(sym_index); sym.atom(elf_file).?.free(elf_file); log.debug("adding %{d} to local symbols free list", .{sym_index}); - elf_file.symbols_free_list.append(elf_file.base.allocator, sym_index) catch {}; + elf_file.symbols_free_list.append(gpa, sym_index) catch {}; elf_file.symbols.items[sym_index] = .{}; // TODO free GOT entry here } pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclIndex) void { - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); log.debug("freeDecl {*}", .{decl}); @@ -780,7 +785,7 @@ pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.DeclInd const sym_index = kv.value.symbol_index; self.freeDeclMetadata(elf_file, sym_index); self.freeUnnamedConsts(elf_file, decl_index); - kv.value.exports.deinit(elf_file.base.allocator); + kv.value.exports.deinit(gpa); } if (self.dwarf) |*dw| { @@ -793,15 +798,16 @@ pub fn getOrCreateMetadataForDecl( elf_file: *Elf, decl_index: InternPool.DeclIndex, ) !Symbol.Index { - const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index); + const gpa = elf_file.base.comp.gpa; + const gop = try self.decls.getOrPut(gpa, decl_index); if (!gop.found_existing) { - const single_threaded = elf_file.base.options.single_threaded; + const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; const symbol_index = try self.addAtom(elf_file); - const mod = elf_file.base.options.module.?; + const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); const sym = elf_file.symbol(symbol_index); if (decl.getOwnedVariable(mod)) |variable| { - if (variable.is_threadlocal and !single_threaded) { + if (variable.is_threadlocal and any_non_single_threaded) { sym.flags.is_tls = true; } } @@ -820,13 +826,13 @@ fn getDeclShdrIndex( code: []const u8, ) error{OutOfMemory}!u16 { _ = self; - const mod = elf_file.base.options.module.?; - const single_threaded = elf_file.base.options.single_threaded; + const mod = elf_file.base.comp.module.?; + const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; const shdr_index = switch (decl.ty.zigTypeTag(mod)) { .Fn => elf_file.zig_text_section_index.?, else => blk: { if (decl.getOwnedVariable(mod)) |variable| { - if (variable.is_threadlocal and !single_threaded) { + if (variable.is_threadlocal and any_non_single_threaded) { const is_all_zeroes = for (code) |byte| { if (byte != 0) break false; } else true; @@ -846,9 +852,12 @@ fn getDeclShdrIndex( } if (variable.is_const) break :blk elf_file.zig_data_rel_ro_section_index.?; if (Value.fromInterned(variable.init).isUndefDeep(mod)) { - const mode = elf_file.base.options.optimize_mode; - if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?; - break :blk elf_file.zig_bss_section_index.?; + // TODO: get the optimize_mode from the Module that owns the decl instead + // of using the root module here. + break :blk switch (elf_file.base.comp.root_mod.optimize_mode) { + .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, + .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?, + }; } // TODO I blatantly copied the logic from the Wasm linker, but is there a less // intrusive check for all zeroes than this? @@ -873,8 +882,8 @@ fn updateDeclCode( code: []const u8, stt_bits: u8, ) !void { - const gpa = elf_file.base.allocator; - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); @@ -971,8 +980,8 @@ fn updateTlv( shndx: u16, code: []const u8, ) !void { - const gpa = elf_file.base.allocator; - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); @@ -1026,6 +1035,7 @@ pub fn updateFunc( const tracy = trace(@src()); defer tracy.end(); + const gpa = elf_file.base.comp.gpa; const func = mod.funcInfo(func_index); const decl_index = func.owner_decl; const decl = mod.declPtr(decl_index); @@ -1034,7 +1044,7 @@ pub fn updateFunc( self.freeUnnamedConsts(elf_file, decl_index); elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); - var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator); + var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null; @@ -1117,7 +1127,8 @@ pub fn updateDecl( const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index); elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file); - var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator); + const gpa = elf_file.base.comp.gpa; + var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null; @@ -1179,8 +1190,8 @@ fn updateLazySymbol( sym: link.File.LazySymbol, symbol_index: Symbol.Index, ) !void { - const gpa = elf_file.base.allocator; - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; var required_alignment: InternPool.Alignment = .none; var code_buffer = std.ArrayList(u8).init(gpa); @@ -1261,8 +1272,8 @@ pub fn lowerUnnamedConst( typed_value: TypedValue, decl_index: InternPool.DeclIndex, ) !u32 { - const gpa = elf_file.base.allocator; - const mod = elf_file.base.options.module.?; + const gpa = elf_file.base.comp.gpa; + const mod = elf_file.base.comp.module.?; const gop = try self.unnamed_consts.getOrPut(gpa, decl_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; @@ -1308,7 +1319,7 @@ fn lowerConst( output_section_index: u16, src_loc: Module.SrcLoc, ) !LowerConstResult { - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); @@ -1364,7 +1375,7 @@ pub fn updateExports( const tracy = trace(@src()); defer tracy.end(); - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; const metadata = switch (exported) { .decl_index => |decl_index| blk: { _ = try self.getOrCreateMetadataForDecl(elf_file, decl_index); @@ -1467,7 +1478,7 @@ pub fn deleteDeclExport( name: InternPool.NullTerminatedString, ) void { const metadata = self.decls.getPtr(decl_index) orelse return; - const mod = elf_file.base.options.module.?; + const mod = elf_file.base.comp.module.?; const exp_name = mod.intern_pool.stringToSlice(name); const esym_index = metadata.@"export"(self, exp_name) orelse return; log.debug("deleting export '{s}'", .{exp_name}); @@ -1485,7 +1496,7 @@ pub fn deleteDeclExport( pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 { _ = lib_name; - const gpa = elf_file.base.allocator; + const gpa = elf_file.base.comp.gpa; const off = try self.strtab.insert(gpa, name); const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); if (!lookup_gop.found_existing) { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index f61e78c233..3af98aa42a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -144,6 +144,35 @@ tlv_table: TlvSymbolTable = .{}, hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, darwin_sdk_layout: ?SdkLayout, +/// Size of the __PAGEZERO segment. +pagezero_vmsize: u64, +/// Minimum space for future expansion of the load commands. +headerpad_size: u32, +/// Set enough space as if all paths were MATPATHLEN. +headerpad_max_install_names: bool, +/// Remove dylibs that are unreachable by the entry point or exported symbols. +dead_strip_dylibs: bool, +frameworks: []const Framework, +/// Install name for the dylib. +/// TODO: unify with soname +install_name: ?[]const u8, +/// Path to entitlements file. +entitlements: ?[]const u8, + +/// When adding a new field, remember to update `hashAddFrameworks`. +pub const Framework = struct { + needed: bool = false, + weak: bool = false, + path: []const u8, +}; + +pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void { + for (hm) |value| { + man.hash.add(value.needed); + man.hash.add(value.weak); + _ = try man.addFile(value.path, null); + } +} /// The filesystem layout of darwin SDK elements. pub const SdkLayout = enum { @@ -156,12 +185,14 @@ pub const SdkLayout = enum { pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { if (build_options.only_c) unreachable; const target = options.comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and options.comp.config.use_lld; + const use_llvm = options.comp.config.use_llvm; assert(target.ofmt == .macho); const gpa = options.comp.gpa; const emit = options.emit; const mode: Mode = mode: { - if (options.use_llvm or options.module == null or options.cache_mode == .whole) + if (use_llvm or options.module == null or options.cache_mode == .whole) break :mode .zld; break :mode .incremental; }; @@ -192,7 +223,11 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { const file = try emit.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, - .mode = link.determineMode(options), + .mode = link.File.determineMode( + use_lld, + options.comp.config.output_mode, + options.comp.config.link_mode, + ), }); self.base.file = file; @@ -242,21 +277,37 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { const self = try arena.create(MachO); + const optimize_mode = options.comp.root_mod.optimize_mode; + const use_llvm = options.comp.config.use_llvm; self.* = .{ .base = .{ .tag = .macho, .comp = options.comp, .emit = options.emit, + .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), + .stack_size = options.stack_size orelse 16777216, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, - .mode = if (options.use_llvm or options.module == null or options.cache_mode == .whole) + .mode = if (use_llvm or options.module == null or options.cache_mode == .whole) .zld else .incremental, + .pagezero_vmsize = options.pagezero_size orelse default_pagezero_vmsize, + .headerpad_size = options.headerpad_size orelse default_headerpad_size, + .headerpad_max_install_names = options.headerpad_max_install_names, + .dead_strip_dylibs = options.dead_strip_dylibs, }; - if (options.use_llvm and options.module != null) { + if (use_llvm and options.module != null) { self.llvm_object = try LlvmObject.create(arena, options); } @@ -267,8 +318,9 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { const gpa = self.base.comp.gpa; + const output_mode = self.base.comp.config.output_mode; - if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { + if (output_mode == .Lib and self.base.options.link_mode == .Static) { if (build_options.have_llvm) { return self.base.linkAsArchive(comp, prog_node); } else { @@ -303,6 +355,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No sub_prog_node.activate(); defer sub_prog_node.end(); + const output_mode = self.base.comp.config.output_mode; const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; if (self.lazy_syms.getPtr(.none)) |metadata| { @@ -335,7 +388,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No } var libs = std.StringArrayHashMap(link.SystemLib).init(arena); - try self.resolveLibSystem(arena, comp, &.{}, &libs); + try self.resolveLibSystem(arena, comp, &libs); const id_symlink_basename = "link.id"; @@ -446,7 +499,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.createDyldPrivateAtom(); try self.writeStubHelperPreamble(); - if (self.base.options.output_mode == .Exe and self.getEntryPoint() != null) { + if (output_mode == .Exe and self.getEntryPoint() != null) { const global = self.getEntryPoint().?; if (self.getSymbol(global).undf()) { // We do one additional check here in case the entry point was found in one of the dylibs. @@ -517,8 +570,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No // The most important here is to have the correct vm and filesize of the __LINKEDIT segment // where the code signature goes into. var codesig = CodeSignature.init(getPageSize(self.base.options.target.cpu.arch)); - codesig.code_directory.ident = self.base.options.emit.?.sub_path; - if (self.base.options.entitlements) |path| { + codesig.code_directory.ident = self.base.emit.sub_path; + if (self.entitlements) |path| { try codesig.addEntitlements(gpa, path); } try self.writeCodeSignaturePadding(&codesig); @@ -536,7 +589,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try lc_writer.writeStruct(self.dysymtab_cmd); try load_commands.writeDylinkerLC(lc_writer); - switch (self.base.options.output_mode) { + switch (output_mode) { .Exe => blk: { const seg_id = self.header_segment_cmd_index.?; const seg = self.segments.items[seg_id]; @@ -552,7 +605,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try lc_writer.writeStruct(macho.entry_point_command{ .entryoff = @as(u32, @intCast(addr - seg.vmaddr)), - .stacksize = self.base.options.stack_size_override orelse 0, + .stacksize = self.base.stack_size, }); }, .Lib => if (self.base.options.link_mode == .Dynamic) { @@ -591,7 +644,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No if (codesig) |*csig| { try self.writeCodeSignature(comp, csig); // code signing always comes last - const emit = self.base.options.emit.?; + const emit = self.base.emit; try invalidateKernelCache(emit.directory.handle, emit.sub_path); } @@ -642,34 +695,20 @@ pub fn resolveLibSystem( self: *MachO, arena: Allocator, comp: *Compilation, - search_dirs: []const []const u8, out_libs: anytype, ) !void { - const gpa = self.base.comp.gpa; - var tmp_arena_allocator = std.heap.ArenaAllocator.init(gpa); - defer tmp_arena_allocator.deinit(); - const tmp_arena = tmp_arena_allocator.allocator(); - - var test_path = std.ArrayList(u8).init(tmp_arena); - var checked_paths = std.ArrayList([]const u8).init(tmp_arena); + var test_path = std.ArrayList(u8).init(arena); + var checked_paths = std.ArrayList([]const u8).init(arena); success: { - for (search_dirs) |dir| if (try accessLibPath( - tmp_arena, - &test_path, - &checked_paths, - dir, - "libSystem", - )) break :success; - if (self.base.options.darwin_sdk_layout) |sdk_layout| switch (sdk_layout) { .sdk => { - const dir = try fs.path.join(tmp_arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" }); - if (try accessLibPath(tmp_arena, &test_path, &checked_paths, dir, "libSystem")) break :success; + const dir = try fs.path.join(arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" }); + if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success; }, .vendored => { - const dir = try comp.zig_lib_directory.join(tmp_arena, &[_][]const u8{ "libc", "darwin" }); - if (try accessLibPath(tmp_arena, &test_path, &checked_paths, dir, "libSystem")) break :success; + const dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "darwin" }); + if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success; }, }; @@ -1082,7 +1121,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts, ctx: *ParseErr try self.dylibs.append(gpa, dylib); const should_link_dylib_even_if_unreachable = blk: { - if (self.base.options.dead_strip_dylibs and !dylib_options.needed) break :blk false; + if (self.dead_strip_dylibs and !dylib_options.needed) break :blk false; break :blk !(dylib_options.dependent or self.referenced_dylibs.contains(gop.value_ptr.*)); }; @@ -1597,7 +1636,8 @@ fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: S } pub fn createMhExecuteHeaderSymbol(self: *MachO) !void { - if (self.base.options.output_mode != .Exe) return; + const output_mode = self.base.comp.config.output_mode; + if (output_mode != .Exe) return; const gpa = self.base.comp.gpa; const sym_index = try self.allocateSymbol(); @@ -1647,10 +1687,11 @@ pub fn createDsoHandleSymbol(self: *MachO) !void { } pub fn resolveSymbols(self: *MachO) !void { + const output_mode = self.base.comp.config.output_mode; // We add the specified entrypoint as the first unresolved symbols so that // we search for it in libraries should there be no object files specified // on the linker line. - if (self.base.options.output_mode == .Exe) { + if (output_mode == .Exe) { const entry_name = self.base.options.entry orelse load_commands.default_entry_point; _ = try self.addUndefined(entry_name, .{}); } @@ -1867,9 +1908,10 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { } fn resolveSymbolsAtLoading(self: *MachO) !void { - const is_lib = self.base.options.output_mode == .Lib; + const output_mode = self.base.comp.config.output_mode; + const is_lib = output_mode == .Lib; const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib; - const allow_undef = is_dyn_lib and (self.base.options.allow_shlib_undefined orelse false); + const allow_undef = is_dyn_lib and self.base.allow_shlib_undefined; var next_sym: usize = 0; while (next_sym < self.unresolved.count()) { @@ -2674,12 +2716,12 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 { const val = decl.val; const mod = self.base.options.module.?; const zig_ty = ty.zigTypeTag(mod); - const mode = self.base.options.optimize_mode; - const single_threaded = self.base.options.single_threaded; + const any_non_single_threaded = self.base.comp.config.any_non_single_threaded; + const optimize_mode = self.base.comp.root_mod.optimize_mode; const sect_id: u8 = blk: { // TODO finish and audit this function if (val.isUndefDeep(mod)) { - if (mode == .ReleaseFast or mode == .ReleaseSmall) { + if (optimize_mode == .ReleaseFast or optimize_mode == .ReleaseSmall) { @panic("TODO __DATA,__bss"); } else { break :blk self.data_section_index.?; @@ -2687,7 +2729,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 { } if (val.getVariable(mod)) |variable| { - if (variable.is_threadlocal and !single_threaded) { + if (variable.is_threadlocal and any_non_single_threaded) { break :blk self.thread_data_section_index.?; } break :blk self.data_section_index.?; @@ -2796,8 +2838,6 @@ pub fn updateExports( if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports); - if (self.base.options.emit == null) return; - const tracy = trace(@src()); defer tracy.end(); @@ -3093,7 +3133,7 @@ fn populateMissingMetadata(self: *MachO) !void { if (self.header_segment_cmd_index == null) { // The first __TEXT segment is immovable and covers MachO header and load commands. self.header_segment_cmd_index = @as(u8, @intCast(self.segments.items.len)); - const ideal_size = @max(self.base.options.headerpad_size orelse 0, default_headerpad_size); + const ideal_size = self.headerpad_size; const needed_size = mem.alignForward(u64, padToIdeal(ideal_size), getPageSize(cpu_arch)); log.debug("found __TEXT segment (header-only) free space 0x{x} to 0x{x}", .{ 0, needed_size }); @@ -3222,13 +3262,13 @@ fn populateMissingMetadata(self: *MachO) !void { } fn calcPagezeroSize(self: *MachO) u64 { - const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize; + const output_mode = self.base.comp.config.output_mode; const page_size = getPageSize(self.base.options.target.cpu.arch); - const aligned_pagezero_vmsize = mem.alignBackward(u64, pagezero_vmsize, page_size); - if (self.base.options.output_mode == .Lib) return 0; + const aligned_pagezero_vmsize = mem.alignBackward(u64, self.pagezero_vmsize, page_size); + if (output_mode == .Lib) return 0; if (aligned_pagezero_vmsize == 0) return 0; - if (aligned_pagezero_vmsize != pagezero_vmsize) { - log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize}); + if (aligned_pagezero_vmsize != self.pagezero_vmsize) { + log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{self.pagezero_vmsize}); log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize}); } return aligned_pagezero_vmsize; @@ -4685,6 +4725,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void { } pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature) !void { + const output_mode = self.base.comp.config.output_mode; const seg_id = self.header_segment_cmd_index.?; const seg = self.segments.items[seg_id]; const offset = self.codesig_cmd.dataoff; @@ -4698,7 +4739,7 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod .exec_seg_base = seg.fileoff, .exec_seg_limit = seg.filesize, .file_size = offset, - .output_mode = self.base.options.output_mode, + .output_mode = output_mode, }, buffer.writer()); assert(buffer.items.len == code_sig.size()); @@ -4712,6 +4753,8 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod /// Writes Mach-O file header. pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void { + const output_mode = self.base.comp.config.output_mode; + var header: macho.mach_header_64 = .{}; header.flags = macho.MH_NOUNDEFS | macho.MH_DYLDLINK | macho.MH_PIE | macho.MH_TWOLEVEL; @@ -4727,7 +4770,7 @@ pub fn writeHeader(self: *MachO, ncmds: u32, sizeofcmds: u32) !void { else => unreachable, } - switch (self.base.options.output_mode) { + switch (output_mode) { .Exe => { header.filetype = macho.MH_EXECUTE; }, diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index e627b91f11..41c387c244 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -6,20 +6,21 @@ pub fn linkWithZld( const tracy = trace(@src()); defer tracy.end(); - const gpa = macho_file.base.allocator; - const options = &macho_file.base.options; - const target = options.target; + const gpa = macho_file.base.comp.gpa; + const target = macho_file.base.comp.root_mod.resolved_target.result; + const emit = macho_file.base.emit; var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const directory = options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{options.emit.?.sub_path}); + const directory = emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{emit.?.sub_path}); + const opt_zcu = macho_file.base.comp.module; // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (options.module != null) blk: { + const module_obj_path: ?[]const u8 = if (opt_zcu != null) blk: { try macho_file.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { @@ -34,22 +35,24 @@ pub fn linkWithZld( sub_prog_node.context.refresh(); defer sub_prog_node.end(); + const output_mode = macho_file.base.comp.config.output_mode; + const link_mode = macho_file.base.comp.config.link_mode; const cpu_arch = target.cpu.arch; - const is_lib = options.output_mode == .Lib; - const is_dyn_lib = options.link_mode == .Dynamic and is_lib; - const is_exe_or_dyn_lib = is_dyn_lib or options.output_mode == .Exe; - const stack_size = options.stack_size_override orelse 0; - const is_debug_build = options.optimize_mode == .Debug; - const gc_sections = options.gc_sections orelse !is_debug_build; + const is_lib = output_mode == .Lib; + const is_dyn_lib = link_mode == .Dynamic and is_lib; + const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; + const stack_size = macho_file.base.stack_size; const id_symlink_basename = "zld.id"; var man: Cache.Manifest = undefined; - defer if (!options.disable_lld_caching) man.deinit(); + defer if (!macho_file.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; - if (!options.disable_lld_caching) { + const objects = macho_file.base.comp.objects; + + if (!macho_file.base.disable_lld_caching) { man = comp.cache_parent.obtain(); // We are about to obtain this lock, so here we give other processes a chance first. @@ -57,7 +60,7 @@ pub fn linkWithZld( comptime assert(Compilation.link_hash_implementation_version == 10); - for (options.objects) |obj| { + for (objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); } @@ -68,24 +71,22 @@ pub fn linkWithZld( // We can skip hashing libc and libc++ components that we are in charge of building from Zig // installation sources because they are always a product of the compiler version + target information. man.hash.add(stack_size); - man.hash.addOptional(options.pagezero_size); - man.hash.addOptional(options.headerpad_size); - man.hash.add(options.headerpad_max_install_names); - man.hash.add(gc_sections); - man.hash.add(options.dead_strip_dylibs); - man.hash.add(options.strip); - man.hash.addListOfBytes(options.lib_dirs); - man.hash.addListOfBytes(options.framework_dirs); - try link.hashAddFrameworks(&man, options.frameworks); - man.hash.addListOfBytes(options.rpath_list); + man.hash.addOptional(macho_file.pagezero_vmsize); + man.hash.addOptional(macho_file.headerpad_size); + man.hash.add(macho_file.headerpad_max_install_names); + man.hash.add(macho_file.base.gc_sections); + man.hash.add(macho_file.dead_strip_dylibs); + man.hash.add(macho_file.base.comp.root_mod.strip); + try MachO.hashAddFrameworks(&man, macho_file.frameworks); + man.hash.addListOfBytes(macho_file.rpath_list); if (is_dyn_lib) { - man.hash.addOptionalBytes(options.install_name); - man.hash.addOptional(options.version); + man.hash.addOptionalBytes(macho_file.install_name); + man.hash.addOptional(comp.version); } - try link.hashAddSystemLibs(&man, options.system_libs); - man.hash.addOptionalBytes(options.sysroot); - man.hash.addListOfBytes(options.force_undefined_symbols.keys()); - try man.addOptionalFile(options.entitlements); + try link.hashAddSystemLibs(&man, comp.system_libs); + man.hash.addOptionalBytes(comp.sysroot); + man.hash.addListOfBytes(macho_file.base.force_undefined_symbols.keys()); + try man.addOptionalFile(macho_file.entitlements); // We don't actually care whether it's a cache hit or miss; we just // need the digest and the lock. @@ -125,13 +126,13 @@ pub fn linkWithZld( }; } - if (options.output_mode == .Obj) { + if (output_mode == .Obj) { // LLD's MachO driver does not support the equivalent of `-r` so we 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. const the_object_path = blk: { - if (options.objects.len != 0) { - break :blk options.objects[0].path; + if (objects.len != 0) { + break :blk objects[0].path; } if (comp.c_object_table.count() != 0) @@ -150,7 +151,7 @@ pub fn linkWithZld( try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); } } else { - const sub_path = options.emit.?.sub_path; + const sub_path = emit.?.sub_path; const old_file = macho_file.base.file; // TODO is this needed at all? defer macho_file.base.file = old_file; @@ -158,7 +159,7 @@ pub fn linkWithZld( const file = try directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, - .mode = link.determineMode(options.*), + .mode = link.File.determineMode(false, output_mode, link_mode), }); defer file.close(); macho_file.base.file = file; @@ -175,8 +176,8 @@ pub fn linkWithZld( // Positional arguments to the linker such as object files and static archives. var positionals = std.ArrayList(Compilation.LinkObject).init(arena); - try positionals.ensureUnusedCapacity(options.objects.len); - positionals.appendSliceAssumeCapacity(options.objects); + try positionals.ensureUnusedCapacity(objects.len); + positionals.appendSliceAssumeCapacity(objects); for (comp.c_object_table.keys()) |key| { try positionals.append(.{ .path = key.status.success.object_path }); @@ -190,7 +191,7 @@ pub fn linkWithZld( if (comp.compiler_rt_obj) |obj| try positionals.append(.{ .path = obj.full_object_path }); // libc++ dep - if (options.link_libcpp) { + if (comp.config.link_libcpp) { try positionals.ensureUnusedCapacity(2); positionals.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }); positionals.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path }); @@ -199,23 +200,23 @@ pub fn linkWithZld( var libs = std.StringArrayHashMap(link.SystemLib).init(arena); { - const vals = options.system_libs.values(); + const vals = comp.system_libs.values(); try libs.ensureUnusedCapacity(vals.len); for (vals) |v| libs.putAssumeCapacity(v.path.?, v); } { - try libs.ensureUnusedCapacity(options.frameworks.len); - for (options.frameworks) |v| libs.putAssumeCapacity(v.path, .{ + try libs.ensureUnusedCapacity(macho_file.frameworks.len); + for (macho_file.frameworks) |v| libs.putAssumeCapacity(v.path, .{ .needed = v.needed, .weak = v.weak, .path = v.path, }); } - try macho_file.resolveLibSystem(arena, comp, options.lib_dirs, &libs); + try macho_file.resolveLibSystem(arena, comp, &libs); - if (options.verbose_link) { + if (comp.verbose_link) { var argv = std.ArrayList([]const u8).init(arena); try argv.append("zig"); @@ -228,14 +229,14 @@ pub fn linkWithZld( if (is_dyn_lib) { try argv.append("-dylib"); - if (options.install_name) |install_name| { + if (macho_file.install_name) |install_name| { try argv.append("-install_name"); try argv.append(install_name); } } { - const platform = Platform.fromTarget(options.target); + const platform = Platform.fromTarget(target); try argv.append("-platform_version"); try argv.append(@tagName(platform.os_tag)); try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version})); @@ -248,44 +249,39 @@ pub fn linkWithZld( } } - if (options.sysroot) |syslibroot| { + if (macho_file.sysroot) |syslibroot| { try argv.append("-syslibroot"); try argv.append(syslibroot); } - for (options.rpath_list) |rpath| { + for (macho_file.rpath_list) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } - if (options.pagezero_size) |pagezero_size| { - try argv.append("-pagezero_size"); - try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size})); - } - - if (options.headerpad_size) |headerpad_size| { - try argv.append("-headerpad_size"); - try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{headerpad_size})); - } + try argv.appendSlice(&.{ + "-pagezero_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_size}), + "-headerpad_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.headerpad_size}), + }); - if (options.headerpad_max_install_names) { + if (macho_file.headerpad_max_install_names) { try argv.append("-headerpad_max_install_names"); } - if (gc_sections) { + if (macho_file.base.gc_sections) { try argv.append("-dead_strip"); } - if (options.dead_strip_dylibs) { + if (macho_file.dead_strip_dylibs) { try argv.append("-dead_strip_dylibs"); } - if (options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("-e"); try argv.append(entry); } - for (options.objects) |obj| { + for (objects) |obj| { if (obj.must_link) { try argv.append("-force_load"); } @@ -303,7 +299,7 @@ pub fn linkWithZld( if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path); if (comp.compiler_rt_obj) |obj| try argv.append(obj.full_object_path); - if (options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } @@ -313,8 +309,8 @@ pub fn linkWithZld( try argv.append("-lSystem"); - for (options.system_libs.keys()) |l_name| { - const info = options.system_libs.get(l_name).?; + for (comp.system_libs.keys()) |l_name| { + const info = comp.system_libs.get(l_name).?; const arg = if (info.needed) try std.fmt.allocPrint(arena, "-needed-l{s}", .{l_name}) else if (info.weak) @@ -324,11 +320,7 @@ pub fn linkWithZld( try argv.append(arg); } - for (options.lib_dirs) |lib_dir| { - try argv.append(try std.fmt.allocPrint(arena, "-L{s}", .{lib_dir})); - } - - for (options.frameworks) |framework| { + for (macho_file.frameworks) |framework| { const name = std.fs.path.stem(framework.path); const arg = if (framework.needed) try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name}) @@ -339,11 +331,7 @@ pub fn linkWithZld( try argv.append(arg); } - for (options.framework_dirs) |framework_dir| { - try argv.append(try std.fmt.allocPrint(arena, "-F{s}", .{framework_dir})); - } - - if (is_dyn_lib and (options.allow_shlib_undefined orelse false)) { + if (is_dyn_lib and macho_file.base.allow_shlib_undefined) { try argv.append("-undefined"); try argv.append("dynamic_lookup"); } @@ -412,7 +400,7 @@ pub fn linkWithZld( }; } - if (gc_sections) { + if (macho_file.base.gc_sections) { try dead_strip.gcAtoms(macho_file); } @@ -519,7 +507,7 @@ pub fn linkWithZld( // where the code signature goes into. var codesig = CodeSignature.init(MachO.getPageSize(cpu_arch)); codesig.code_directory.ident = fs.path.basename(full_out_path); - if (options.entitlements) |path| { + if (macho_file.entitlements) |path| { try codesig.addEntitlements(gpa, path); } try macho_file.writeCodeSignaturePadding(&codesig); @@ -539,7 +527,7 @@ pub fn linkWithZld( try lc_writer.writeStruct(macho_file.dysymtab_cmd); try load_commands.writeDylinkerLC(lc_writer); - switch (macho_file.base.options.output_mode) { + switch (output_mode) { .Exe => blk: { const seg_id = macho_file.header_segment_cmd_index.?; const seg = macho_file.segments.items[seg_id]; @@ -555,10 +543,10 @@ pub fn linkWithZld( try lc_writer.writeStruct(macho.entry_point_command{ .entryoff = @as(u32, @intCast(addr - seg.vmaddr)), - .stacksize = macho_file.base.options.stack_size_override orelse 0, + .stacksize = macho_file.base.stack_size, }); }, - .Lib => if (macho_file.base.options.link_mode == .Dynamic) { + .Lib => if (link_mode == .Dynamic) { try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer); }, else => {}, @@ -598,11 +586,11 @@ pub fn linkWithZld( if (codesig) |*csig| { try macho_file.writeCodeSignature(comp, csig); // code signing always comes last - try MachO.invalidateKernelCache(directory.handle, macho_file.base.options.emit.?.sub_path); + try MachO.invalidateKernelCache(directory.handle, macho_file.base.emit.sub_path); } } - if (!options.disable_lld_caching) { + if (!macho_file.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { @@ -622,12 +610,11 @@ pub fn linkWithZld( fn createSegments(macho_file: *MachO) !void { const gpa = macho_file.base.allocator; - const pagezero_vmsize = macho_file.base.options.pagezero_size orelse MachO.default_pagezero_vmsize; const page_size = MachO.getPageSize(macho_file.base.options.target.cpu.arch); - const aligned_pagezero_vmsize = mem.alignBackward(u64, pagezero_vmsize, page_size); + const aligned_pagezero_vmsize = mem.alignBackward(u64, macho_file.pagezero_vmsize, page_size); if (macho_file.base.options.output_mode != .Lib and aligned_pagezero_vmsize > 0) { - if (aligned_pagezero_vmsize != pagezero_vmsize) { - log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize}); + if (aligned_pagezero_vmsize != macho_file.pagezero_vmsize) { + log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{macho_file.pagezero_vmsize}); log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize}); } macho_file.pagezero_segment_cmd_index = @intCast(macho_file.segments.items.len); diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index 606c5f1237..1cfc14cef0 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -24,46 +24,56 @@ const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, llvm_object: *LlvmObject, -ptx_file_name: []const u8, -pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx { - if (!options.use_llvm) return error.PtxArchNotSupported; +pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { + if (build_options.only_c) unreachable; - if (!options.target.cpu.arch.isNvptx()) return error.PtxArchNotSupported; + const target = options.comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and options.comp.config.use_lld; + const use_llvm = options.comp.config.use_llvm; - switch (options.target.os.tag) { + assert(use_llvm); // Caught by Compilation.Config.resolve. + assert(!use_lld); // Caught by Compilation.Config.resolve. + assert(target.cpu.arch.isNvptx()); // Caught by Compilation.Config.resolve. + + switch (target.os.tag) { // TODO: does it also work with nvcl ? .cuda => {}, else => return error.PtxArchNotSupported, } - const llvm_object = try LlvmObject.create(gpa, options); - const nvptx = try gpa.create(NvPtx); + const llvm_object = try LlvmObject.create(arena, options); + const nvptx = try arena.create(NvPtx); nvptx.* = .{ .base = .{ .tag = .nvptx, - .options = options, + .comp = options.comp, + .emit = options.emit, + .gc_sections = options.gc_sections orelse false, + .stack_size = options.stack_size orelse 0, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, - .allocator = gpa, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .llvm_object = llvm_object, - .ptx_file_name = try std.mem.join(gpa, "", &[_][]const u8{ options.root_name, ".ptx" }), }; return nvptx; } -pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx { - if (!options.use_llvm) return error.PtxArchNotSupported; - assert(options.target.ofmt == .nvptx); - - log.debug("Opening .ptx target file {s}", .{sub_path}); - return createEmpty(allocator, options); +pub fn open(arena: Allocator, options: link.FileOpenOptions) !*NvPtx { + const target = options.comp.root_mod.resolved_target.result; + assert(target.ofmt == .nvptx); + return createEmpty(arena, options); } pub fn deinit(self: *NvPtx) void { - self.llvm_object.destroy(self.base.allocator); - self.base.allocator.free(self.ptx_file_name); + self.llvm_object.deinit(); } pub fn updateFunc(self: *NvPtx, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { @@ -110,7 +120,7 @@ pub fn flushModule(self: *NvPtx, comp: *Compilation, prog_node: *std.Progress.No comp.emit_asm = .{ // 'null' means using the default cache dir: zig-cache/o/... .directory = null, - .basename = self.ptx_file_name, + .basename = self.base.emit.sub_path, }; defer { comp.bin_file.options.emit = outfile; diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index b608b29161..a5bb943ada 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -318,12 +318,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Plan9 { .magic = try aout.magicFromArch(self.base.options.target.cpu.arch), }; // a / will always be in a file path - try self.file_segments.put(self.base.allocator, "/", 1); + try self.file_segments.put(gpa, "/", 1); return self; } fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope(mod)); @@ -379,6 +379,7 @@ fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !voi } fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !void { + const gpa = self.base.comp.gpa; const sep = std.fs.path.sep; var it = std.mem.tokenizeScalar(u8, path, sep); while (it.next()) |component| { @@ -386,7 +387,7 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi try a.writer().writeInt(u16, num, .big); } else { self.file_segments_i += 1; - try self.file_segments.put(self.base.allocator, component, self.file_segments_i); + try self.file_segments.put(gpa, component, self.file_segments_i); try a.writer().writeInt(u16, self.file_segments_i, .big); } } @@ -397,6 +398,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: @panic("Attempted to compile for object format that was disabled by build configuration"); } + const gpa = self.base.comp.gpa; const func = mod.funcInfo(func_index); const decl_index = func.owner_decl; const decl = mod.declPtr(decl_index); @@ -404,10 +406,10 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: const atom_idx = try self.seeDecl(decl_index); - var code_buffer = std.ArrayList(u8).init(self.base.allocator); + var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); var dbg_info_output: DebugInfoOutput = .{ - .dbg_line = std.ArrayList(u8).init(self.base.allocator), + .dbg_line = std.ArrayList(u8).init(gpa), .start_line = null, .end_line = undefined, .pcop_change_index = null, @@ -448,14 +450,15 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air: } pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { + const gpa = self.base.comp.gpa; _ = try self.seeDecl(decl_index); - var code_buffer = std.ArrayList(u8).init(self.base.allocator); + var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); - const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index); + const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } @@ -465,7 +468,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De const index = unnamed_consts.items.len; // name is freed when the unnamed const is freed - const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index }); + const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); const sym_index = try self.allocateSymbolIndex(); const new_atom_idx = try self.createAtom(); @@ -498,17 +501,18 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De }, }; // duped_code is freed when the unnamed const is freed - const duped_code = try self.base.allocator.dupe(u8, code); - errdefer self.base.allocator.free(duped_code); + const duped_code = try gpa.dupe(u8, code); + errdefer gpa.free(duped_code); const new_atom = self.getAtomPtr(new_atom_idx); new_atom.* = info; new_atom.code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len } }; - try unnamed_consts.append(self.base.allocator, new_atom_idx); + try unnamed_consts.append(gpa, new_atom_idx); // we return the new_atom_idx to codegen return new_atom_idx; } pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) !void { + const gpa = self.base.comp.gpa; const decl = mod.declPtr(decl_index); if (decl.isExtern(mod)) { @@ -517,7 +521,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) } const atom_idx = try self.seeDecl(decl_index); - var code_buffer = std.ArrayList(u8).init(self.base.allocator); + var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; // TODO we need the symbol index for symbol in the table of locals for the containing atom @@ -535,16 +539,17 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex) return; }, }; - try self.data_decl_table.ensureUnusedCapacity(self.base.allocator, 1); - const duped_code = try self.base.allocator.dupe(u8, code); + try self.data_decl_table.ensureUnusedCapacity(gpa, 1); + const duped_code = try gpa.dupe(u8, code); self.getAtomPtr(self.decls.get(decl_index).?.index).code = .{ .code_ptr = null, .other = .{ .decl_index = decl_index } }; if (self.data_decl_table.fetchPutAssumeCapacity(decl_index, duped_code)) |old_entry| { - self.base.allocator.free(old_entry.value); + gpa.free(old_entry.value); } return self.updateFinish(decl_index); } /// called at the end of update{Decl,Func} fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void { + const gpa = self.base.comp.gpa; const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); const is_fn = (decl.ty.zigTypeTag(mod) == .Fn); @@ -558,7 +563,7 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void { const sym: aout.Sym = .{ .value = undefined, // the value of stuff gets filled in in flushModule .type = atom.type, - .name = try self.base.allocator.dupe(u8, mod.intern_pool.stringToSlice(decl.name)), + .name = try gpa.dupe(u8, mod.intern_pool.stringToSlice(decl.name)), }; if (atom.sym_index) |s| { @@ -571,10 +576,11 @@ fn updateFinish(self: *Plan9, decl_index: InternPool.DeclIndex) !void { } fn allocateSymbolIndex(self: *Plan9) !usize { + const gpa = self.base.comp.gpa; if (self.syms_index_free_list.popOrNull()) |i| { return i; } else { - _ = try self.syms.addOne(self.base.allocator); + _ = try self.syms.addOne(gpa); return self.syms.items.len - 1; } } @@ -589,7 +595,8 @@ fn allocateGotIndex(self: *Plan9) usize { } pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { - assert(!self.base.options.use_lld); + const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; + assert(!use_lld); switch (self.base.options.effectiveOutputMode()) { .Exe => {}, @@ -650,7 +657,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No @panic("Attempted to compile for object format that was disabled by build configuration"); } - _ = comp; + const gpa = comp.gpa; + const tracy = trace(@src()); defer tracy.end(); @@ -691,12 +699,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No const atom_count = self.atomCount(); assert(self.got_len == atom_count + self.got_index_free_list.items.len); const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; - var got_table = try self.base.allocator.alloc(u8, got_size); - defer self.base.allocator.free(got_table); + var got_table = try gpa.alloc(u8, got_size); + defer gpa.free(got_table); // + 4 for header, got, symbols, linecountinfo - var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount()); - defer self.base.allocator.free(iovecs); + var iovecs = try gpa.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount()); + defer gpa.free(iovecs); const file = self.base.file.?; @@ -709,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No var iovecs_i: usize = 1; var text_i: u64 = 0; - var linecountinfo = std.ArrayList(u8).init(self.base.allocator); + var linecountinfo = std.ArrayList(u8).init(gpa); defer linecountinfo.deinit(); // text { @@ -901,10 +909,10 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No } } } - var sym_buf = std.ArrayList(u8).init(self.base.allocator); + var sym_buf = std.ArrayList(u8).init(gpa); try self.writeSyms(&sym_buf); const syms = try sym_buf.toOwnedSlice(); - defer self.base.allocator.free(syms); + defer gpa.free(syms); assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; iovecs_i += 1; @@ -985,6 +993,7 @@ fn addDeclExports( decl_index: InternPool.DeclIndex, exports: []const *Module.Export, ) !void { + const gpa = self.base.comp.gpa; const metadata = self.decls.getPtr(decl_index).?; const atom = self.getAtom(metadata.index); @@ -994,7 +1003,7 @@ fn addDeclExports( if (exp.opts.section.unwrap()) |section_name| { if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) { try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( - self.base.allocator, + gpa, mod.declPtr(decl_index).srcLoc(mod), "plan9 does not support extra sections", .{}, @@ -1005,19 +1014,20 @@ fn addDeclExports( const sym = .{ .value = atom.offset.?, .type = atom.type.toGlobal(), - .name = try self.base.allocator.dupe(u8, exp_name), + .name = try gpa.dupe(u8, exp_name), }; if (metadata.getExport(self, exp_name)) |i| { self.syms.items[i] = sym; } else { - try self.syms.append(self.base.allocator, sym); - try metadata.exports.append(self.base.allocator, self.syms.items.len - 1); + try self.syms.append(gpa, sym); + try metadata.exports.append(gpa, self.syms.items.len - 1); } } } pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void { + const gpa = self.base.comp.gpa; // TODO audit the lifetimes of decls table entries. It's possible to get // freeDecl without any updateDecl in between. // However that is planned to change, see the TODO comment in Module.zig @@ -1029,17 +1039,17 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void { const symidx_and_submap = self.fn_decl_table.get(decl.getFileScope(mod)).?; var submap = symidx_and_submap.functions; if (submap.fetchSwapRemove(decl_index)) |removed_entry| { - self.base.allocator.free(removed_entry.value.code); - self.base.allocator.free(removed_entry.value.lineinfo); + gpa.free(removed_entry.value.code); + gpa.free(removed_entry.value.lineinfo); } if (submap.count() == 0) { self.syms.items[symidx_and_submap.sym_index] = aout.Sym.undefined_symbol; - self.syms_index_free_list.append(self.base.allocator, symidx_and_submap.sym_index) catch {}; - submap.deinit(self.base.allocator); + self.syms_index_free_list.append(gpa, symidx_and_submap.sym_index) catch {}; + submap.deinit(gpa); } } else { if (self.data_decl_table.fetchSwapRemove(decl_index)) |removed_entry| { - self.base.allocator.free(removed_entry.value); + gpa.free(removed_entry.value); } } if (self.decls.fetchRemove(decl_index)) |const_kv| { @@ -1047,35 +1057,36 @@ pub fn freeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) void { const atom = self.getAtom(kv.value.index); if (atom.got_index) |i| { // TODO: if this catch {} is triggered, an assertion in flushModule will be triggered, because got_index_free_list will have the wrong length - self.got_index_free_list.append(self.base.allocator, i) catch {}; + self.got_index_free_list.append(gpa, i) catch {}; } if (atom.sym_index) |i| { - self.syms_index_free_list.append(self.base.allocator, i) catch {}; + self.syms_index_free_list.append(gpa, i) catch {}; self.syms.items[i] = aout.Sym.undefined_symbol; } - kv.value.exports.deinit(self.base.allocator); + kv.value.exports.deinit(gpa); } self.freeUnnamedConsts(decl_index); { const atom_index = self.decls.get(decl_index).?.index; const relocs = self.relocs.getPtr(atom_index) orelse return; - relocs.clearAndFree(self.base.allocator); + relocs.clearAndFree(gpa); assert(self.relocs.remove(atom_index)); } } fn freeUnnamedConsts(self: *Plan9, decl_index: InternPool.DeclIndex) void { + const gpa = self.base.comp.gpa; const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return; for (unnamed_consts.items) |atom_idx| { const atom = self.getAtom(atom_idx); - self.base.allocator.free(self.syms.items[atom.sym_index.?].name); + gpa.free(self.syms.items[atom.sym_index.?].name); self.syms.items[atom.sym_index.?] = aout.Sym.undefined_symbol; - self.syms_index_free_list.append(self.base.allocator, atom.sym_index.?) catch {}; + self.syms_index_free_list.append(gpa, atom.sym_index.?) catch {}; } - unnamed_consts.clearAndFree(self.base.allocator); + unnamed_consts.clearAndFree(gpa); } fn createAtom(self: *Plan9) !Atom.Index { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const index = @as(Atom.Index, @intCast(self.atoms.items.len)); const atom = try self.atoms.addOne(gpa); atom.* = .{ @@ -1089,7 +1100,8 @@ fn createAtom(self: *Plan9) !Atom.Index { } pub fn seeDecl(self: *Plan9, decl_index: InternPool.DeclIndex) !Atom.Index { - const gop = try self.decls.getOrPut(self.base.allocator, decl_index); + const gpa = self.base.comp.gpa; + const gop = try self.decls.getOrPut(gpa, decl_index); if (!gop.found_existing) { const index = try self.createAtom(); self.getAtomPtr(index).got_index = self.allocateGotIndex(); @@ -1134,7 +1146,8 @@ pub fn updateExports( } pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index { - const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(self.base.options.module.?)); + const gpa = self.base.comp.gpa; + const gop = try self.lazy_syms.getOrPut(gpa, sym.getDecl(self.base.options.module.?)); errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); if (!gop.found_existing) gop.value_ptr.* = .{}; @@ -1160,7 +1173,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.In } fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Index) !void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const mod = self.base.options.module.?; var required_alignment: InternPool.Alignment = .none; @@ -1206,8 +1219,8 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind }, }; // duped_code is freed when the atom is freed - const duped_code = try self.base.allocator.dupe(u8, code); - errdefer self.base.allocator.free(duped_code); + const duped_code = try gpa.dupe(u8, code); + errdefer gpa.free(duped_code); self.getAtomPtr(atom_index).code = .{ .code_ptr = duped_code.ptr, .other = .{ .code_len = duped_code.len }, @@ -1215,13 +1228,13 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind } pub fn deinit(self: *Plan9) void { - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; { var it = self.relocs.valueIterator(); while (it.next()) |relocs| { - relocs.deinit(self.base.allocator); + relocs.deinit(gpa); } - self.relocs.deinit(self.base.allocator); + self.relocs.deinit(gpa); } // free the unnamed consts var it_unc = self.unnamed_const_atoms.iterator(); @@ -1280,24 +1293,36 @@ pub fn deinit(self: *Plan9) void { } } -pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 { - if (options.use_llvm) - return error.LLVMBackendDoesNotSupportPlan9; - assert(options.target.ofmt == .plan9); +pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { + if (build_options.only_c) unreachable; + + const target = options.comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and options.comp.config.use_lld; + const use_llvm = options.comp.config.use_llvm; - const self = try createEmpty(allocator, options); + assert(!use_llvm); // Caught by Compilation.Config.resolve. + assert(!use_lld); // Caught by Compilation.Config.resolve. + assert(target.ofmt == .plan9); + + const self = try createEmpty(arena, options); errdefer self.base.destroy(); - const file = try options.emit.?.directory.handle.createFile(sub_path, .{ + const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ .read = true, - .mode = link.determineMode(options), + .mode = link.File.determineMode( + use_lld, + options.comp.config.output_mode, + options.comp.config.link_mode, + ), }); errdefer file.close(); self.base.file = file; - self.bases = defaultBaseAddrs(options.target.cpu.arch); + self.bases = defaultBaseAddrs(target.cpu.arch); + + const gpa = options.comp.gpa; - try self.syms.appendSlice(self.base.allocator, &.{ + try self.syms.appendSlice(gpa, &.{ // we include the global offset table to make it easier for debugging .{ .value = self.getAddr(0, .d), // the global offset table starts at 0 @@ -1490,7 +1515,7 @@ pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.S // be used by more than one function, however, its address is being used so we need // to put it in some location. // ... - const gpa = self.base.allocator; + const gpa = self.base.comp.gpa; const gop = try self.anon_decls.getOrPut(gpa, decl_val); const mod = self.base.options.module.?; if (!gop.found_existing) { @@ -1538,11 +1563,12 @@ pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: li } pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void { - const gop = try self.relocs.getOrPut(self.base.allocator, parent_index); + const gpa = self.base.comp.gpa; + const gop = try self.relocs.getOrPut(gpa, parent_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } - try gop.value_ptr.append(self.base.allocator, reloc); + try gop.value_ptr.append(gpa, reloc); } pub fn getAtom(self: *const Plan9, index: Atom.Index) Atom { diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index ac36a391ec..c6bb5f5588 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -47,48 +47,65 @@ base: link.File, object: codegen.Object, -pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV { - const self = try gpa.create(SpirV); +pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { + const gpa = options.comp.gpa; + const target = options.comp.root_mod.resolved_target.result; + + const self = try arena.create(SpirV); self.* = .{ .base = .{ .tag = .spirv, - .options = options, + .comp = options.comp, + .emit = options.emit, + .gc_sections = options.gc_sections orelse false, + .stack_size = options.stack_size orelse 0, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, - .allocator = gpa, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .object = codegen.Object.init(gpa), }; errdefer self.deinit(); - // TODO: Figure out where to put all of these - switch (options.target.cpu.arch) { + switch (target.cpu.arch) { .spirv32, .spirv64 => {}, - else => return error.TODOArchNotSupported, + else => unreachable, // Caught by Compilation.Config.resolve. } - switch (options.target.os.tag) { + switch (target.os.tag) { .opencl, .glsl450, .vulkan => {}, - else => return error.TODOOsNotSupported, + else => unreachable, // Caught by Compilation.Config.resolve. } - if (options.target.abi != .none) { - return error.TODOAbiNotSupported; - } + assert(target.abi != .none); // Caught by Compilation.Config.resolve. return self; } -pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV { - assert(options.target.ofmt == .spirv); +pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV { + if (build_options.only_c) unreachable; + + const target = options.comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and options.comp.config.use_lld; + const use_llvm = options.comp.config.use_llvm; - if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all. - if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all. + assert(!use_llvm); // Caught by Compilation.Config.resolve. + assert(!use_lld); // Caught by Compilation.Config.resolve. + assert(target.ofmt == .spirv); // Caught by Compilation.Config.resolve. - const spirv = try createEmpty(allocator, options); + const spirv = try createEmpty(arena, options); errdefer spirv.base.destroy(); // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true }); + const file = try options.emit.?.directory.handle.createFile(options.emit.sub_path, .{ + .truncate = true, + .read = true, + }); spirv.base.file = file; return spirv; } @@ -150,11 +167,7 @@ pub fn freeDecl(self: *SpirV, decl_index: InternPool.DeclIndex) void { } pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { - if (build_options.have_llvm and self.base.options.use_lld) { - return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all. - } else { - return self.flushModule(comp, prog_node); - } + return self.flushModule(comp, prog_node); } pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 513922f247..bb0d4447bb 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -191,6 +191,9 @@ synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, +import_table: bool, +export_table: bool, + pub const Alignment = types.Alignment; pub const Segment = struct { @@ -363,63 +366,71 @@ pub const StringTable = struct { } }; -pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm { - assert(options.target.ofmt == .wasm); +pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { + if (build_options.only_c) unreachable; + const gpa = options.comp.gpa; + const target = options.comp.root_mod.resolved_target.result; + assert(target.ofmt == .wasm); - if (options.use_llvm and options.use_lld) { - return createEmpty(allocator, options); - } + const use_lld = build_options.have_llvm and options.comp.config.use_lld; + const use_llvm = options.comp.config.use_llvm; + const output_mode = options.comp.config.output_mode; - const wasm_bin = try createEmpty(allocator, options); - errdefer wasm_bin.base.destroy(); + const wasm = try createEmpty(arena, options); + errdefer wasm.base.destroy(); - // We are not using LLD at this point, so ensure we set the intermediary basename - if (build_options.have_llvm and options.use_llvm and options.module != null) { - // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`, - // we also want to put the intermediary object file in the cache while the - // main emit directory is the cwd. - wasm_bin.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{ - options.emit.?.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch), - }); + if (use_lld and use_llvm) { + // LLVM emits the object file; LLD links it into the final product. + return wasm; } + const sub_path = if (!use_lld) options.emit.sub_path else p: { + // Open a temporary object file, not the final output file because we + // want to link with LLD. + const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ + options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + }); + wasm.base.intermediary_basename = o_file_path; + break :p o_file_path; + }; + // TODO: read the file and keep valid parts instead of truncating const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = if (fs.has_executable_bit) - if (options.target.os.tag == .wasi and options.output_mode == .Exe) + if (target.os.tag == .wasi and output_mode == .Exe) fs.File.default_mode | 0b001_000_000 else fs.File.default_mode else 0, }); - wasm_bin.base.file = file; - wasm_bin.name = sub_path; + wasm.base.file = file; + wasm.name = sub_path; // create stack pointer symbol { - const loc = try wasm_bin.createSyntheticSymbol("__stack_pointer", .global); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global); + const symbol = loc.getSymbol(wasm); // For object files we will import the stack pointer symbol - if (options.output_mode == .Obj) { + if (output_mode == .Obj) { symbol.setUndefined(true); - symbol.index = @as(u32, @intCast(wasm_bin.imported_globals_count)); - wasm_bin.imported_globals_count += 1; - try wasm_bin.imports.putNoClobber( - allocator, + symbol.index = @intCast(wasm.imported_globals_count); + wasm.imported_globals_count += 1; + try wasm.imports.putNoClobber( + gpa, loc, .{ - .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), + .module_name = try wasm.string_table.put(gpa, wasm.host_name), .name = symbol.name, .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, }, ); } else { - symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); + symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - const global = try wasm_bin.wasm_globals.addOne(allocator); + const global = try wasm.wasm_globals.addOne(gpa); global.* = .{ .global_type = .{ .valtype = .i32, @@ -432,25 +443,25 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option // create indirect function pointer symbol { - const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table); + const symbol = loc.getSymbol(wasm); const table: std.wasm.Table = .{ .limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable` .reftype = .funcref, }; - if (options.output_mode == .Obj or options.import_table) { + if (output_mode == .Obj or options.import_table) { symbol.setUndefined(true); - symbol.index = @intCast(wasm_bin.imported_tables_count); - wasm_bin.imported_tables_count += 1; - try wasm_bin.imports.put(allocator, loc, .{ - .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), + symbol.index = @intCast(wasm.imported_tables_count); + wasm.imported_tables_count += 1; + try wasm.imports.put(gpa, loc, .{ + .module_name = try wasm.string_table.put(gpa, wasm.host_name), .name = symbol.name, .kind = .{ .table = table }, }); } else { - symbol.index = @as(u32, @intCast(wasm_bin.imported_tables_count + wasm_bin.tables.items.len)); - try wasm_bin.tables.append(allocator, table); - if (options.export_table) { + symbol.index = @as(u32, @intCast(wasm.imported_tables_count + wasm.tables.items.len)); + try wasm.tables.append(gpa, table); + if (wasm.export_table) { symbol.setFlag(.WASM_SYM_EXPORTED); } else { symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); @@ -460,8 +471,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option // create __wasm_call_ctors { - const loc = try wasm_bin.createSyntheticSymbol("__wasm_call_ctors", .function); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function); + const symbol = loc.getSymbol(wasm); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); // we do not know the function index until after we merged all sections. // Therefore we set `symbol.index` and create its corresponding references @@ -469,67 +480,76 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option } // shared-memory symbols for TLS support - if (wasm_bin.base.options.shared_memory) { + if (wasm.base.options.shared_memory) { { - const loc = try wasm_bin.createSyntheticSymbol("__tls_base", .global); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__tls_base", .global); + const symbol = loc.getSymbol(wasm); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); - try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{ + symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); + try wasm.wasm_globals.append(gpa, .{ .global_type = .{ .valtype = .i32, .mutable = true }, .init = .{ .i32_const = undefined }, }); } { - const loc = try wasm_bin.createSyntheticSymbol("__tls_size", .global); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__tls_size", .global); + const symbol = loc.getSymbol(wasm); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); - try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{ + symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); + try wasm.wasm_globals.append(gpa, .{ .global_type = .{ .valtype = .i32, .mutable = false }, .init = .{ .i32_const = undefined }, }); } { - const loc = try wasm_bin.createSyntheticSymbol("__tls_align", .global); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__tls_align", .global); + const symbol = loc.getSymbol(wasm); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); - symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); - try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{ + symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); + try wasm.wasm_globals.append(gpa, .{ .global_type = .{ .valtype = .i32, .mutable = false }, .init = .{ .i32_const = undefined }, }); } { - const loc = try wasm_bin.createSyntheticSymbol("__wasm_init_tls", .function); - const symbol = loc.getSymbol(wasm_bin); + const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function); + const symbol = loc.getSymbol(wasm); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); } } - // if (!options.strip and options.module != null) { - // wasm_bin.dwarf = Dwarf.init(allocator, &wasm_bin.base, .dwarf32); - // try wasm_bin.initDebugSections(); - // } - - return wasm_bin; + return wasm; } -pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { - const wasm = try gpa.create(Wasm); - errdefer gpa.destroy(wasm); +pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { + const use_llvm = options.comp.config.use_llvm; + const output_mode = options.comp.config.output_mode; + + const wasm = try arena.create(Wasm); wasm.* = .{ .base = .{ .tag = .wasm, - .options = options, + .comp = options.comp, + .emit = options.emit, + .gc_sections = options.gc_sections orelse (output_mode != .Obj), + .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, - .allocator = gpa, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .name = undefined, + .import_table = options.import_table, + .export_table = options.export_table, }; - if (options.use_llvm) { - wasm.llvm_object = try LlvmObject.create(gpa, options); + if (use_llvm) { + wasm.llvm_object = try LlvmObject.create(arena, options); } return wasm; } @@ -537,22 +557,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { /// For a given name, creates a new global synthetic symbol. /// Leaves index undefined and the default flags (0). fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { - const name_offset = try wasm.string_table.put(wasm.base.allocator, name); + const gpa = wasm.base.comp.gpa; + const name_offset = try wasm.string_table.put(gpa, name); return wasm.createSyntheticSymbolOffset(name_offset, tag); } fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { const sym_index = @as(u32, @intCast(wasm.symbols.items.len)); const loc: SymbolLoc = .{ .index = sym_index, .file = null }; - try wasm.symbols.append(wasm.base.allocator, .{ + const gpa = wasm.base.comp.gpa; + try wasm.symbols.append(gpa, .{ .name = name_offset, .flags = 0, .tag = tag, .index = undefined, .virtual_address = undefined, }); - try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {}); - try wasm.globals.put(wasm.base.allocator, name_offset, loc); + try wasm.resolved_symbols.putNoClobber(gpa, loc, {}); + try wasm.globals.put(gpa, name_offset, loc); return loc; } @@ -589,12 +611,13 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { const file = try fs.cwd().openFile(path, .{}); errdefer file.close(); - var object = Object.create(wasm.base.allocator, file, path, null) catch |err| switch (err) { + const gpa = wasm.base.comp.gpa; + var object = Object.create(gpa, file, path, null) catch |err| switch (err) { error.InvalidMagicByte, error.NotObjectFile => return false, else => |e| return e, }; - errdefer object.deinit(wasm.base.allocator); - try wasm.objects.append(wasm.base.allocator, object); + errdefer object.deinit(gpa); + try wasm.objects.append(gpa, object); return true; } @@ -602,7 +625,8 @@ fn parseObjectFile(wasm: *Wasm, path: []const u8) !bool { /// When the index was not found, a new `Atom` will be created, and its index will be returned. /// The newly created Atom is empty with default fields as specified by `Atom.empty`. pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !Atom.Index { - const gop = try wasm.decls.getOrPut(wasm.base.allocator, decl_index); + const gpa = wasm.base.comp.gpa; + const gop = try wasm.decls.getOrPut(gpa, decl_index); if (!gop.found_existing) { const atom_index = try wasm.createAtom(); gop.value_ptr.* = atom_index; @@ -611,18 +635,19 @@ pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !At const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); - symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name); + symbol.name = try wasm.string_table.put(gpa, full_name); } return gop.value_ptr.*; } /// Creates a new empty `Atom` and returns its `Atom.Index` fn createAtom(wasm: *Wasm) !Atom.Index { - const index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); - const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); + const gpa = wasm.base.comp.gpa; + const index: Atom.Index = @intCast(wasm.managed_atoms.items.len); + const atom = try wasm.managed_atoms.addOne(gpa); atom.* = Atom.empty; atom.sym_index = try wasm.allocateSymbol(); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, .{ .file = null, .index = atom.sym_index }, index); + try wasm.symbol_atom.putNoClobber(gpa, .{ .file = null, .index = atom.sym_index }, index); return index; } @@ -644,6 +669,8 @@ pub inline fn getAtomPtr(wasm: *Wasm, index: Atom.Index) *Atom { /// When false, it will only link with object files that contain symbols that /// are referenced by other object files or Zig code. fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { + const gpa = wasm.base.comp.gpa; + const file = try fs.cwd().openFile(path, .{}); errdefer file.close(); @@ -651,25 +678,25 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { .file = file, .name = path, }; - archive.parse(wasm.base.allocator) catch |err| switch (err) { + archive.parse(gpa) catch |err| switch (err) { error.EndOfStream, error.NotArchive => { - archive.deinit(wasm.base.allocator); + archive.deinit(gpa); return false; }, else => |e| return e, }; if (!force_load) { - errdefer archive.deinit(wasm.base.allocator); - try wasm.archives.append(wasm.base.allocator, archive); + errdefer archive.deinit(gpa); + try wasm.archives.append(gpa, archive); return true; } - defer archive.deinit(wasm.base.allocator); + defer archive.deinit(gpa); // In this case we must force link all embedded object files within the archive // We loop over all symbols, and then group them by offset as the offset // notates where the object file starts. - var offsets = std.AutoArrayHashMap(u32, void).init(wasm.base.allocator); + var offsets = std.AutoArrayHashMap(u32, void).init(gpa); defer offsets.deinit(); for (archive.toc.values()) |symbol_offsets| { for (symbol_offsets.items) |sym_offset| { @@ -678,8 +705,8 @@ fn parseArchive(wasm: *Wasm, path: []const u8, force_load: bool) !bool { } for (offsets.keys()) |file_offset| { - const object = try wasm.objects.addOne(wasm.base.allocator); - object.* = try archive.parseObject(wasm.base.allocator, file_offset); + const object = try wasm.objects.addOne(gpa); + object.* = try archive.parseObject(gpa, file_offset); } return true; @@ -695,6 +722,7 @@ fn requiresTLSReloc(wasm: *const Wasm) bool { } fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { + const gpa = wasm.base.comp.gpa; const object: Object = wasm.objects.items[object_index]; log.debug("Resolving symbols in object: '{s}'", .{object.name}); @@ -708,7 +736,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { if (mem.eql(u8, sym_name, "__indirect_function_table")) { continue; } - const sym_name_index = try wasm.string_table.put(wasm.base.allocator, sym_name); + const sym_name_index = try wasm.string_table.put(gpa, sym_name); if (symbol.isLocal()) { if (symbol.isUndefined()) { @@ -716,17 +744,17 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { log.err(" symbol '{s}' defined in '{s}'", .{ sym_name, object.name }); return error.UndefinedLocal; } - try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {}); + try wasm.resolved_symbols.putNoClobber(gpa, location, {}); continue; } - const maybe_existing = try wasm.globals.getOrPut(wasm.base.allocator, sym_name_index); + const maybe_existing = try wasm.globals.getOrPut(gpa, sym_name_index); if (!maybe_existing.found_existing) { maybe_existing.value_ptr.* = location; - try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {}); + try wasm.resolved_symbols.putNoClobber(gpa, location, {}); if (symbol.isUndefined()) { - try wasm.undefs.putNoClobber(wasm.base.allocator, sym_name_index, location); + try wasm.undefs.putNoClobber(gpa, sym_name_index, location); } continue; } @@ -753,7 +781,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { return error.SymbolCollision; } - try wasm.discarded.put(wasm.base.allocator, location, existing_loc); + try wasm.discarded.put(gpa, location, existing_loc); continue; // Do not overwrite defined symbols with undefined symbols } @@ -791,7 +819,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { } // both undefined so skip overwriting existing symbol and discard the new symbol - try wasm.discarded.put(wasm.base.allocator, location, existing_loc); + try wasm.discarded.put(gpa, location, existing_loc); continue; } @@ -822,7 +850,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { // symbol is weak and the new one isn't, in which case we *do* overwrite it. if (existing_sym.isWeak() and symbol.isWeak()) blk: { if (existing_sym.isUndefined() and !symbol.isUndefined()) break :blk; - try wasm.discarded.put(wasm.base.allocator, location, existing_loc); + try wasm.discarded.put(gpa, location, existing_loc); continue; } @@ -830,10 +858,10 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { log.debug("Overwriting symbol '{s}'", .{sym_name}); log.debug(" old definition in '{s}'", .{existing_file_path}); log.debug(" new definition in '{s}'", .{object.name}); - try wasm.discarded.putNoClobber(wasm.base.allocator, existing_loc, location); + try wasm.discarded.putNoClobber(gpa, existing_loc, location); maybe_existing.value_ptr.* = location; - try wasm.globals.put(wasm.base.allocator, sym_name_index, location); - try wasm.resolved_symbols.put(wasm.base.allocator, location, {}); + try wasm.globals.put(gpa, sym_name_index, location); + try wasm.resolved_symbols.put(gpa, location, {}); assert(wasm.resolved_symbols.swapRemove(existing_loc)); if (existing_sym.isUndefined()) { _ = wasm.undefs.swapRemove(sym_name_index); @@ -842,6 +870,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { } fn resolveSymbolsInArchives(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; if (wasm.archives.items.len == 0) return; log.debug("Resolving symbols in archives", .{}); @@ -860,9 +889,9 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { // Symbol is found in unparsed object file within current archive. // Parse object and and resolve symbols again before we check remaining // undefined symbols. - const object_file_index = @as(u16, @intCast(wasm.objects.items.len)); - const object = try archive.parseObject(wasm.base.allocator, offset.items[0]); - try wasm.objects.append(wasm.base.allocator, object); + const object_file_index: u16 = @intCast(wasm.objects.items.len); + const object = try archive.parseObject(gpa, offset.items[0]); + try wasm.objects.append(gpa, object); try wasm.resolveSymbolsInObject(object_file_index); // continue loop for any remaining undefined symbols that still exist @@ -880,6 +909,8 @@ fn writeI32Const(writer: anytype, val: u32) !void { } fn setupInitMemoryFunction(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; + // Passive segments are used to avoid memory being reinitialized on each // thread's instantiation. These passive segments are initialized and // dropped in __wasm_init_memory, which is registered as the start function @@ -896,7 +927,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { break :address loc.getSymbol(wasm).virtual_address; } else 0; - var function_body = std.ArrayList(u8).init(wasm.base.allocator); + var function_body = std.ArrayList(u8).init(gpa); defer function_body.deinit(); const writer = function_body.writer(); @@ -1040,6 +1071,8 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { /// Constructs a synthetic function that performs runtime relocations for /// TLS symbols. This function is called by `__wasm_init_tls`. fn setupTLSRelocationsFunction(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; + // When we have TLS GOT entries and shared memory is enabled, // we must perform runtime relocations or else we don't create the function. if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) { @@ -1047,7 +1080,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void { } // const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs"); - var function_body = std.ArrayList(u8).init(wasm.base.allocator); + var function_body = std.ArrayList(u8).init(gpa); defer function_body.deinit(); const writer = function_body.writer(); @@ -1221,10 +1254,12 @@ fn validateFeatures( /// if one or multiple undefined references exist. When none exist, the symbol will /// not be created, ensuring we don't unneccesarily emit unreferenced symbols. fn resolveLazySymbols(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; + if (wasm.string_table.getOffset("__heap_base")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); - try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); + try wasm.discarded.putNoClobber(gpa, kv.value, loc); _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. } } @@ -1232,7 +1267,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { if (wasm.string_table.getOffset("__heap_end")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); - try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); + try wasm.discarded.putNoClobber(gpa, kv.value, loc); _ = wasm.resolved_symbols.swapRemove(loc); } } @@ -1241,12 +1276,12 @@ fn resolveLazySymbols(wasm: *Wasm) !void { if (wasm.string_table.getOffset("__tls_base")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); - try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); + try wasm.discarded.putNoClobber(gpa, kv.value, loc); _ = wasm.resolved_symbols.swapRemove(kv.value); const symbol = loc.getSymbol(wasm); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len); - try wasm.wasm_globals.append(wasm.base.allocator, .{ + try wasm.wasm_globals.append(gpa, .{ .global_type = .{ .valtype = .i32, .mutable = true }, .init = .{ .i32_const = undefined }, }); @@ -1256,7 +1291,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); - try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); + try wasm.discarded.putNoClobber(gpa, kv.value, loc); _ = wasm.resolved_symbols.swapRemove(kv.value); } } @@ -1292,8 +1327,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void { } pub fn deinit(wasm: *Wasm) void { - const gpa = wasm.base.allocator; - if (wasm.llvm_object) |llvm_object| llvm_object.destroy(gpa); + const gpa = wasm.base.comp.gpa; + if (wasm.llvm_object) |llvm_object| llvm_object.deinit(); for (wasm.func_types.items) |*func_type| { func_type.deinit(gpa); @@ -1378,7 +1413,9 @@ pub fn deinit(wasm: *Wasm) void { /// Allocates a new symbol and returns its index. /// Will re-use slots when a symbol was freed at an earlier stage. pub fn allocateSymbol(wasm: *Wasm) !u32 { - try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1); + const gpa = wasm.base.comp.gpa; + + try wasm.symbols.ensureUnusedCapacity(gpa, 1); const symbol: Symbol = .{ .name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), @@ -1404,6 +1441,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air: const tracy = trace(@src()); defer tracy.end(); + const gpa = wasm.base.comp.gpa; const func = mod.funcInfo(func_index); const decl_index = func.owner_decl; const decl = mod.declPtr(decl_index); @@ -1414,7 +1452,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: InternPool.Index, air: // var decl_state: ?Dwarf.DeclState = if (wasm.dwarf) |*dwarf| try dwarf.initDeclState(mod, decl_index) else null; // defer if (decl_state) |*ds| ds.deinit(); - var code_writer = std.ArrayList(u8).init(wasm.base.allocator); + var code_writer = std.ArrayList(u8).init(gpa); defer code_writer.deinit(); // const result = try codegen.generateFunction( // &wasm.base, @@ -1477,6 +1515,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) ! return; } + const gpa = wasm.base.comp.gpa; const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); const atom = wasm.getAtomPtr(atom_index); atom.clear(); @@ -1489,7 +1528,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: InternPool.DeclIndex) ! } const val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val; - var code_writer = std.ArrayList(u8).init(wasm.base.allocator); + var code_writer = std.ArrayList(u8).init(gpa); defer code_writer.deinit(); const res = try codegen.generateSymbol( @@ -1528,16 +1567,17 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.De } fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const u8, symbol_tag: Symbol.Tag) !void { + const gpa = wasm.base.comp.gpa; const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); const atom_index = wasm.decls.get(decl_index).?; const atom = wasm.getAtomPtr(atom_index); const symbol = &wasm.symbols.items[atom.sym_index]; const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); - symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name); + symbol.name = try wasm.string_table.put(gpa, full_name); symbol.tag = symbol_tag; - try atom.code.appendSlice(wasm.base.allocator, code); - try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); + try atom.code.appendSlice(gpa, code); + try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {}); atom.size = @intCast(code.len); if (code.len == 0) return; @@ -1591,6 +1631,7 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { /// Returns the symbol index of the local /// The given `decl` is the parent decl whom owns the constant. pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 { + const gpa = wasm.base.comp.gpa; const mod = wasm.base.options.module.?; assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions const decl = mod.declPtr(decl_index); @@ -1599,14 +1640,14 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.Dec const parent_atom = wasm.getAtom(parent_atom_index); const local_index = parent_atom.locals.items.len; const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); - const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ + const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{ fqn, local_index, }); - defer wasm.base.allocator.free(name); + defer gpa.free(name); switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) { .ok => |atom_index| { - try wasm.getAtomPtr(parent_atom_index).locals.append(wasm.base.allocator, atom_index); + try wasm.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index); return wasm.getAtom(atom_index).getSymbolIndex().?; }, .fail => |em| { @@ -1623,24 +1664,25 @@ const LowerConstResult = union(enum) { }; fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult { + const gpa = wasm.base.comp.gpa; const mod = wasm.base.options.module.?; // Create and initialize a new local symbol and atom const atom_index = try wasm.createAtom(); - var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); + var value_bytes = std.ArrayList(u8).init(gpa); defer value_bytes.deinit(); const code = code: { const atom = wasm.getAtomPtr(atom_index); atom.alignment = tv.ty.abiAlignment(mod); wasm.symbols.items[atom.sym_index] = .{ - .name = try wasm.string_table.put(wasm.base.allocator, name), + .name = try wasm.string_table.put(gpa, name), .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), .tag = .data, .index = undefined, .virtual_address = undefined, }; - try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, atom.symbolLoc(), {}); + try wasm.resolved_symbols.putNoClobber(gpa, atom.symbolLoc(), {}); const result = try codegen.generateSymbol( &wasm.base, @@ -1663,7 +1705,7 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src const atom = wasm.getAtomPtr(atom_index); atom.size = @intCast(code.len); - try atom.code.appendSlice(wasm.base.allocator, code); + try atom.code.appendSlice(gpa, code); return .{ .ok = atom_index }; } @@ -1673,8 +1715,9 @@ fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.Src /// and then returns the index to it. pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u32 { _ = lib_name; - const name_index = try wasm.string_table.put(wasm.base.allocator, name); - const gop = try wasm.globals.getOrPut(wasm.base.allocator, name_index); + const gpa = wasm.base.comp.gpa; + const name_index = try wasm.string_table.put(gpa, name); + const gop = try wasm.globals.getOrPut(gpa, name_index); if (gop.found_existing) { return gop.value_ptr.*.index; } @@ -1691,14 +1734,14 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3 const sym_index = if (wasm.symbols_free_list.popOrNull()) |index| index else blk: { const index: u32 = @intCast(wasm.symbols.items.len); - try wasm.symbols.ensureUnusedCapacity(wasm.base.allocator, 1); + try wasm.symbols.ensureUnusedCapacity(gpa, 1); wasm.symbols.items.len += 1; break :blk index; }; wasm.symbols.items[sym_index] = symbol; gop.value_ptr.* = .{ .index = sym_index, .file = null }; - try wasm.resolved_symbols.put(wasm.base.allocator, gop.value_ptr.*, {}); - try wasm.undefs.putNoClobber(wasm.base.allocator, name_index, gop.value_ptr.*); + try wasm.resolved_symbols.put(gpa, gop.value_ptr.*, {}); + try wasm.undefs.putNoClobber(gpa, name_index, gop.value_ptr.*); return sym_index; } @@ -1709,6 +1752,7 @@ pub fn getDeclVAddr( decl_index: InternPool.DeclIndex, reloc_info: link.File.RelocInfo, ) !u64 { + const gpa = wasm.base.comp.gpa; const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); @@ -1725,17 +1769,17 @@ pub fn getDeclVAddr( // as function pointers are not allowed to be stored inside the data section. // They are instead stored in a function table which are called by index. try wasm.addTableFunction(target_symbol_index); - try atom.relocs.append(wasm.base.allocator, .{ + try atom.relocs.append(gpa, .{ .index = target_symbol_index, - .offset = @as(u32, @intCast(reloc_info.offset)), + .offset = @intCast(reloc_info.offset), .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, }); } else { - try atom.relocs.append(wasm.base.allocator, .{ + try atom.relocs.append(gpa, .{ .index = target_symbol_index, - .offset = @as(u32, @intCast(reloc_info.offset)), + .offset = @intCast(reloc_info.offset), .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, - .addend = @as(i32, @intCast(reloc_info.addend)), + .addend = @intCast(reloc_info.addend), }); } // we do not know the final address at this point, @@ -1751,7 +1795,8 @@ pub fn lowerAnonDecl( explicit_alignment: Alignment, src_loc: Module.SrcLoc, ) !codegen.Result { - const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val); + const gpa = wasm.base.comp.gpa; + const gop = try wasm.anon_decls.getOrPut(gpa, decl_val); if (!gop.found_existing) { const mod = wasm.base.options.module.?; const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); @@ -1779,6 +1824,7 @@ pub fn lowerAnonDecl( } pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { + const gpa = wasm.base.comp.gpa; const atom_index = wasm.anon_decls.get(decl_val).?; const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?; @@ -1793,17 +1839,17 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin // as function pointers are not allowed to be stored inside the data section. // They are instead stored in a function table which are called by index. try wasm.addTableFunction(target_symbol_index); - try parent_atom.relocs.append(wasm.base.allocator, .{ + try parent_atom.relocs.append(gpa, .{ .index = target_symbol_index, - .offset = @as(u32, @intCast(reloc_info.offset)), + .offset = @intCast(reloc_info.offset), .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64, }); } else { - try parent_atom.relocs.append(wasm.base.allocator, .{ + try parent_atom.relocs.append(gpa, .{ .index = target_symbol_index, - .offset = @as(u32, @intCast(reloc_info.offset)), + .offset = @intCast(reloc_info.offset), .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64, - .addend = @as(i32, @intCast(reloc_info.addend)), + .addend = @intCast(reloc_info.addend), }); } @@ -1840,8 +1886,6 @@ pub fn updateExports( } if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports); - if (wasm.base.options.emit == null) return; - const decl_index = switch (exported) { .decl_index => |i| i, .value => |val| { @@ -1880,7 +1924,7 @@ pub fn updateExports( }; const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index); const exported_atom = wasm.getAtom(exported_atom_index); - const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name)); + const export_name = try wasm.string_table.put(gpa, mod.intern_pool.stringToSlice(exp.opts.name)); const sym_loc = exported_atom.symbolLoc(); const symbol = sym_loc.getSymbol(wasm); symbol.setGlobal(true); @@ -1915,7 +1959,7 @@ pub fn updateExports( if (!existing_sym.isUndefined()) blk: { if (symbol.isWeak()) { - try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc); + try wasm.discarded.put(gpa, existing_loc, sym_loc); continue; // to-be-exported symbol is weak, so we keep the existing symbol } @@ -1939,18 +1983,18 @@ pub fn updateExports( } // in this case the existing symbol must be replaced either because it's weak or undefined. - try wasm.discarded.put(wasm.base.allocator, existing_loc, sym_loc); + try wasm.discarded.put(gpa, existing_loc, sym_loc); _ = wasm.imports.remove(existing_loc); _ = wasm.undefs.swapRemove(existing_sym.name); } // Ensure the symbol will be exported using the given name if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { - try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); + try wasm.export_names.put(gpa, sym_loc, export_name); } try wasm.globals.put( - wasm.base.allocator, + gpa, export_name, sym_loc, ); @@ -1959,18 +2003,19 @@ pub fn updateExports( pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { if (wasm.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index); + const gpa = wasm.base.comp.gpa; const mod = wasm.base.options.module.?; const decl = mod.declPtr(decl_index); const atom_index = wasm.decls.get(decl_index).?; const atom = wasm.getAtomPtr(atom_index); - wasm.symbols_free_list.append(wasm.base.allocator, atom.sym_index) catch {}; + wasm.symbols_free_list.append(gpa, atom.sym_index) catch {}; _ = wasm.decls.remove(decl_index); wasm.symbols.items[atom.sym_index].tag = .dead; for (atom.locals.items) |local_atom_index| { const local_atom = wasm.getAtom(local_atom_index); const local_symbol = &wasm.symbols.items[local_atom.sym_index]; local_symbol.tag = .dead; // also for any local symbol - wasm.symbols_free_list.append(wasm.base.allocator, local_atom.sym_index) catch {}; + wasm.symbols_free_list.append(gpa, local_atom.sym_index) catch {}; assert(wasm.resolved_symbols.swapRemove(local_atom.symbolLoc())); assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); } @@ -1999,8 +2044,9 @@ pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { /// Appends a new entry to the indirect function table pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void { - const index = @as(u32, @intCast(wasm.function_table.count())); - try wasm.function_table.put(wasm.base.allocator, .{ .file = null, .index = symbol_index }, index); + const gpa = wasm.base.comp.gpa; + const index: u32 = @intCast(wasm.function_table.count()); + try wasm.function_table.put(gpa, .{ .file = null, .index = symbol_index }, index); } /// Assigns indexes to all indirect functions. @@ -2019,7 +2065,7 @@ fn mapFunctionTable(wasm: *Wasm) void { } } - if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) { + if (wasm.import_table or wasm.base.options.output_mode == .Obj) { const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?; const import = wasm.imports.getPtr(sym_loc).?; import.kind.table.limits.min = index - 1; // we start at index 1. @@ -2048,6 +2094,7 @@ pub fn addOrUpdateImport( /// is asserted instead. type_index: ?u32, ) !void { + const gpa = wasm.base.comp.gpa; assert(symbol_index != 0); // For the import name, we use the decl's name, rather than the fully qualified name // Also mangle the name when the lib name is set and not equal to "C" so imports with the same @@ -2055,11 +2102,11 @@ pub fn addOrUpdateImport( const mangle_name = lib_name != null and !std.mem.eql(u8, lib_name.?, "c"); const full_name = if (mangle_name) full_name: { - break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? }); + break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? }); } else name; - defer if (mangle_name) wasm.base.allocator.free(full_name); + defer if (mangle_name) gpa.free(full_name); - const decl_name_index = try wasm.string_table.put(wasm.base.allocator, full_name); + const decl_name_index = try wasm.string_table.put(gpa, full_name); const symbol: *Symbol = &wasm.symbols.items[symbol_index]; symbol.setUndefined(true); symbol.setGlobal(true); @@ -2068,12 +2115,12 @@ pub fn addOrUpdateImport( // we specified a specific name for the symbol that does not match the import name symbol.setFlag(.WASM_SYM_EXPLICIT_NAME); } - const global_gop = try wasm.globals.getOrPut(wasm.base.allocator, decl_name_index); + const global_gop = try wasm.globals.getOrPut(gpa, decl_name_index); if (!global_gop.found_existing) { const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; global_gop.value_ptr.* = loc; - try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); - try wasm.undefs.putNoClobber(wasm.base.allocator, decl_name_index, loc); + try wasm.resolved_symbols.put(gpa, loc, {}); + try wasm.undefs.putNoClobber(gpa, decl_name_index, loc); } else if (global_gop.value_ptr.*.index != symbol_index) { // We are not updating a symbol, but found an existing global // symbol with the same name. This means we always favor the @@ -2081,21 +2128,21 @@ pub fn addOrUpdateImport( // We can also skip storing the import as we will not output // this symbol. return wasm.discarded.put( - wasm.base.allocator, + gpa, .{ .file = null, .index = symbol_index }, global_gop.value_ptr.*, ); } if (type_index) |ty_index| { - const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null }); + const gop = try wasm.imports.getOrPut(gpa, .{ .index = symbol_index, .file = null }); const module_name = if (lib_name) |l_name| blk: { break :blk l_name; } else wasm.host_name; if (!gop.found_existing) { gop.value_ptr.* = .{ - .module_name = try wasm.string_table.put(wasm.base.allocator, module_name), - .name = try wasm.string_table.put(wasm.base.allocator, name), + .module_name = try wasm.string_table.put(gpa, module_name), + .name = try wasm.string_table.put(gpa, name), .kind = .{ .function = ty_index }, }; } @@ -2132,10 +2179,10 @@ const Kind = union(enum) { /// Parses an Atom and inserts its metadata into the corresponding sections. fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { + const gpa = wasm.base.comp.gpa; const atom = wasm.getAtomPtr(atom_index); const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); - const do_garbage_collect = wasm.base.options.gc_sections orelse - (wasm.base.options.output_mode != .Obj); + const do_garbage_collect = wasm.base.gc_sections; if (symbol.isDead() and do_garbage_collect) { // Prevent unreferenced symbols from being parsed. @@ -2147,7 +2194,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { const index: u32 = @intCast(wasm.functions.count() + wasm.imported_functions_count); const type_index = wasm.atom_types.get(atom_index).?; try wasm.functions.putNoClobber( - wasm.base.allocator, + gpa, .{ .file = null, .index = index }, .{ .func = .{ .type_index = type_index }, .sym_index = atom.sym_index }, ); @@ -2156,7 +2203,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { if (wasm.code_section_index == null) { wasm.code_section_index = @intCast(wasm.segments.items.len); - try wasm.segments.append(wasm.base.allocator, .{ + try wasm.segments.append(gpa, .{ .alignment = atom.alignment, .size = atom.size, .offset = 0, @@ -2167,11 +2214,11 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { break :result wasm.code_section_index.?; }, .data => result: { - const segment_name = try std.mem.concat(wasm.base.allocator, u8, &.{ + const segment_name = try std.mem.concat(gpa, u8, &.{ kind.segmentName(), wasm.string_table.get(symbol.name), }); - errdefer wasm.base.allocator.free(segment_name); + errdefer gpa.free(segment_name); const segment_info: types.Segment = .{ .name = segment_name, .alignment = atom.alignment, @@ -2188,14 +2235,14 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { } const should_merge = wasm.base.options.output_mode != .Obj; - const gop = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(should_merge)); + const gop = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(should_merge)); if (gop.found_existing) { const index = gop.value_ptr.*; wasm.segments.items[index].size += atom.size; symbol.index = @intCast(wasm.segment_info.getIndex(index).?); // segment info already exists, so free its memory - wasm.base.allocator.free(segment_name); + gpa.free(segment_name); break :result index; } else { const index: u32 = @intCast(wasm.segments.items.len); @@ -2203,7 +2250,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { if (wasm.base.options.shared_memory) { flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); } - try wasm.segments.append(wasm.base.allocator, .{ + try wasm.segments.append(gpa, .{ .alignment = atom.alignment, .size = 0, .offset = 0, @@ -2212,7 +2259,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { gop.value_ptr.* = index; const info_index: u32 = @intCast(wasm.segment_info.count()); - try wasm.segment_info.put(wasm.base.allocator, index, segment_info); + try wasm.segment_info.put(gpa, index, segment_info); symbol.index = info_index; break :result index; } @@ -2228,6 +2275,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { /// From a given index, append the given `Atom` at the back of the linked list. /// Simply inserts it into the map of atoms when it doesn't exist yet. pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void { + const gpa = wasm.base.comp.gpa; const atom = wasm.getAtomPtr(atom_index); if (wasm.atoms.getPtr(index)) |last_index_ptr| { const last = wasm.getAtomPtr(last_index_ptr.*); @@ -2235,7 +2283,7 @@ pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void atom.prev = last_index_ptr.*; last_index_ptr.* = atom_index; } else { - try wasm.atoms.putNoClobber(wasm.base.allocator, index, atom_index); + try wasm.atoms.putNoClobber(gpa, index, atom_index); } } @@ -2363,12 +2411,13 @@ fn allocateVirtualAddresses(wasm: *Wasm) void { } fn sortDataSegments(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{}; - try new_mapping.ensureUnusedCapacity(wasm.base.allocator, wasm.data_segments.count()); - errdefer new_mapping.deinit(wasm.base.allocator); + try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count()); + errdefer new_mapping.deinit(gpa); - const keys = try wasm.base.allocator.dupe([]const u8, wasm.data_segments.keys()); - defer wasm.base.allocator.free(keys); + const keys = try gpa.dupe([]const u8, wasm.data_segments.keys()); + defer gpa.free(keys); const SortContext = struct { fn sort(_: void, lhs: []const u8, rhs: []const u8) bool { @@ -2388,7 +2437,7 @@ fn sortDataSegments(wasm: *Wasm) !void { const segment_index = wasm.data_segments.get(key).?; new_mapping.putAssumeCapacity(key, segment_index); } - wasm.data_segments.deinit(wasm.base.allocator); + wasm.data_segments.deinit(gpa); wasm.data_segments = new_mapping; } @@ -2401,8 +2450,9 @@ fn sortDataSegments(wasm: *Wasm) !void { /// original functions and their types. We need to know the type to verify it doesn't /// contain any parameters. fn setupInitFunctions(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; for (wasm.objects.items, 0..) |object, file_index| { - try wasm.init_funcs.ensureUnusedCapacity(wasm.base.allocator, object.init_funcs.len); + try wasm.init_funcs.ensureUnusedCapacity(gpa, object.init_funcs.len); for (object.init_funcs) |init_func| { const symbol = object.symtable[init_func.symbol_index]; const ty: std.wasm.Type = if (symbol.isUndefined()) ty: { @@ -2439,6 +2489,7 @@ fn setupInitFunctions(wasm: *Wasm) !void { /// Generates an atom containing the global error set' size. /// This will only be generated if the symbol exists. fn setupErrorsLen(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return; const errors_len = wasm.base.options.module.?.global_error_set.count(); @@ -2456,19 +2507,19 @@ fn setupErrorsLen(wasm: *Wasm) !void { prev_atom.next = atom.next; atom.prev = null; } - atom.deinit(wasm.base.allocator); + atom.deinit(gpa); break :blk index; } else new_atom: { const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len); - try wasm.symbol_atom.put(wasm.base.allocator, loc, atom_index); - try wasm.managed_atoms.append(wasm.base.allocator, undefined); + try wasm.symbol_atom.put(gpa, loc, atom_index); + try wasm.managed_atoms.append(gpa, undefined); break :new_atom atom_index; }; const atom = wasm.getAtomPtr(atom_index); atom.* = Atom.empty; atom.sym_index = loc.index; atom.size = 2; - try atom.code.writer(wasm.base.allocator).writeInt(u16, @intCast(errors_len), .little); + try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little); try wasm.parseAtom(atom_index, .{ .data = .read_only }); } @@ -2480,16 +2531,17 @@ fn setupErrorsLen(wasm: *Wasm) !void { /// references to the function stored in the symbol have been finalized so we end /// up calling the resolved function. fn initializeCallCtorsFunction(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; // No code to emit, so also no ctors to call if (wasm.code_section_index == null) { // Make sure to remove it from the resolved symbols so we do not emit // it within any section. TODO: Remove this once we implement garbage collection. const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?; - std.debug.assert(wasm.resolved_symbols.swapRemove(loc)); + assert(wasm.resolved_symbols.swapRemove(loc)); return; } - var function_body = std.ArrayList(u8).init(wasm.base.allocator); + var function_body = std.ArrayList(u8).init(gpa); defer function_body.deinit(); const writer = function_body.writer(); @@ -2531,6 +2583,7 @@ fn createSyntheticFunction( func_ty: std.wasm.Type, function_body: *std.ArrayList(u8), ) !void { + const gpa = wasm.base.comp.gpa; const loc = wasm.findGlobalSymbol(symbol_name) orelse try wasm.createSyntheticSymbol(symbol_name, .function); const symbol = loc.getSymbol(wasm); @@ -2541,7 +2594,7 @@ fn createSyntheticFunction( // create function with above type const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count())); try wasm.functions.putNoClobber( - wasm.base.allocator, + gpa, .{ .file = null, .index = func_index }, .{ .func = .{ .type_index = ty_index }, .sym_index = loc.index }, ); @@ -2549,7 +2602,7 @@ fn createSyntheticFunction( // create the atom that will be output into the final binary const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); - const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); + const atom = try wasm.managed_atoms.addOne(gpa); atom.* = .{ .size = @as(u32, @intCast(function_body.items.len)), .offset = 0, @@ -2562,7 +2615,7 @@ fn createSyntheticFunction( .original_offset = 0, }; try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); + try wasm.symbol_atom.putNoClobber(gpa, loc, atom_index); // `allocateAtoms` has already been called, set the atom's offset manually. // This is fine to do manually as we insert the atom at the very end. @@ -2582,10 +2635,11 @@ pub fn createFunction( function_body: *std.ArrayList(u8), relocations: *std.ArrayList(Relocation), ) !u32 { + const gpa = wasm.base.comp.gpa; const loc = try wasm.createSyntheticSymbol(symbol_name, .function); - const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); - const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); + const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len); + const atom = try wasm.managed_atoms.addOne(gpa); atom.* = .{ .size = @intCast(function_body.items.len), .offset = 0, @@ -2607,9 +2661,9 @@ pub fn createFunction( break :idx index; }; try wasm.appendAtomAtIndex(section_index, atom_index); - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index); - try wasm.atom_types.put(wasm.base.allocator, atom_index, try wasm.putOrGetFuncType(func_ty)); - try wasm.synthetic_functions.append(wasm.base.allocator, atom_index); + try wasm.symbol_atom.putNoClobber(gpa, loc, atom_index); + try wasm.atom_types.put(gpa, atom_index, try wasm.putOrGetFuncType(func_ty)); + try wasm.synthetic_functions.append(gpa, atom_index); return loc.index; } @@ -2622,9 +2676,11 @@ fn setupStartSection(wasm: *Wasm) !void { } fn initializeTLSFunction(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; + if (!wasm.base.options.shared_memory) return; - var function_body = std.ArrayList(u8).init(wasm.base.allocator); + var function_body = std.ArrayList(u8).init(gpa); defer function_body.deinit(); const writer = function_body.writer(); @@ -2684,6 +2740,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { } fn setupImports(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; log.debug("Merging imports", .{}); var discarded_it = wasm.discarded.keyIterator(); while (discarded_it.next()) |discarded| { @@ -2718,12 +2775,12 @@ fn setupImports(wasm: *Wasm) !void { // We copy the import to a new import to ensure the names contain references // to the internal string table, rather than of the object file. const new_imp: types.Import = .{ - .module_name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.module_name)), - .name = try wasm.string_table.put(wasm.base.allocator, object.string_table.get(import.name)), + .module_name = try wasm.string_table.put(gpa, object.string_table.get(import.module_name)), + .name = try wasm.string_table.put(gpa, object.string_table.get(import.name)), .kind = import.kind, }; // TODO: De-duplicate imports when they contain the same names and type - try wasm.imports.putNoClobber(wasm.base.allocator, symbol_loc, new_imp); + try wasm.imports.putNoClobber(gpa, symbol_loc, new_imp); } // Assign all indexes of the imports to their representing symbols @@ -2764,7 +2821,9 @@ fn setupImports(wasm: *Wasm) !void { /// Takes the global, function and table section from each linked object file /// and merges it into a single section for each. fn mergeSections(wasm: *Wasm) !void { - var removed_duplicates = std.ArrayList(SymbolLoc).init(wasm.base.allocator); + const gpa = wasm.base.comp.gpa; + + var removed_duplicates = std.ArrayList(SymbolLoc).init(gpa); defer removed_duplicates.deinit(); for (wasm.resolved_symbols.keys()) |sym_loc| { @@ -2791,7 +2850,7 @@ fn mergeSections(wasm: *Wasm) !void { switch (symbol.tag) { .function => { const gop = try wasm.functions.getOrPut( - wasm.base.allocator, + gpa, .{ .file = sym_loc.file, .index = symbol.index }, ); if (gop.found_existing) { @@ -2800,7 +2859,7 @@ fn mergeSections(wasm: *Wasm) !void { // we only emit a single function, instead of duplicates. symbol.unmark(); try wasm.discarded.putNoClobber( - wasm.base.allocator, + gpa, sym_loc, .{ .file = gop.key_ptr.*.file, .index = gop.value_ptr.*.sym_index }, ); @@ -2813,12 +2872,12 @@ fn mergeSections(wasm: *Wasm) !void { .global => { const original_global = object.globals[index]; symbol.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count; - try wasm.wasm_globals.append(wasm.base.allocator, original_global); + try wasm.wasm_globals.append(gpa, original_global); }, .table => { const original_table = object.tables[index]; symbol.index = @as(u32, @intCast(wasm.tables.items.len)) + wasm.imported_tables_count; - try wasm.tables.append(wasm.base.allocator, original_table); + try wasm.tables.append(gpa, original_table); }, else => unreachable, } @@ -2838,10 +2897,11 @@ fn mergeSections(wasm: *Wasm) !void { /// 'types' section, while assigning the type index to the representing /// section (import, export, function). fn mergeTypes(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; // A map to track which functions have already had their // type inserted. If we do this for the same function multiple times, // it will be overwritten with the incorrect type. - var dirty = std.AutoHashMap(u32, void).init(wasm.base.allocator); + var dirty = std.AutoHashMap(u32, void).init(gpa); try dirty.ensureUnusedCapacity(@as(u32, @intCast(wasm.functions.count()))); defer dirty.deinit(); @@ -2873,6 +2933,7 @@ fn mergeTypes(wasm: *Wasm) !void { } fn setupExports(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; if (wasm.base.options.output_mode == .Obj) return; log.debug("Building exports from symbols", .{}); @@ -2903,11 +2964,11 @@ fn setupExports(wasm: *Wasm) !void { const sym_name = sym_loc.getName(wasm); const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { if (sym_loc.file == null) break :blk symbol.name; - break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); + break :blk try wasm.string_table.put(gpa, sym_name); }; const exp: types.Export = if (symbol.tag == .data) exp: { const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len)); - try wasm.wasm_globals.append(wasm.base.allocator, .{ + try wasm.wasm_globals.append(gpa, .{ .global_type = .{ .valtype = .i32, .mutable = false }, .init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) }, }); @@ -2926,7 +2987,7 @@ fn setupExports(wasm: *Wasm) !void { wasm.string_table.get(exp.name), exp.index, }); - try wasm.exports.append(wasm.base.allocator, exp); + try wasm.exports.append(gpa, exp); } log.debug("Completed building exports. Total count: ({d})", .{wasm.exports.items.len}); @@ -2957,8 +3018,6 @@ fn setupStart(wasm: *Wasm) !void { fn setupMemory(wasm: *Wasm) !void { log.debug("Setting up memory layout", .{}); const page_size = std.wasm.page_size; // 64kb - // Use the user-provided stack size or else we use 1MB by default - const stack_size = wasm.base.options.stack_size_override orelse page_size * 16; const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention const heap_alignment: Alignment = .@"16"; // wasm's heap alignment as specified by tool-convention @@ -2974,7 +3033,7 @@ fn setupMemory(wasm: *Wasm) !void { if (place_stack_first and !is_obj) { memory_ptr = stack_alignment.forward(memory_ptr); - memory_ptr += stack_size; + memory_ptr += wasm.base.stack_size; // We always put the stack pointer global at index 0 wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); } @@ -3021,7 +3080,7 @@ fn setupMemory(wasm: *Wasm) !void { if (!place_stack_first and !is_obj) { memory_ptr = stack_alignment.forward(memory_ptr); - memory_ptr += stack_size; + memory_ptr += wasm.base.stack_size; wasm.wasm_globals.items[0].init.i32_const = @as(i32, @bitCast(@as(u32, @intCast(memory_ptr)))); } @@ -3088,29 +3147,30 @@ fn setupMemory(wasm: *Wasm) !void { /// index of the segment within the final data section. When the segment does not yet /// exist, a new one will be initialized and appended. The new index will be returned in that case. pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 { + const gpa = wasm.base.comp.gpa; const object: Object = wasm.objects.items[object_index]; const symbol = object.symtable[symbol_index]; - const index = @as(u32, @intCast(wasm.segments.items.len)); + const index: u32 = @intCast(wasm.segments.items.len); switch (symbol.tag) { .data => { const segment_info = object.segment_info[symbol.index]; const merge_segment = wasm.base.options.output_mode != .Obj; - const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment)); + const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment)); if (!result.found_existing) { result.value_ptr.* = index; var flags: u32 = 0; if (wasm.base.options.shared_memory) { flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); } - try wasm.segments.append(wasm.base.allocator, .{ + try wasm.segments.append(gpa, .{ .alignment = .@"1", .size = 0, .offset = 0, .flags = flags, }); - try wasm.segment_info.putNoClobber(wasm.base.allocator, index, .{ - .name = try wasm.base.allocator.dupe(u8, segment_info.name), + try wasm.segment_info.putNoClobber(gpa, index, .{ + .name = try gpa.dupe(u8, segment_info.name), .alignment = segment_info.alignment, .flags = segment_info.flags, }); @@ -3183,7 +3243,8 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u3 /// Appends a new segment with default field values fn appendDummySegment(wasm: *Wasm) !void { - try wasm.segments.append(wasm.base.allocator, .{ + const gpa = wasm.base.comp.gpa; + try wasm.segments.append(gpa, .{ .alignment = .@"1", .size = 0, .offset = 0, @@ -3203,6 +3264,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { // and then return said symbol's index. The final table will be populated // during `flush` when we know all possible error names. + const gpa = wasm.base.comp.gpa; const atom_index = try wasm.createAtom(); const atom = wasm.getAtomPtr(atom_index); const slice_ty = Type.slice_const_u8_sentinel_0; @@ -3210,7 +3272,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { atom.alignment = slice_ty.abiAlignment(mod); const sym_index = atom.sym_index; - const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table"); + const sym_name = try wasm.string_table.put(gpa, "__zig_err_name_table"); const symbol = &wasm.symbols.items[sym_index]; symbol.* = .{ .name = sym_name, @@ -3222,7 +3284,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); symbol.mark(); - try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); + try wasm.resolved_symbols.put(gpa, atom.symbolLoc(), {}); log.debug("Error name table was created with symbol index: ({d})", .{sym_index}); wasm.error_table_symbol = sym_index; @@ -3234,6 +3296,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { /// This creates a table that consists of pointers and length to each error name. /// The table is what is being pointed to within the runtime bodies that are generated. fn populateErrorNameTable(wasm: *Wasm) !void { + const gpa = wasm.base.comp.gpa; const symbol_index = wasm.error_table_symbol orelse return; const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = symbol_index }).?; @@ -3243,7 +3306,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { const names_atom_index = try wasm.createAtom(); const names_atom = wasm.getAtomPtr(names_atom_index); names_atom.alignment = .@"1"; - const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_names"); + const sym_name = try wasm.string_table.put(gpa, "__zig_err_names"); const names_symbol = &wasm.symbols.items[names_atom.sym_index]; names_symbol.* = .{ .name = sym_name, @@ -3269,10 +3332,10 @@ fn populateErrorNameTable(wasm: *Wasm) !void { const slice_ty = Type.slice_const_u8_sentinel_0; const offset = @as(u32, @intCast(atom.code.items.len)); // first we create the data for the slice of the name - try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated - try atom.code.writer(wasm.base.allocator).writeInt(u32, len - 1, .little); + try atom.code.appendNTimes(gpa, 0, 4); // ptr to name, will be relocated + try atom.code.writer(gpa).writeInt(u32, len - 1, .little); // create relocation to the error name - try atom.relocs.append(wasm.base.allocator, .{ + try atom.relocs.append(gpa, .{ .index = names_atom.sym_index, .relocation_type = .R_WASM_MEMORY_ADDR_I32, .offset = offset, @@ -3282,7 +3345,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { addend += len; // as we updated the error name table, we now store the actual name within the names atom - try names_atom.code.ensureUnusedCapacity(wasm.base.allocator, len); + try names_atom.code.ensureUnusedCapacity(gpa, len); names_atom.code.appendSliceAssumeCapacity(error_name); names_atom.code.appendAssumeCapacity(0); @@ -3291,8 +3354,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void { names_atom.size = addend; const name_loc = names_atom.symbolLoc(); - try wasm.resolved_symbols.put(wasm.base.allocator, name_loc, {}); - try wasm.symbol_atom.put(wasm.base.allocator, name_loc, names_atom_index); + try wasm.resolved_symbols.put(gpa, name_loc, {}); + try wasm.symbol_atom.put(gpa, name_loc, names_atom_index); // link the atoms with the rest of the binary so they can be allocated // and relocations will be performed. @@ -3304,7 +3367,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void { /// This initializes the index, appends a new segment, /// and finally, creates a managed `Atom`. pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) !Atom.Index { - const new_index = @as(u32, @intCast(wasm.segments.items.len)); + const gpa = wasm.base.comp.gpa; + const new_index: u32 = @intCast(wasm.segments.items.len); index.* = new_index; try wasm.appendDummySegment(); @@ -3312,7 +3376,7 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! const atom = wasm.getAtomPtr(atom_index); wasm.symbols.items[atom.sym_index] = .{ .tag = .section, - .name = try wasm.string_table.put(wasm.base.allocator, name), + .name = try wasm.string_table.put(gpa, name), .index = 0, .flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL), }; @@ -3322,8 +3386,10 @@ pub fn createDebugSectionForIndex(wasm: *Wasm, index: *?u32, name: []const u8) ! } fn resetState(wasm: *Wasm) void { + const gpa = wasm.base.comp.gpa; + for (wasm.segment_info.values()) |segment_info| { - wasm.base.allocator.free(segment_info.name); + gpa.free(segment_info.name); } var atom_it = wasm.decls.valueIterator(); @@ -3358,16 +3424,12 @@ fn resetState(wasm: *Wasm) void { } pub fn flush(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { - if (wasm.base.options.emit == null) { - if (wasm.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp, prog_node); - } - return; - } + const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld; + const use_llvm = wasm.base.comp.config.use_llvm; - if (build_options.have_llvm and wasm.base.options.use_lld) { + if (use_lld) { return wasm.linkWithLLD(comp, prog_node); - } else if (wasm.base.options.use_llvm and !wasm.base.options.use_lld) { + } else if (use_llvm and !use_lld) { return wasm.linkWithZld(comp, prog_node); } else { return wasm.flushModule(comp, prog_node); @@ -3379,21 +3441,22 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l const tracy = trace(@src()); defer tracy.end(); - const gpa = wasm.base.allocator; - const options = wasm.base.options; + const gpa = wasm.base.comp.gpa; // Used for all temporary memory allocated during flushin var arena_instance = std.heap.ArenaAllocator.init(gpa); defer arena_instance.deinit(); const arena = arena_instance.allocator(); - const directory = options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{options.emit.?.sub_path}); + const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path}); + const opt_zcu = wasm.base.comp.module; + const use_llvm = wasm.base.comp.config.use_llvm; // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (options.module != null) blk: { - assert(options.use_llvm); // `linkWithZld` should never be called when the Wasm backend is used + const module_obj_path: ?[]const u8 = if (opt_zcu != null) blk: { + assert(use_llvm); // `linkWithZld` should never be called when the Wasm backend is used try wasm.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { @@ -3416,12 +3479,14 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l const id_symlink_basename = "zld.id"; var man: Cache.Manifest = undefined; - defer if (!options.disable_lld_caching) man.deinit(); + defer if (!wasm.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; + const objects = wasm.base.comp.objects; + // NOTE: The following section must be maintained to be equal // as the section defined in `linkWithLLD` - if (!options.disable_lld_caching) { + if (!wasm.base.disable_lld_caching) { man = comp.cache_parent.obtain(); // We are about to obtain this lock, so here we give other processes a chance first. @@ -3429,7 +3494,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l comptime assert(Compilation.link_hash_implementation_version == 10); - for (options.objects) |obj| { + for (objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); } @@ -3438,19 +3503,19 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l } try man.addOptionalFile(module_obj_path); try man.addOptionalFile(compiler_rt_path); - man.hash.addOptionalBytes(options.entry); - man.hash.addOptional(options.stack_size_override); - man.hash.add(wasm.base.options.build_id); - man.hash.add(options.import_memory); - man.hash.add(options.import_table); - man.hash.add(options.export_table); - man.hash.addOptional(options.initial_memory); - man.hash.addOptional(options.max_memory); - man.hash.add(options.shared_memory); - man.hash.addOptional(options.global_base); - man.hash.add(options.export_symbol_names.len); + man.hash.addOptionalBytes(wasm.base.comp.config.entry); + man.hash.add(wasm.base.stack_size); + man.hash.add(wasm.base.build_id); + man.hash.add(wasm.base.comp.config.import_memory); + man.hash.add(wasm.base.comp.config.shared_memory); + man.hash.add(wasm.import_table); + man.hash.add(wasm.export_table); + man.hash.addOptional(wasm.initial_memory); + man.hash.addOptional(wasm.max_memory); + man.hash.addOptional(wasm.global_base); + man.hash.add(wasm.export_symbol_names.len); // strip does not need to go into the linker hash because it is part of the hash namespace - for (options.export_symbol_names) |symbol_name| { + for (wasm.export_symbol_names) |symbol_name| { man.hash.addBytes(symbol_name); } @@ -3485,30 +3550,36 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l // Positional arguments to the linker such as object files and static archives. var positionals = std.ArrayList([]const u8).init(arena); - try positionals.ensureUnusedCapacity(options.objects.len); + try positionals.ensureUnusedCapacity(objects.len); + + const target = wasm.base.comp.root_mod.resolved_target.result; + const output_mode = wasm.base.comp.config.output_mode; + const link_mode = wasm.base.comp.config.link_mode; + const link_libc = wasm.base.comp.config.link_libc; + const link_libcpp = wasm.base.comp.config.link_libcpp; + const wasi_exec_model = wasm.base.comp.config.wasi_exec_model; // When the target os is WASI, we allow linking with WASI-LIBC - if (options.target.os.tag == .wasi) { - const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or - (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic); + if (target.os.tag == .wasi) { + const is_exe_or_dyn_lib = output_mode == .Exe or + (output_mode == .Lib and link_mode == .Dynamic); if (is_exe_or_dyn_lib) { - const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs; - for (wasi_emulated_libs) |crt_file| { + for (wasm.wasi_emulated_libs) |crt_file| { try positionals.append(try comp.get_libc_crt_file( arena, wasi_libc.emulatedLibCRFileLibName(crt_file), )); } - if (wasm.base.options.link_libc) { + if (link_libc) { try positionals.append(try comp.get_libc_crt_file( arena, - wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model), + wasi_libc.execModelCrtFileFullName(wasi_exec_model), )); try positionals.append(try comp.get_libc_crt_file(arena, "libc.a")); } - if (wasm.base.options.link_libcpp) { + if (link_libcpp) { try positionals.append(comp.libcxx_static_lib.?.full_object_path); try positionals.append(comp.libcxxabi_static_lib.?.full_object_path); } @@ -3519,7 +3590,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l try positionals.append(path); } - for (options.objects) |object| { + for (objects) |object| { try positionals.append(object.path); } @@ -3562,7 +3633,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l try wasm.setupExports(); try wasm.writeToFile(enabled_features, emit_features_count, arena); - if (!wasm.base.options.disable_lld_caching) { + if (!wasm.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { @@ -3594,15 +3665,18 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try wasm.populateErrorNameTable(); // Used for all temporary memory allocated during flushin - var arena_instance = std.heap.ArenaAllocator.init(wasm.base.allocator); + const gpa = wasm.base.comp.gpa; + var arena_instance = std.heap.ArenaAllocator.init(gpa); defer arena_instance.deinit(); const arena = arena_instance.allocator(); + const objects = wasm.base.comp.objects; + // Positional arguments to the linker such as object files and static archives. var positionals = std.ArrayList([]const u8).init(arena); - try positionals.ensureUnusedCapacity(wasm.base.options.objects.len); + try positionals.ensureUnusedCapacity(objects.len); - for (wasm.base.options.objects) |object| { + for (objects) |object| { positionals.appendAssumeCapacity(object.path); } @@ -3711,6 +3785,10 @@ fn writeToFile( feature_count: u32, arena: Allocator, ) !void { + const gpa = wasm.base.comp.gpa; + const use_llvm = wasm.base.comp.config.use_llvm; + const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld; + // Size of each section header const header_size = 5 + 1; // The amount of sections that will be written @@ -3719,9 +3797,9 @@ fn writeToFile( var code_section_index: ?u32 = null; // Index of the data section. Used to tell relocation table where the section lives. var data_section_index: ?u32 = null; - const is_obj = wasm.base.options.output_mode == .Obj or (!wasm.base.options.use_llvm and wasm.base.options.use_lld); + const is_obj = wasm.base.options.output_mode == .Obj or (!use_llvm and use_lld); - var binary_bytes = std.ArrayList(u8).init(wasm.base.allocator); + var binary_bytes = std.ArrayList(u8).init(gpa); defer binary_bytes.deinit(); const binary_writer = binary_bytes.writer(); @@ -3774,8 +3852,8 @@ fn writeToFile( if (import_memory) { const mem_name = if (is_obj) "__linear_memory" else "memory"; const mem_imp: types.Import = .{ - .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name), - .name = try wasm.string_table.put(wasm.base.allocator, mem_name), + .module_name = try wasm.string_table.put(gpa, wasm.host_name), + .name = try wasm.string_table.put(gpa, mem_name), .kind = .{ .memory = wasm.memories.limits }, }; try wasm.emitImport(binary_writer, mem_imp); @@ -3955,7 +4033,7 @@ fn writeToFile( var atom_index = wasm.atoms.get(code_index).?; // The code section must be sorted in line with the function order. - var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(wasm.base.allocator, wasm.functions.count()); + var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(gpa, wasm.functions.count()); defer sorted_atoms.deinit(); while (true) { @@ -3966,7 +4044,7 @@ fn writeToFile( sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions atom_index = atom.prev orelse break; } - std.debug.assert(wasm.functions.count() == sorted_atoms.items.len); + assert(wasm.functions.count() == sorted_atoms.items.len); const atom_sort_fn = struct { fn sort(ctx: *const Wasm, lhs: *const Atom, rhs: *const Atom) bool { @@ -4086,7 +4164,7 @@ fn writeToFile( if (!wasm.base.options.strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. - switch (wasm.base.options.build_id) { + switch (wasm.base.build_id) { .none => {}, .fast => { var id: [16]u8 = undefined; @@ -4121,7 +4199,7 @@ fn writeToFile( // try dwarf.writeDbgLineHeader(); // } - var debug_bytes = std.ArrayList(u8).init(wasm.base.allocator); + var debug_bytes = std.ArrayList(u8).init(gpa); defer debug_bytes.deinit(); const DebugSection = struct { @@ -4362,8 +4440,10 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem } fn emitNameSubsection(wasm: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void { + const gpa = wasm.base.comp.gpa; + // We must emit subsection size, so first write to a temporary list - var section_list = std.ArrayList(u8).init(wasm.base.allocator); + var section_list = std.ArrayList(u8).init(gpa); defer section_list.deinit(); const sub_writer = section_list.writer(); @@ -4445,12 +4525,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const tracy = trace(@src()); defer tracy.end(); - var arena_allocator = std.heap.ArenaAllocator.init(wasm.base.allocator); + const gpa = wasm.base.comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const directory = wasm.base.options.emit.?.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.options.emit.?.sub_path}); + const directory = wasm.base.emit.directory; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{wasm.base.emit.sub_path}); // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. @@ -4481,11 +4562,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; - defer if (!wasm.base.options.disable_lld_caching) man.deinit(); + defer if (!wasm.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; - if (!wasm.base.options.disable_lld_caching) { + if (!wasm.base.disable_lld_caching) { man = comp.cache_parent.obtain(); // We are about to obtain this lock, so here we give other processes a chance first. @@ -4502,13 +4583,13 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } try man.addOptionalFile(module_obj_path); try man.addOptionalFile(compiler_rt_path); - man.hash.addOptionalBytes(wasm.base.options.entry); - man.hash.addOptional(wasm.base.options.stack_size_override); - man.hash.add(wasm.base.options.build_id); + man.hash.addOptionalBytes(wasm.base.comp.config.entry); + man.hash.add(wasm.base.stack_size); + man.hash.add(wasm.base.build_id); man.hash.add(wasm.base.options.import_memory); man.hash.add(wasm.base.options.export_memory); - man.hash.add(wasm.base.options.import_table); - man.hash.add(wasm.base.options.export_table); + man.hash.add(wasm.import_table); + man.hash.add(wasm.export_table); man.hash.addOptional(wasm.base.options.initial_memory); man.hash.addOptional(wasm.base.options.max_memory); man.hash.add(wasm.base.options.shared_memory); @@ -4573,7 +4654,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } } else { // Create an LLD command line and invoke it. - var argv = std.ArrayList([]const u8).init(wasm.base.allocator); + var argv = std.ArrayList([]const u8).init(gpa); defer argv.deinit(); // We will invoke ourselves as a child process to gain access to LLD. // This is necessary because LLD does not behave properly as a library - @@ -4598,22 +4679,20 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append("--export-memory"); } - if (wasm.base.options.import_table) { - assert(!wasm.base.options.export_table); + if (wasm.import_table) { + assert(!wasm.export_table); try argv.append("--import-table"); } - if (wasm.base.options.export_table) { - assert(!wasm.base.options.import_table); + if (wasm.export_table) { + assert(!wasm.import_table); try argv.append("--export-table"); } - if (wasm.base.options.gc_sections) |gc| { - // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly - // specified it as garbage collection is enabled by default. - if (!gc) { - try argv.append("--no-gc-sections"); - } + // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly + // specified it as garbage collection is enabled by default. + if (!wasm.base.gc_sections) { + try argv.append("--no-gc-sections"); } if (wasm.base.options.strip) { @@ -4662,12 +4741,10 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append("--no-entry"); } - // Increase the default stack size to a more reasonable value of 1MB instead of - // the default of 1 Wasm page being 64KB, unless overridden by the user. - try argv.append("-z"); - const stack_size = wasm.base.options.stack_size_override orelse std.wasm.page_size * 16; - const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); - try argv.append(arg); + try argv.appendSlice(&.{ + "-z", + try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}), + }); if (wasm.base.options.import_symbols) { try argv.append("--allow-undefined"); @@ -4681,7 +4758,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } // XXX - TODO: add when wasm-ld supports --build-id. - // if (wasm.base.options.build_id) { + // if (wasm.base.build_id) { // try argv.append("--build-id=tree"); // } @@ -4695,8 +4772,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const is_exe_or_dyn_lib = wasm.base.options.output_mode == .Exe or (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic); if (is_exe_or_dyn_lib) { - const wasi_emulated_libs = wasm.base.options.wasi_emulated_libs; - for (wasi_emulated_libs) |crt_file| { + for (wasm.wasi_emulated_libs) |crt_file| { try argv.append(try comp.get_libc_crt_file( arena, wasi_libc.emulatedLibCRFileLibName(crt_file), @@ -4753,7 +4829,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append(p); } - if (wasm.base.options.verbose_link) { + if (wasm.base.comp.verbose_link) { // Skip over our own name so that the LLD linker name is the first argv item. Compilation.dump_argv(argv.items[1..]); } @@ -4838,7 +4914,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } } - if (!wasm.base.options.disable_lld_caching) { + if (!wasm.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { @@ -5113,14 +5189,15 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { if (wasm.getTypeIndex(func_type)) |index| { return index; } + const gpa = wasm.base.comp.gpa; // functype does not exist. - const index = @as(u32, @intCast(wasm.func_types.items.len)); - const params = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.params); - errdefer wasm.base.allocator.free(params); - const returns = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.returns); - errdefer wasm.base.allocator.free(returns); - try wasm.func_types.append(wasm.base.allocator, .{ + const index: u32 = @intCast(wasm.func_types.items.len); + const params = try gpa.dupe(std.wasm.Valtype, func_type.params); + errdefer gpa.free(params); + const returns = try gpa.dupe(std.wasm.Valtype, func_type.returns); + errdefer gpa.free(returns); + try wasm.func_types.append(gpa, .{ .params = params, .returns = returns, }); @@ -5131,9 +5208,10 @@ pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { /// Asserts declaration has an associated `Atom`. /// Returns the index into the list of types. pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: std.wasm.Type) !u32 { + const gpa = wasm.base.comp.gpa; const atom_index = wasm.decls.get(decl_index).?; const index = try wasm.putOrGetFuncType(func_type); - try wasm.atom_types.put(wasm.base.allocator, atom_index, index); + try wasm.atom_types.put(gpa, atom_index, index); return index; } @@ -5142,8 +5220,7 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s fn markReferences(wasm: *Wasm) !void { const tracy = trace(@src()); defer tracy.end(); - const do_garbage_collect = wasm.base.options.gc_sections orelse - (wasm.base.options.output_mode != .Obj); + const do_garbage_collect = wasm.base.gc_sections; for (wasm.resolved_symbols.keys()) |sym_loc| { const sym = sym_loc.getSymbol(wasm); diff --git a/src/main.zig b/src/main.zig index 5685ddad27..4f701398ca 100644 --- a/src/main.zig +++ b/src/main.zig @@ -842,7 +842,7 @@ fn buildOutputType( var linker_print_gc_sections: bool = false; var linker_print_icf_sections: bool = false; var linker_print_map: bool = false; - var linker_opt_bisect_limit: i32 = -1; + var llvm_opt_bisect_limit: c_int = -1; var linker_z_nocopyreloc = false; var linker_z_nodelete = false; var linker_z_notext = false; @@ -859,7 +859,7 @@ fn buildOutputType( var linker_module_definition_file: ?[]const u8 = null; var test_no_exec = false; var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{}; - var stack_size_override: ?u64 = null; + var stack_size: ?u64 = null; var image_base_override: ?u64 = null; var link_eh_frame_hdr = false; var link_emit_relocs = false; @@ -892,7 +892,7 @@ fn buildOutputType( var contains_res_file: bool = false; var reference_trace: ?u32 = null; var pdb_out_path: ?[]const u8 = null; - var dwarf_format: ?std.dwarf.Format = null; + var debug_format: ?link.File.DebugFormat = null; var error_limit: ?Module.ErrorInt = null; var want_structured_cfg: ?bool = null; // These are before resolving sysroot. @@ -1129,10 +1129,7 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "--force_undefined")) { try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {}); } else if (mem.eql(u8, arg, "--stack")) { - const next_arg = args_iter.nextOrFatal(); - stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| { - fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) }); - }; + stack_size = parseStackSize(args_iter.nextOrFatal()); } else if (mem.eql(u8, arg, "--image-base")) { const next_arg = args_iter.nextOrFatal(); image_base_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| { @@ -1487,9 +1484,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-strip")) { mod_opts.strip = false; } else if (mem.eql(u8, arg, "-gdwarf32")) { - dwarf_format = .@"32"; + debug_format = .{ .dwarf = .@"32" }; } else if (mem.eql(u8, arg, "-gdwarf64")) { - dwarf_format = .@"64"; + debug_format = .{ .dwarf = .@"64" }; } else if (mem.eql(u8, arg, "-fformatted-panics")) { formatted_panics = true; } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { @@ -1511,7 +1508,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-builtin")) { no_builtin = true; } else if (mem.startsWith(u8, arg, "-fopt-bisect-limit=")) { - linker_opt_bisect_limit = std.math.lossyCast(i32, parseIntSuffix(arg, "-fopt-bisect-limit=".len)); + const next_arg = arg["-fopt-bisect-limit=".len..]; + llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err| + fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { link_eh_frame_hdr = true; } else if (mem.eql(u8, arg, "--dynamicbase")) { @@ -1994,11 +1993,11 @@ fn buildOutputType( }, .gdwarf32 => { mod_opts.strip = false; - dwarf_format = .@"32"; + debug_format = .{ .dwarf = .@"32" }; }, .gdwarf64 => { mod_opts.strip = false; - dwarf_format = .@"64"; + debug_format = .{ .dwarf = .@"64" }; }, .sanitize => { if (mem.eql(u8, it.only_arg, "undefined")) { @@ -2257,10 +2256,7 @@ fn buildOutputType( } else if (mem.eql(u8, z_arg, "norelro")) { linker_z_relro = false; } else if (mem.startsWith(u8, z_arg, "stack-size=")) { - const next_arg = z_arg["stack-size=".len..]; - stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| { - fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) }); - }; + stack_size = parseStackSize(z_arg["stack-size=".len..]); } else if (mem.startsWith(u8, z_arg, "common-page-size=")) { linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len); } else if (mem.startsWith(u8, z_arg, "max-page-size=")) { @@ -2285,10 +2281,7 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-u")) { try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {}); } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) { - const stack_size = linker_args_it.nextOrFatal(); - stack_size_override = std.fmt.parseUnsigned(u64, stack_size, 0) catch |err| { - fatal("unable to parse stack size override '{s}': {s}", .{ stack_size, @errorName(err) }); - }; + stack_size = parseStackSize(linker_args_it.nextOrFatal()); } else if (mem.eql(u8, arg, "--image-base")) { const image_base = linker_args_it.nextOrFatal(); image_base_override = std.fmt.parseUnsigned(u64, image_base, 0) catch |err| { @@ -3407,7 +3400,7 @@ fn buildOutputType( .linker_print_gc_sections = linker_print_gc_sections, .linker_print_icf_sections = linker_print_icf_sections, .linker_print_map = linker_print_map, - .linker_opt_bisect_limit = linker_opt_bisect_limit, + .llvm_opt_bisect_limit = llvm_opt_bisect_limit, .linker_global_base = linker_global_base, .linker_export_symbol_names = linker_export_symbol_names.items, .linker_z_nocopyreloc = linker_z_nocopyreloc, @@ -3430,7 +3423,7 @@ fn buildOutputType( .link_eh_frame_hdr = link_eh_frame_hdr, .link_emit_relocs = link_emit_relocs, .force_undefined_symbols = force_undefined_symbols, - .stack_size_override = stack_size_override, + .stack_size = stack_size, .image_base_override = image_base_override, .formatted_panics = formatted_panics, .function_sections = function_sections, @@ -3459,7 +3452,7 @@ fn buildOutputType( .test_runner_path = test_runner_path, .disable_lld_caching = !output_to_cache, .subsystem = subsystem, - .dwarf_format = dwarf_format, + .debug_format = debug_format, .debug_compile_errors = debug_compile_errors, .enable_link_snapshots = enable_link_snapshots, .install_name = install_name, @@ -7688,3 +7681,8 @@ fn resolveTargetQueryOrFatal(target_query: std.Target.Query) std.Target { return std.zig.system.resolveTargetQuery(target_query) catch |err| fatal("unable to resolve target: {s}", .{@errorName(err)}); } + +fn parseStackSize(s: []const u8) u64 { + return std.fmt.parseUnsigned(u64, s, 0) catch |err| + fatal("unable to parse stack size '{s}': {s}", .{ s, @errorName(err) }); +} diff --git a/src/musl.zig b/src/musl.zig index bbb3c145bb..47b8c8d6b5 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -226,7 +226,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr .is_native_abi = false, .self_exe_path = comp.self_exe_path, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, .verbose_cimport = comp.verbose_cimport, diff --git a/src/target.zig b/src/target.zig index f610e55fb0..04c25a5f0c 100644 --- a/src/target.zig +++ b/src/target.zig @@ -323,6 +323,14 @@ pub fn hasLlvmSupport(target: std.Target, ofmt: std.Target.ObjectFormat) bool { }; } +/// The set of targets that Zig supports using LLD to link for. +pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool { + return switch (ofmt) { + .elf, .coff, .wasm => true, + else => false, + }; +} + /// The set of targets that our own self-hosted backends have robust support for. /// Used to select between LLVM backend and self-hosted backend when compiling in /// debug mode. A given target should only return true here if it is passing greater -- cgit v1.2.3 From 9a48a5ab0784ae9744c72cfcc6d7ad9b2cea6a9c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Dec 2023 13:36:33 -0700 Subject: compiler: update references to single_threaded --- src/Compilation.zig | 10 ++++------ src/Compilation/Config.zig | 6 ++++-- src/arch/wasm/CodeGen.zig | 5 ++++- src/codegen.zig | 4 +++- src/codegen/llvm.zig | 15 +++++++++++---- src/libcxx.zig | 4 ++-- src/libunwind.zig | 2 +- src/link/MachO.zig | 33 ++++++++++++++++++++++----------- 8 files changed, 51 insertions(+), 28 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index b7cf3c5276..4d4eafba65 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1871,7 +1871,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { try comp.work_queue.writeItem(.libtsan); } - if (comp.getTarget().isMinGW() and !comp.bin_file.options.single_threaded) { + if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) { // LLD might drop some symbols as unused during LTO and GCing, therefore, // we force mark them for resolution here. @@ -2418,10 +2418,8 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.main_mod, .{ .files = man }); // Synchronize with other matching comments: ZigOnlyHashStuff - man.hash.add(comp.bin_file.options.valgrind); - man.hash.add(comp.bin_file.options.single_threaded); - man.hash.add(comp.bin_file.options.use_llvm); - man.hash.add(comp.bin_file.options.use_lib_llvm); + man.hash.add(comp.config.use_llvm); + man.hash.add(comp.config.use_lib_llvm); man.hash.add(comp.bin_file.options.dll_export_fns); man.hash.add(comp.bin_file.options.is_test); man.hash.add(comp.test_evented_io); @@ -4922,7 +4920,7 @@ pub fn addCCArgs( try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS"); try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS"); - if (comp.bin_file.options.single_threaded) { + if (!comp.config.any_non_single_threaded) { try argv.append("-D_LIBCPP_HAS_NO_THREADS"); } diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 33b9bab40b..0e379212cc 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -7,6 +7,8 @@ link_libc: bool, link_libcpp: bool, link_libunwind: bool, any_unwind_tables: bool, +any_c_source_files: bool, +any_non_single_threaded: bool, pie: bool, /// If this is true then linker code is responsible for making an LLVM IR /// Module, outputting it to an object file, and then linking that together @@ -31,7 +33,6 @@ shared_memory: bool, is_test: bool, test_evented_io: bool, entry: ?[]const u8, -any_c_source_files: bool, pub const CFrontend = enum { clang, aro }; @@ -374,6 +375,8 @@ pub fn resolve(options: Options) !Config { .link_libcpp = link_libcpp, .link_libunwind = link_libunwind, .any_unwind_tables = any_unwind_tables, + .any_c_source_files = options.any_c_source_files, + .any_non_single_threaded = options.any_non_single_threaded, .pie = pie, .lto = lto, .import_memory = import_memory, @@ -385,7 +388,6 @@ pub fn resolve(options: Options) !Config { .use_lld = use_lld, .entry = entry, .wasi_exec_model = wasi_exec_model, - .any_c_source_files = options.any_c_source_files, }; } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index aa6c2dea79..e0be273c26 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -7724,10 +7724,13 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { + const zcu = func.bin_file.base.comp.module.?; // Only when the atomic feature is enabled, and we're not building // for a single-threaded build, can we emit the `fence` instruction. // In all other cases, we emit no instructions for a fence. - if (func.useAtomicFeature() and !func.bin_file.base.options.single_threaded) { + const func_namespace = zcu.namespacePtr(zcu.declPtr(func.decl).namespace); + const single_threaded = func_namespace.file_scope.mod.single_threaded; + if (func.useAtomicFeature() and !single_threaded) { try func.addAtomicTag(.atomic_fence); } diff --git a/src/codegen.zig b/src/codegen.zig index b464a9f365..5efde3985c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -942,7 +942,9 @@ fn genDeclRef( try mod.markDeclAlive(decl); - const is_threadlocal = tv.val.isPtrToThreadLocal(mod) and !bin_file.options.single_threaded; + const decl_namespace = mod.namespacePtr(decl.namespace_index); + const single_threaded = decl_namespace.file_scope.mod.single_threaded; + const is_threadlocal = tv.val.isPtrToThreadLocal(mod) and !single_threaded; const is_extern = decl.isExtern(mod); if (bin_file.cast(link.File.Elf)) |elf_file| { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 57e5770d89..a072c6a069 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1591,8 +1591,10 @@ pub const Object = struct { var di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn = null; var di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn = null; + const namespace = mod.namespacePtr(decl.src_namespace); + if (o.di_builder) |dib| { - di_file = try o.getDIFile(gpa, mod.namespacePtr(decl.src_namespace).file_scope); + di_file = try o.getDIFile(gpa, namespace.file_scope); const line_number = decl.src_line + 1; const is_internal_linkage = decl.val.getExternFunc(mod) == null and @@ -1623,6 +1625,8 @@ pub const Object = struct { di_scope = subprogram.toScope(); } + const single_threaded = namespace.file_scope.mod.single_threaded; + var fg: FuncGen = .{ .gpa = gpa, .air = air, @@ -1634,7 +1638,7 @@ pub const Object = struct { .arg_index = 0, .func_inst_table = .{}, .blocks = .{}, - .sync_scope = if (mod.comp.bin_file.options.single_threaded) .singlethread else .system, + .sync_scope = if (single_threaded) .singlethread else .system, .di_scope = di_scope, .di_file = di_file, .base_line = dg.decl.src_line, @@ -1788,8 +1792,10 @@ pub const Object = struct { if (mod.wantDllExports()) global_index.setDllStorageClass(.default, &self.builder); global_index.setUnnamedAddr(.unnamed_addr, &self.builder); if (decl.val.getVariable(mod)) |decl_var| { + const decl_namespace = mod.namespacePtr(decl.namespace_index); + const single_threaded = decl_namespace.file_scope.mod.single_threaded; global_index.ptrConst(&self.builder).kind.variable.setThreadLocal( - if (decl_var.is_threadlocal and !mod.comp.bin_file.options.single_threaded) + if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default, @@ -3176,7 +3182,8 @@ pub const Object = struct { variable_index.setLinkage(.external, &o.builder); variable_index.setUnnamedAddr(.default, &o.builder); if (decl.val.getVariable(mod)) |decl_var| { - const single_threaded = mod.comp.bin_file.options.single_threaded; + const decl_namespace = mod.namespacePtr(decl.namespace_index); + const single_threaded = decl_namespace.file_scope.mod.single_threaded; variable_index.setThreadLocal( if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default, &o.builder, diff --git a/src/libcxx.zig b/src/libcxx.zig index 19c1d25b8c..8ae7db80f1 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -154,7 +154,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { continue; if (std.mem.startsWith(u8, cxx_src, "src/support/ibm/") and target.os.tag != .zos) continue; - if (comp.bin_file.options.single_threaded) { + if (!comp.config.any_non_single_threaded) { if (std.mem.startsWith(u8, cxx_src, "src/support/win32/thread_win32.cpp")) { continue; } @@ -332,7 +332,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { } // WASM targets are single threaded. - if (comp.bin_file.options.single_threaded) { + if (!comp.config.any_non_single_threaded) { if (std.mem.startsWith(u8, cxxabi_src, "src/cxa_thread_atexit.cpp")) { continue; } diff --git a/src/libunwind.zig b/src/libunwind.zig index f0330a4e51..876bd7a31f 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -67,7 +67,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { if (comp.bin_file.options.optimize_mode == .Debug) { try cflags.append("-D_DEBUG"); } - if (comp.bin_file.options.single_threaded) { + if (!comp.config.any_non_single_threaded) { try cflags.append("-D_LIBUNWIND_HAS_NO_THREADS"); } if (target.cpu.arch.isARM() and target.abi.floatAbi() == .hard) { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index c1d7eef652..3da076ba56 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -267,7 +267,10 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { }); try self.strtab.buffer.append(gpa, 0); - try self.populateMissingMetadata(); + try self.populateMissingMetadata(.{ + .symbol_count_hint = options.symbol_count_hint, + .program_code_size_hint = options.program_code_size_hint, + }); if (self.d_sym) |*d_sym| { try d_sym.populateMissingMetadata(self); @@ -1704,7 +1707,8 @@ pub fn createDsoHandleSymbol(self: *MachO) !void { } pub fn resolveSymbols(self: *MachO) !void { - const output_mode = self.base.comp.config.output_mode; + const comp = self.base.comp; + const output_mode = comp.config.output_mode; // We add the specified entrypoint as the first unresolved symbols so that // we search for it in libraries should there be no object files specified // on the linker line. @@ -1729,7 +1733,7 @@ pub fn resolveSymbols(self: *MachO) !void { if (self.unresolved.count() > 0 and self.dyld_stub_binder_index == null) { self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .{ .add_got = true }); } - if (!self.base.options.single_threaded and self.mode == .incremental) { + if (comp.config.any_non_single_threaded and self.mode == .incremental) { _ = try self.addUndefined("__tlv_bootstrap", .{}); } @@ -2436,7 +2440,8 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex) const tracy = trace(@src()); defer tracy.end(); - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; const decl = mod.declPtr(decl_index); if (decl.val.getExternFunc(mod)) |_| { @@ -2453,7 +2458,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex) } const is_threadlocal = if (decl.val.getVariable(mod)) |variable| - variable.is_threadlocal and !self.base.options.single_threaded + variable.is_threadlocal and comp.config.any_non_single_threaded else false; if (is_threadlocal) return self.updateThreadlocalVariable(mod, decl_index); @@ -3129,11 +3134,17 @@ pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: li return 0; } -fn populateMissingMetadata(self: *MachO) !void { +const PopulateMissingMetadataOptions = struct { + symbol_count_hint: u64, + program_code_size_hint: u64, +}; + +fn populateMissingMetadata(self: *MachO, options: PopulateMissingMetadataOptions) !void { assert(self.mode == .incremental); - const gpa = self.base.comp.gpa; - const target = self.base.comp.root_mod.resolved_target.result; + const comp = self.base.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; const pagezero_vmsize = self.calcPagezeroSize(); @@ -3171,7 +3182,7 @@ fn populateMissingMetadata(self: *MachO) !void { if (self.text_section_index == null) { // Sadly, segments need unique string identfiers for some reason. self.text_section_index = try self.allocateSection("__TEXT1", "__text", .{ - .size = self.base.options.program_code_size_hint, + .size = options.program_code_size_hint, .alignment = switch (cpu_arch) { .x86_64 => 1, .aarch64 => @sizeOf(u32), @@ -3207,7 +3218,7 @@ fn populateMissingMetadata(self: *MachO) !void { if (self.got_section_index == null) { self.got_section_index = try self.allocateSection("__DATA_CONST", "__got", .{ - .size = @sizeOf(u64) * self.base.options.symbol_count_hint, + .size = @sizeOf(u64) * options.symbol_count_hint, .alignment = @alignOf(u64), .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, .prot = macho.PROT.READ | macho.PROT.WRITE, @@ -3245,7 +3256,7 @@ fn populateMissingMetadata(self: *MachO) !void { self.segment_table_dirty = true; } - if (!self.base.options.single_threaded) { + if (comp.config.any_non_single_threaded) { if (self.thread_vars_section_index == null) { self.thread_vars_section_index = try self.allocateSection("__DATA2", "__thread_vars", .{ .size = @sizeOf(u64) * 3, -- cgit v1.2.3 From 0789e91eeb08495c5084067df2b2dab410197364 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Dec 2023 16:25:28 -0700 Subject: linkers: update references to "options" field --- src/Compilation.zig | 91 ++++++----- src/Compilation/Config.zig | 2 +- src/Sema.zig | 27 ++-- src/codegen/llvm.zig | 4 +- src/libtsan.zig | 2 +- src/link.zig | 3 +- src/link/Coff/lld.zig | 94 ++++++------ src/link/Dwarf.zig | 10 +- src/link/Elf.zig | 295 ++++++++++++++++++------------------ src/link/Elf/Atom.zig | 13 +- src/link/Elf/Object.zig | 2 +- src/link/Elf/ZigObject.zig | 2 +- src/link/Elf/synthetic_sections.zig | 24 +-- src/link/MachO.zig | 36 +++-- src/link/MachO/DebugSymbols.zig | 7 +- src/link/MachO/dead_strip.zig | 2 +- src/link/MachO/load_commands.zig | 34 ++--- src/link/MachO/zld.zig | 9 +- src/link/NvPtx.zig | 3 +- src/link/Plan9.zig | 32 ++-- src/link/SpirV.zig | 3 +- src/link/Wasm.zig | 245 ++++++++++++++++++------------ 22 files changed, 511 insertions(+), 429 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 2859090edc..cedbf5024f 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -76,6 +76,7 @@ framework_dirs: []const []const u8, system_libs: std.StringArrayHashMapUnmanaged(SystemLib), version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, +skip_linker_dependencies: bool, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = @@ -940,7 +941,7 @@ pub const InitOptions = struct { /// * getpid /// * mman /// * signal - wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{}, + wasi_emulated_libs: []const wasi_libc.CRTFile = &.{}, /// This means that if the output mode is an executable it will be a /// Position Independent Executable. If the output mode is not an /// executable this field is ignored. @@ -1238,7 +1239,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const sysroot = options.sysroot orelse libc_dirs.sysroot; const include_compiler_rt = options.want_compiler_rt orelse - (!options.skip_linker_dependencies and is_exe_or_dyn_lib); + (!comp.skip_linker_dependencies and is_exe_or_dyn_lib); if (include_compiler_rt and output_mode == .Obj) { // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");` @@ -1639,6 +1640,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .objects = options.link_objects, .framework_dirs = options.framework_dirs, .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, + .skip_linker_dependencies = options.skip_linker_dependencies, }; if (bin_file_emit) |emit| { @@ -1695,7 +1697,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .soname = options.soname, .compatibility_version = options.compatibility_version, .dll_export_fns = dll_export_fns, - .skip_linker_dependencies = options.skip_linker_dependencies, .parent_compilation_link_libc = options.parent_compilation_link_libc, .each_lib_rpath = each_lib_rpath, .build_id = build_id, @@ -1765,9 +1766,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; + const have_bin_emit = comp.bin_file != null or comp.whole_bin_sub_path != null; - if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) { + if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) { if (target.isDarwin()) { switch (target.abi) { .none, @@ -1808,27 +1809,34 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .{ .musl_crt_file = .crt1_o }, .{ .musl_crt_file = .scrt1_o }, .{ .musl_crt_file = .rcrt1_o }, - switch (comp.bin_file.options.link_mode) { + switch (comp.config.link_mode) { .Static => .{ .musl_crt_file = .libc_a }, .Dynamic => .{ .musl_crt_file = .libc_so }, }, }); } - if (comp.wantBuildWasiLibcFromSource()) { - if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; - const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; - try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components - for (wasi_emulated_libs) |crt_file| { - comp.work_queue.writeItemAssumeCapacity(.{ - .wasi_libc_crt_file = crt_file, - }); + if (comp.bin_file) |lf| { + if (lf.cast(link.File.Wasm)) |wasm| { + if (comp.wantBuildWasiLibcFromSource()) { + if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; + + // worst-case we need all components + try comp.work_queue.ensureUnusedCapacity(wasm.wasi_emulated_libs.len + 2); + + for (wasm.wasi_emulated_libs) |crt_file| { + comp.work_queue.writeItemAssumeCapacity(.{ + .wasi_libc_crt_file = crt_file, + }); + } + comp.work_queue.writeAssumeCapacity(&[_]Job{ + .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) }, + .{ .wasi_libc_crt_file = .libc_a }, + }); + } } - comp.work_queue.writeAssumeCapacity(&[_]Job{ - .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) }, - .{ .wasi_libc_crt_file = .libc_a }, - }); } + if (comp.wantBuildMinGWFromSource()) { if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; @@ -1863,27 +1871,29 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { if (comp.wantBuildLibUnwindFromSource()) { try comp.work_queue.writeItem(.{ .libunwind = {} }); } - if (build_options.have_llvm and is_exe_or_dyn_lib and comp.bin_file.options.link_libcpp) { + if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { try comp.work_queue.writeItem(.libcxx); try comp.work_queue.writeItem(.libcxxabi); } - if (build_options.have_llvm and comp.bin_file.options.tsan) { + if (build_options.have_llvm and comp.config.any_sanitize_thread) { try comp.work_queue.writeItem(.libtsan); } - if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) { - // LLD might drop some symbols as unused during LTO and GCing, therefore, - // we force mark them for resolution here. + if (comp.bin_file) |lf| { + if (comp.getTarget().isMinGW() and comp.config.any_non_single_threaded) { + // LLD might drop some symbols as unused during LTO and GCing, therefore, + // we force mark them for resolution here. - const tls_index_sym = switch (comp.getTarget().cpu.arch) { - .x86 => "__tls_index", - else => "_tls_index", - }; + const tls_index_sym = switch (comp.getTarget().cpu.arch) { + .x86 => "__tls_index", + else => "_tls_index", + }; - try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, tls_index_sym, {}); + try lf.force_undefined_symbols.put(comp.gpa, tls_index_sym, {}); + } } - if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { + if (comp.include_compiler_rt and capable_of_building_compiler_rt) { if (is_exe_or_dyn_lib) { log.debug("queuing a job to build compiler_rt_lib", .{}); comp.job_queued_compiler_rt_lib = true; @@ -1895,8 +1905,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - if (!comp.bin_file.options.skip_linker_dependencies and is_exe_or_dyn_lib and - !comp.bin_file.options.link_libc and capable_of_building_zig_libc) + if (!comp.skip_linker_dependencies and is_exe_or_dyn_lib and + !comp.config.link_libc and capable_of_building_zig_libc) { try comp.work_queue.writeItem(.{ .zig_libc = {} }); } @@ -2425,7 +2435,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.test_evented_io); man.hash.addOptionalBytes(comp.test_filter); man.hash.addOptionalBytes(comp.test_name_prefix); - man.hash.add(comp.bin_file.options.skip_linker_dependencies); + man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.formatted_panics); man.hash.add(mod.emit_h != null); man.hash.add(mod.error_limit); @@ -2477,7 +2487,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); man.hash.add(comp.bin_file.options.each_lib_rpath); man.hash.add(comp.bin_file.build_id); - man.hash.add(comp.bin_file.options.skip_linker_dependencies); + man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.bin_file.options.z_nodelete); man.hash.add(comp.bin_file.options.z_notext); man.hash.add(comp.bin_file.options.z_defs); @@ -2489,7 +2499,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.bin_file.options.z_max_page_size orelse 0); man.hash.add(comp.bin_file.options.hash_style); man.hash.add(comp.bin_file.options.compress_debug_sections); - man.hash.add(comp.bin_file.options.include_compiler_rt); + man.hash.add(comp.include_compiler_rt); man.hash.add(comp.bin_file.options.sort_section); if (comp.config.link_libc) { man.hash.add(comp.bin_file.options.libc_installation != null); @@ -3836,7 +3846,7 @@ pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { // Also nothing that applies only to compiling .zig code. man.hash.add(comp.sanitize_c); man.hash.addListOfBytes(comp.clang_argv); - man.hash.add(comp.bin_file.options.link_libcpp); + man.hash.add(comp.config.link_libcpp); // When libc_installation is null it means that Zig generated this dir list // based on the zig library directory alone. The zig lib directory file @@ -4909,7 +4919,7 @@ pub fn addCCArgs( try argv.append("-fno-builtin"); } - if (comp.bin_file.options.link_libcpp) { + if (comp.config.link_libcpp) { const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "libcxx", "include", }); @@ -4954,7 +4964,7 @@ pub fn addCCArgs( try argv.append(libunwind_include_path); } - if (comp.bin_file.options.link_libc and target.isGnuLibC()) { + if (comp.config.link_libc and target.isGnuLibC()) { const target_version = target.os.version_range.linux.glibc; const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ target_version.minor, @@ -5944,7 +5954,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool { .Lib => comp.bin_file.options.link_mode == .Dynamic, .Exe => true, }; - return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and + return comp.config.link_libc and is_exe_or_dyn_lib and comp.bin_file.options.libc_installation == null and comp.bin_file.options.target.ofmt != .c; } @@ -6164,6 +6174,7 @@ fn buildOutputFromZig( .have_zcu = true, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .link_libc = comp.config.link_libc, }); const root_mod = Package.Module.create(.{ @@ -6224,7 +6235,6 @@ fn buildOutputFromZig( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .link_libc = comp.bin_file.options.link_libc, .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); @@ -6305,7 +6315,6 @@ pub fn build_crt_file( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .link_libc = comp.bin_file.options.link_libc, .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); @@ -6327,7 +6336,7 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { // This can happen when the user uses `build-exe foo.obj -lkernel32` and // then when we create a sub-Compilation for zig libc, it also tries to // build kernel32.lib. - if (comp.bin_file.options.skip_linker_dependencies) return; + if (comp.skip_linker_dependencies) return; // This happens when an `extern "foo"` function is referenced. // If we haven't seen this library yet and we're targeting Windows, we need diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 0e379212cc..aba21e4bfe 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -335,7 +335,7 @@ pub fn resolve(options: Options) !Config { break :b .Static; }; - const import_memory = options.import_memory orelse false; + const import_memory = options.import_memory orelse (options.output_mode == .Obj); const export_memory = b: { if (link_mode == .Dynamic) { if (options.export_memory == true) return error.ExportMemoryAndDynamicIncompatible; diff --git a/src/Sema.zig b/src/Sema.zig index 9d1f65584e..910b1cca47 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5742,7 +5742,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr const msg = try sema.errMsg(&child_block, src, "C import failed", .{}); errdefer msg.destroy(gpa); - if (!comp.bin_file.options.link_libc) + if (!comp.config.link_libc) try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); const gop = try mod.cimport_errors.getOrPut(gpa, sema.owner_decl_index); @@ -9058,7 +9058,7 @@ fn resolveGenericBody( /// Given a library name, examines if the library name should end up in /// `link.File.Options.system_libs` table (for example, libc is always -/// specified via dedicated flag `link.File.Options.link_libc` instead), +/// specified via dedicated flag `link_libc` instead), /// and puts it there if it doesn't exist. /// It also dupes the library name which can then be saved as part of the /// respective `Decl` (either `ExternFn` or `Var`). @@ -9076,7 +9076,7 @@ fn handleExternLibName( const target = mod.getTarget(); log.debug("extern fn symbol expected in lib '{s}'", .{lib_name}); if (target.is_libc_lib_name(lib_name)) { - if (!comp.bin_file.options.link_libc) { + if (!comp.config.link_libc) { return sema.fail( block, src_loc, @@ -9087,18 +9087,21 @@ fn handleExternLibName( break :blk; } if (target.is_libcpp_lib_name(lib_name)) { - if (!comp.bin_file.options.link_libcpp) { - return sema.fail( - block, - src_loc, - "dependency on libc++ must be explicitly specified in the build command", - .{}, - ); - } + if (!comp.config.link_libcpp) return sema.fail( + block, + src_loc, + "dependency on libc++ must be explicitly specified in the build command", + .{}, + ); break :blk; } if (mem.eql(u8, lib_name, "unwind")) { - comp.bin_file.options.link_libunwind = true; + if (!comp.config.link_libunwind) return sema.fail( + block, + src_loc, + "dependency on libunwind must be explicitly specified in the build command", + .{}, + ); break :blk; } if (!target.isWasm() and !comp.bin_file.options.pic) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a072c6a069..522da0f8c9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3083,9 +3083,7 @@ pub const Object = struct { if (comp.unwind_tables) { try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); } - if (comp.bin_file.options.skip_linker_dependencies or - comp.bin_file.options.no_builtin) - { + if (comp.skip_linker_dependencies or comp.bin_file.options.no_builtin) { // The intent here is for compiler-rt and libc functions to not generate // infinite recursion. For example, if we are compiling the memcpy function, // and llvm detects that the body is equivalent to memcpy, it may replace the diff --git a/src/libtsan.zig b/src/libtsan.zig index 2489eb21af..d0af65e4c6 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -119,7 +119,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { }); } - const to_c_or_not_to_c_sources = if (comp.bin_file.options.link_libc) + const to_c_or_not_to_c_sources = if (comp.config.link_libc) &sanitizer_libcdep_sources else &sanitizer_nolibc_sources; diff --git a/src/link.zig b/src/link.zig index 95a3282186..612c05f82b 100644 --- a/src/link.zig +++ b/src/link.zig @@ -133,7 +133,6 @@ pub const File = struct { export_symbol_names: []const []const u8, global_base: ?u64, dll_export_fns: bool, - skip_linker_dependencies: bool, parent_compilation_link_libc: bool, each_lib_rpath: bool, build_id: std.zig.BuildId, @@ -1099,7 +1098,7 @@ pub const File = struct { } pub fn isStatic(self: File) bool { - return self.base.comp.config.link_mode == .Static; + return self.comp.config.link_mode == .Static; } pub fn isObject(self: File) bool { diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index a321d28fb3..1719d5fa67 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -48,7 +48,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const is_lib = self.base.comp.config.output_mode == .Lib; const is_dyn_lib = self.base.comp.config.link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or self.base.comp.config.output_mode == .Exe; - const link_in_crt = self.base.options.link_libc and is_exe_or_dyn_lib; + const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib; const target = self.base.comp.root_mod.resolved_target.result; const optimize_mode = self.base.comp.root_mod.optimize_mode; @@ -56,17 +56,17 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; - defer if (!self.base.options.disable_lld_caching) man.deinit(); + defer if (!self.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { man = comp.cache_parent.obtain(); self.base.releaseLock(); comptime assert(Compilation.link_hash_implementation_version == 10); - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); } @@ -79,12 +79,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } try man.addOptionalFile(module_obj_path); - man.hash.addOptionalBytes(self.base.options.entry); + man.hash.addOptionalBytes(comp.config.entry); man.hash.add(self.base.stack_size); man.hash.addOptional(self.image_base); - man.hash.addListOfBytes(self.base.options.lib_dirs); - man.hash.add(self.base.options.skip_linker_dependencies); - if (self.base.options.link_libc) { + man.hash.addListOfBytes(self.lib_dirs); + man.hash.add(comp.skip_linker_dependencies); + if (comp.config.link_libc) { man.hash.add(self.base.comp.libc_installation != null); if (self.base.comp.libc_installation) |libc_installation| { man.hash.addBytes(libc_installation.crt_dir.?); @@ -95,18 +95,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } try link.hashAddSystemLibs(&man, self.base.comp.system_libs); - man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys()); - man.hash.addOptional(self.base.options.subsystem); - man.hash.add(self.base.options.is_test); - man.hash.add(self.base.options.tsaware); - man.hash.add(self.base.options.nxcompat); - man.hash.add(self.base.options.dynamicbase); + man.hash.addListOfBytes(self.base.force_undefined_symbols.keys()); + man.hash.addOptional(self.subsystem); + man.hash.add(comp.config.is_test); + man.hash.add(self.tsaware); + man.hash.add(self.nxcompat); + man.hash.add(self.dynamicbase); man.hash.addOptional(self.base.allow_shlib_undefined); // strip does not need to go into the linker hash because it is part of the hash namespace - man.hash.addOptional(self.base.options.major_subsystem_version); - man.hash.addOptional(self.base.options.minor_subsystem_version); - man.hash.addOptional(self.base.options.version); - try man.addOptionalFile(self.base.options.module_definition_file); + man.hash.addOptional(self.major_subsystem_version); + man.hash.addOptional(self.minor_subsystem_version); + man.hash.addOptional(comp.version); + try man.addOptionalFile(self.module_definition_file); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -141,8 +141,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { - if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0].path; + if (comp.objects.len != 0) + break :blk comp.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -171,21 +171,21 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append("-ERRORLIMIT:0"); try argv.append("-NOLOGO"); - if (!self.base.options.strip) { + if (self.base.debug_format != .strip) { try argv.append("-DEBUG"); const out_ext = std.fs.path.extension(full_out_path); - const out_pdb = self.base.options.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ + const out_pdb = self.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ full_out_path[0 .. full_out_path.len - out_ext.len], }); try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb})); } - if (self.base.options.version) |version| { + if (comp.version) |version| { try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); } - if (self.base.options.lto) { + if (comp.config.lto) { switch (optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-OPT:lldlto=2"), @@ -209,7 +209,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } - for (self.base.options.force_undefined_symbols.keys()) |symbol| { + for (self.base.force_undefined_symbols.keys()) |symbol| { try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol})); } @@ -217,17 +217,17 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append("-DLL"); } - if (self.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{entry})); } - if (self.base.options.tsaware) { + if (self.tsaware) { try argv.append("-tsaware"); } - if (self.base.options.nxcompat) { + if (self.nxcompat) { try argv.append("-nxcompat"); } - if (!self.base.options.dynamicbase) { + if (!self.dynamicbase) { try argv.append("-dynamicbase:NO"); } if (self.base.allow_shlib_undefined) { @@ -236,12 +236,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); - if (self.base.options.implib_emit) |emit| { + if (self.implib_emit) |emit| { const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path}); try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path})); } - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation) |libc_installation| { try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?})); @@ -252,12 +252,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } - for (self.base.options.lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_dir})); } - try argv.ensureUnusedCapacity(self.base.options.objects.len); - for (self.base.options.objects) |obj| { + try argv.ensureUnusedCapacity(comp.objects.len); + for (comp.objects) |obj| { if (obj.must_link) { argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{s}", .{obj.path})); } else { @@ -279,18 +279,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(p); } - if (self.base.options.module_definition_file) |def| { + if (self.module_definition_file) |def| { try argv.append(try allocPrint(arena, "-DEF:{s}", .{def})); } const resolved_subsystem: ?std.Target.SubSystem = blk: { - if (self.base.options.subsystem) |explicit| break :blk explicit; + if (self.subsystem) |explicit| break :blk explicit; switch (target.os.tag) { .windows => { if (self.base.comp.module) |module| { if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib) break :blk null; - if (module.stage1_flags.have_c_main or self.base.options.is_test or + if (module.stage1_flags.have_c_main or comp.config.is_test or module.stage1_flags.have_winmain_crt_startup or module.stage1_flags.have_wwinmain_crt_startup) { @@ -310,8 +310,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const mode: Mode = mode: { if (resolved_subsystem) |subsystem| { const subsystem_suffix = ss: { - if (self.base.options.major_subsystem_version) |major| { - if (self.base.options.minor_subsystem_version) |minor| { + if (self.major_subsystem_version) |major| { + if (self.minor_subsystem_version) |minor| { break :ss try allocPrint(arena, ",{d}.{d}", .{ major, minor }); } else { break :ss try allocPrint(arena, ",{d}", .{major}); @@ -447,7 +447,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } else { try argv.append("-NODEFAULTLIB"); - if (!is_lib and self.base.options.entry == null) { + if (!is_lib and comp.config.entry == null) { if (self.base.comp.module) |module| { if (module.stage1_flags.have_winmain_crt_startup) { try argv.append("-ENTRY:WinMainCRTStartup"); @@ -463,18 +463,18 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } // libc++ dep - if (self.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } // libunwind dep - if (self.base.options.link_libunwind) { + if (comp.config.link_libunwind) { try argv.append(comp.libunwind_static_lib.?.full_object_path); } - if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) { - if (!self.base.options.link_libc) { + if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) { + if (!comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try argv.append(lib.full_object_path); } @@ -492,13 +492,13 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod argv.appendAssumeCapacity(crt_file.full_object_path); continue; } - if (try findLib(arena, lib_basename, self.base.options.lib_dirs)) |full_path| { + if (try findLib(arena, lib_basename, self.lib_dirs)) |full_path| { argv.appendAssumeCapacity(full_path); continue; } if (target.abi.isGnu()) { const fallback_name = try allocPrint(arena, "lib{s}.dll.a", .{key}); - if (try findLib(arena, fallback_name, self.base.options.lib_dirs)) |full_path| { + if (try findLib(arena, fallback_name, self.lib_dirs)) |full_path| { argv.appendAssumeCapacity(full_path); continue; } @@ -582,7 +582,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index ef803a45f1..5bd65b2227 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1022,16 +1022,18 @@ const min_nop_size = 2; /// actual_capacity + (actual_capacity / ideal_factor) const ideal_factor = 3; -pub fn init(allocator: Allocator, bin_file: *File, format: Format) Dwarf { - const target = &bin_file.options.target; +pub fn init(lf: *File, format: Format) Dwarf { + const comp = lf.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 0...32 => .p32, 33...64 => .p64, else => unreachable, }; return .{ - .allocator = allocator, - .bin_file = bin_file, + .allocator = gpa, + .bin_file = lf, .format = format, .ptr_width = ptr_width, .dbg_line_header = switch (target.cpu.arch) { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index df83878494..a116c46d2f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1,5 +1,6 @@ base: link.File, image_base: u64, +rdynamic: bool, ptr_width: PtrWidth, @@ -358,19 +359,21 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, .function_sections = options.function_sections, .data_sections = options.data_sections, - - .image_base = b: { - if (is_dyn_lib) break :b 0; - if (output_mode == .Exe and comp.config.pie) return 0; - return options.image_base orelse switch (ptr_width) { - .p32 => 0x1000, - .p64 => 0x1000000, - }; - }, }, .ptr_width = ptr_width, .page_size = page_size, .default_sym_version = default_sym_version, + + .image_base = b: { + if (is_dyn_lib) break :b 0; + if (output_mode == .Exe and comp.config.pie) break :b 0; + break :b options.image_base orelse switch (ptr_width) { + .p32 => 0x1000, + .p64 => 0x1000000, + }; + }, + + .rdynamic = options.rdynamic, }; if (use_llvm and comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, options); @@ -1006,7 +1009,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node break :blk path; } } else null; - const gc_sections = self.base.gc_sections; // --verbose-link if (self.base.comp.verbose_link) try self.dumpArgv(comp); @@ -1047,14 +1049,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node var rpath_table = std.StringArrayHashMap(void).init(gpa); defer rpath_table.deinit(); - for (self.base.options.rpath_list) |rpath| { + for (self.base.rpath_list) |rpath| { _ = try rpath_table.put(rpath, {}); } - if (self.base.options.each_lib_rpath) { + if (self.each_lib_rpath) { var test_path = std.ArrayList(u8).init(gpa); defer test_path.deinit(); - for (self.base.options.lib_dirs) |lib_dir_path| { + for (self.lib_dirs) |lib_dir_path| { for (self.base.comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; @@ -1076,9 +1078,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } // libc - if (!self.base.options.skip_linker_dependencies and - !self.base.options.link_libc) - { + if (!comp.skip_linker_dependencies and !comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try positionals.append(.{ .path = lib.full_object_path }); } @@ -1263,10 +1263,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node self.entry_index = if (entry) |name| self.globalByName(name) else null; } - if (gc_sections) { + if (self.base.gc_sections) { try gc.gcAtoms(self); - if (self.base.options.print_gc_sections) { + if (self.base.print_gc_sections) { try gc.dumpPrunedAtoms(self); } } @@ -1347,13 +1347,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { - const gpa = self.base.comp.gpa; + const gpa = comp.gpa; var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); defer positionals.deinit(); - try positionals.ensureUnusedCapacity(self.base.options.objects.len); - positionals.appendSliceAssumeCapacity(self.base.options.objects); + try positionals.ensureUnusedCapacity(comp.objects.len); + positionals.appendSliceAssumeCapacity(comp.objects); // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up @@ -1495,8 +1495,8 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); defer positionals.deinit(); - try positionals.ensureUnusedCapacity(self.base.options.objects.len); - positionals.appendSliceAssumeCapacity(self.base.options.objects); + try positionals.ensureUnusedCapacity(comp.objects.len); + positionals.appendSliceAssumeCapacity(comp.objects); // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up @@ -1606,7 +1606,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append(full_out_path); if (self.base.isRelocatable()) { - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { try argv.append(obj.path); } @@ -1626,28 +1626,28 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } if (self.base.isDynLib()) { - if (self.base.options.soname) |name| { + if (self.soname) |name| { try argv.append("-soname"); try argv.append(name); } } - if (self.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("--entry"); try argv.append(entry); } - for (self.base.options.rpath_list) |rpath| { + for (self.base.rpath_list) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } - if (self.base.options.each_lib_rpath) { - for (self.base.options.lib_dirs) |lib_dir_path| { + if (self.each_lib_rpath) { + for (self.lib_dirs) |lib_dir_path| { try argv.append("-rpath"); try argv.append(lib_dir_path); } - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (Compilation.classifyFileExt(obj.path) == .shared_library) { const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; if (obj.loption) continue; @@ -1669,29 +1669,29 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("--gc-sections"); } - if (self.base.options.print_gc_sections) { + if (self.base.print_gc_sections) { try argv.append("--print-gc-sections"); } - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { try argv.append("--eh-frame-hdr"); } - if (self.base.options.rdynamic) { + if (self.rdynamic) { try argv.append("--export-dynamic"); } - if (self.base.options.z_notext) { + if (self.z_notext) { try argv.append("-z"); try argv.append("notext"); } - if (self.base.options.z_nocopyreloc) { + if (self.z_nocopyreloc) { try argv.append("-z"); try argv.append("nocopyreloc"); } - if (self.base.options.z_now) { + if (self.z_now) { try argv.append("-z"); try argv.append("now"); } @@ -1702,11 +1702,11 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("-shared"); } - if (self.base.options.pie and self.base.isExe()) { + if (comp.config.pie and self.base.isExe()) { try argv.append("-pie"); } - if (self.base.options.strip) { + if (self.base.debug_format == .strip) { try argv.append("-s"); } @@ -1715,12 +1715,12 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { if (csu.crti) |v| try argv.append(v); if (csu.crtbegin) |v| try argv.append(v); - for (self.base.options.lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { try argv.append("-L"); try argv.append(lib_dir); } - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation) |libc_installation| { try argv.append("-L"); try argv.append(libc_installation.crt_dir.?); @@ -1728,7 +1728,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } var whole_archive = false; - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (obj.must_link and !whole_archive) { try argv.append("-whole-archive"); whole_archive = true; @@ -1756,15 +1756,12 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append(p); } - // TSAN - if (self.base.options.tsan) { + if (comp.config.any_sanitize_thread) { try argv.append(comp.tsan_static_lib.?.full_object_path); } // libc - if (!self.base.options.skip_linker_dependencies and - !self.base.options.link_libc) - { + if (!comp.skip_linker_dependencies and !comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try argv.append(lib.full_object_path); } @@ -1799,18 +1796,18 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { } // libc++ dep - if (self.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } // libunwind dep - if (self.base.options.link_libunwind) { + if (comp.config.link_libunwind) { try argv.append(comp.libunwind_static_lib.?.full_object_path); } // libc dep - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation != null) { const needs_grouping = link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); @@ -1963,8 +1960,6 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { defer script.deinit(gpa); try script.parse(data, self); - const lib_dirs = self.base.options.lib_dirs; - var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); @@ -1981,7 +1976,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { // TODO I think technically we should re-use the mechanism used by the frontend here. // Maybe we should hoist search-strategy all the way here? - for (lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { if (!self.isStatic()) { if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Dynamic)) break :success; @@ -1998,7 +1993,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { } else |_| {} try checked_paths.append(try gpa.dupe(u8, scr_obj.path)); - for (lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, scr_obj.path, null)) break :success; } @@ -2338,7 +2333,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const link_mode = self.base.comp.config.link_mode; const is_dyn_lib = link_mode == .Dynamic and is_lib; const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; - const have_dynamic_linker = self.base.options.link_libc and + const have_dynamic_linker = comp.config.link_libc and link_mode == .Dynamic and is_exe_or_dyn_lib; const target = self.base.comp.root_mod.resolved_target.result; const compiler_rt_path: ?[]const u8 = blk: { @@ -2358,11 +2353,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; - defer if (!self.base.options.disable_lld_caching) man.deinit(); + defer if (!self.base.disable_lld_caching) man.deinit(); var digest: [Cache.hex_digest_len]u8 = undefined; - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { man = comp.cache_parent.obtain(); // We are about to obtain this lock, so here we give other processes a chance first. @@ -2370,9 +2365,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v comptime assert(Compilation.link_hash_implementation_version == 10); - try man.addOptionalFile(self.base.options.linker_script); - try man.addOptionalFile(self.base.options.version_script); - for (self.base.options.objects) |obj| { + try man.addOptionalFile(self.linker_script); + try man.addOptionalFile(self.version_script); + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); man.hash.add(obj.loption); @@ -2385,34 +2380,34 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // We can skip hashing libc and libc++ components that we are in charge of building from Zig // installation sources because they are always a product of the compiler version + target information. - man.hash.addOptionalBytes(self.base.options.entry); + man.hash.addOptionalBytes(comp.config.entry); man.hash.addOptional(self.image_base); man.hash.add(self.base.gc_sections); - man.hash.addOptional(self.base.options.sort_section); - man.hash.add(self.base.options.eh_frame_hdr); - man.hash.add(self.base.options.emit_relocs); - man.hash.add(self.base.options.rdynamic); - man.hash.addListOfBytes(self.base.options.lib_dirs); - man.hash.addListOfBytes(self.base.options.rpath_list); - man.hash.add(self.base.options.each_lib_rpath); + man.hash.addOptional(self.sort_section); + man.hash.add(self.eh_frame_hdr); + man.hash.add(self.emit_relocs); + man.hash.add(self.rdynamic); + man.hash.addListOfBytes(self.lib_dirs); + man.hash.addListOfBytes(self.base.rpath_list); + man.hash.add(self.each_lib_rpath); if (output_mode == .Exe) { man.hash.add(self.base.stack_size); man.hash.add(self.base.build_id); } - man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys()); - man.hash.add(self.base.options.skip_linker_dependencies); - man.hash.add(self.base.options.z_nodelete); - man.hash.add(self.base.options.z_notext); - man.hash.add(self.base.options.z_defs); - man.hash.add(self.base.options.z_origin); - man.hash.add(self.base.options.z_nocopyreloc); - man.hash.add(self.base.options.z_now); - man.hash.add(self.base.options.z_relro); - man.hash.add(self.base.options.z_common_page_size orelse 0); - man.hash.add(self.base.options.z_max_page_size orelse 0); - man.hash.add(self.base.options.hash_style); + man.hash.addListOfBytes(self.symbol_wrap_set.keys()); + man.hash.add(comp.skip_linker_dependencies); + man.hash.add(self.z_nodelete); + man.hash.add(self.z_notext); + man.hash.add(self.z_defs); + man.hash.add(self.z_origin); + man.hash.add(self.z_nocopyreloc); + man.hash.add(self.z_now); + man.hash.add(self.z_relro); + man.hash.add(self.z_common_page_size orelse 0); + man.hash.add(self.z_max_page_size orelse 0); + man.hash.add(self.hash_style); // strip does not need to go into the linker hash because it is part of the hash namespace - if (self.base.options.link_libc) { + if (comp.config.link_libc) { man.hash.add(self.base.comp.libc_installation != null); if (self.base.comp.libc_installation) |libc_installation| { man.hash.addBytes(libc_installation.crt_dir.?); @@ -2421,16 +2416,16 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.addOptionalBytes(target.dynamic_linker.get()); } } - man.hash.addOptionalBytes(self.base.options.soname); - man.hash.addOptional(self.base.options.version); + man.hash.addOptionalBytes(self.soname); + man.hash.addOptional(comp.version); try link.hashAddSystemLibs(&man, self.base.comp.system_libs); - man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys()); + man.hash.addListOfBytes(self.base.force_undefined_symbols.keys()); man.hash.add(self.base.allow_shlib_undefined); - man.hash.add(self.base.options.bind_global_refs_locally); - man.hash.add(self.base.options.compress_debug_sections); - man.hash.add(self.base.options.tsan); - man.hash.addOptionalBytes(self.base.options.sysroot); - man.hash.add(self.base.options.linker_optimization); + man.hash.add(self.bind_global_refs_locally); + man.hash.add(self.compress_debug_sections); + man.hash.add(comp.config.any_sanitize_thread); + man.hash.addOptionalBytes(self.sysroot); + man.hash.add(self.optimization); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -2466,14 +2461,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails // before even generating the relocatable. if (output_mode == .Obj and - (self.base.options.lto or target.isBpfFreestanding())) + (comp.config.lto or target.isBpfFreestanding())) { // 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. const the_object_path = blk: { - if (self.base.options.objects.len != 0) - break :blk self.base.options.objects[0].path; + if (comp.objects.len != 0) + break :blk comp.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -2505,32 +2500,32 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--error-limit=0"); - if (self.base.options.sysroot) |sysroot| { + if (self.sysroot) |sysroot| { try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); } - if (self.base.options.lto) { - switch (self.base.options.optimize_mode) { + if (comp.config.lto) { + switch (comp.root_mod.optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("--lto-O2"), .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), } } try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{ - self.base.options.linker_optimization, + self.optimization, })); - if (self.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("--entry"); try argv.append(entry); } - for (self.base.options.force_undefined_symbols.keys()) |sym| { + for (self.base.force_undefined_symbols.keys()) |sym| { try argv.append("-u"); try argv.append(sym); } - switch (self.base.options.hash_style) { + switch (self.hash_style) { .gnu => try argv.append("--hash-style=gnu"), .sysv => try argv.append("--hash-style=sysv"), .both => {}, // this is the default @@ -2559,12 +2554,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base})); - if (self.base.options.linker_script) |linker_script| { + if (self.linker_script) |linker_script| { try argv.append("-T"); try argv.append(linker_script); } - if (self.base.options.sort_section) |how| { + if (self.sort_section) |how| { const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)}); try argv.append(arg); } @@ -2573,67 +2568,67 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--gc-sections"); } - if (self.base.options.print_gc_sections) { + if (self.base.print_gc_sections) { try argv.append("--print-gc-sections"); } - if (self.base.options.print_icf_sections) { + if (self.print_icf_sections) { try argv.append("--print-icf-sections"); } - if (self.base.options.print_map) { + if (self.print_map) { try argv.append("--print-map"); } - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { try argv.append("--eh-frame-hdr"); } - if (self.base.options.emit_relocs) { + if (self.emit_relocs) { try argv.append("--emit-relocs"); } - if (self.base.options.rdynamic) { + if (self.rdynamic) { try argv.append("--export-dynamic"); } - if (self.base.options.strip) { + if (self.base.debug_format == .strip) { try argv.append("-s"); } - if (self.base.options.z_nodelete) { + if (self.z_nodelete) { try argv.append("-z"); try argv.append("nodelete"); } - if (self.base.options.z_notext) { + if (self.z_notext) { try argv.append("-z"); try argv.append("notext"); } - if (self.base.options.z_defs) { + if (self.z_defs) { try argv.append("-z"); try argv.append("defs"); } - if (self.base.options.z_origin) { + if (self.z_origin) { try argv.append("-z"); try argv.append("origin"); } - if (self.base.options.z_nocopyreloc) { + if (self.z_nocopyreloc) { try argv.append("-z"); try argv.append("nocopyreloc"); } - if (self.base.options.z_now) { + if (self.z_now) { // LLD defaults to -zlazy try argv.append("-znow"); } - if (!self.base.options.z_relro) { + if (!self.z_relro) { // LLD defaults to -zrelro try argv.append("-znorelro"); } - if (self.base.options.z_common_page_size) |size| { + if (self.z_common_page_size) |size| { try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "common-page-size={d}", .{size})); } - if (self.base.options.z_max_page_size) |size| { + if (self.z_max_page_size) |size| { try argv.append("-z"); try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size})); } @@ -2658,7 +2653,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("-shared"); } - if (self.base.options.pie and output_mode == .Exe) { + if (comp.config.pie and output_mode == .Exe) { try argv.append("-pie"); } @@ -2683,20 +2678,20 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // rpaths var rpath_table = std.StringHashMap(void).init(gpa); defer rpath_table.deinit(); - for (self.base.options.rpath_list) |rpath| { + for (self.base.rpath_list) |rpath| { if ((try rpath_table.fetchPut(rpath, {})) == null) { try argv.append("-rpath"); try argv.append(rpath); } } - for (self.base.options.symbol_wrap_set.keys()) |symbol_name| { + for (self.symbol_wrap_set.keys()) |symbol_name| { try argv.appendSlice(&.{ "-wrap", symbol_name }); } - if (self.base.options.each_lib_rpath) { + if (self.each_lib_rpath) { var test_path = std.ArrayList(u8).init(arena); - for (self.base.options.lib_dirs) |lib_dir_path| { + for (self.lib_dirs) |lib_dir_path| { for (self.base.comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; @@ -2706,7 +2701,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } } - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (Compilation.classifyFileExt(obj.path) == .shared_library) { const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; if (obj.loption) continue; @@ -2719,12 +2714,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } - for (self.base.options.lib_dirs) |lib_dir| { + for (self.lib_dirs) |lib_dir| { try argv.append("-L"); try argv.append(lib_dir); } - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation) |libc_installation| { try argv.append("-L"); try argv.append(libc_installation.crt_dir.?); @@ -2739,11 +2734,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } if (is_dyn_lib) { - if (self.base.options.soname) |soname| { + if (self.soname) |soname| { try argv.append("-soname"); try argv.append(soname); } - if (self.base.options.version_script) |version_script| { + if (self.version_script) |version_script| { try argv.append("-version-script"); try argv.append(version_script); } @@ -2751,7 +2746,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // Positional arguments to the linker such as object files. var whole_archive = false; - for (self.base.options.objects) |obj| { + for (comp.objects) |obj| { if (obj.must_link and !whole_archive) { try argv.append("-whole-archive"); whole_archive = true; @@ -2779,15 +2774,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(p); } - // TSAN - if (self.base.options.tsan) { + if (comp.config.any_sanitize_thread) { try argv.append(comp.tsan_static_lib.?.full_object_path); } // libc if (is_exe_or_dyn_lib and - !self.base.options.skip_linker_dependencies and - !self.base.options.link_libc) + !comp.skip_linker_dependencies and + !comp.config.link_libc) { if (comp.libc_static_lib) |lib| { try argv.append(lib.full_object_path); @@ -2832,19 +2826,19 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } // libc++ dep - if (self.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxxabi_static_lib.?.full_object_path); try argv.append(comp.libcxx_static_lib.?.full_object_path); } // libunwind dep - if (self.base.options.link_libunwind) { + if (comp.config.link_libunwind) { try argv.append(comp.libunwind_static_lib.?.full_object_path); } // libc dep self.error_flags.missing_libc = false; - if (self.base.options.link_libc) { + if (comp.config.link_libc) { if (self.base.comp.libc_installation != null) { const needs_grouping = link_mode == .Static; if (needs_grouping) try argv.append("--start-group"); @@ -2884,13 +2878,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--allow-shlib-undefined"); } - switch (self.base.options.compress_debug_sections) { + switch (self.compress_debug_sections) { .none => {}, .zlib => try argv.append("--compress-debug-sections=zlib"), .zstd => try argv.append("--compress-debug-sections=zstd"), } - if (self.base.options.bind_global_refs_locally) { + if (self.bind_global_refs_locally) { try argv.append("-Bsymbolic"); } @@ -2964,7 +2958,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } } - if (!self.base.options.disable_lld_caching) { + if (!self.base.disable_lld_caching) { // Update the file with the digest. If it fails we can continue; it only // means that the next invocation will have an unnecessary cache miss. Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { @@ -3101,7 +3095,8 @@ fn writeElfHeader(self: *Elf) !void { }; index += 1; - const target = self.base.comp.root_mod.resolved_target.result; + const comp = self.base.comp; + const target = comp.root_mod.resolved_target.result; const endian = target.cpu.arch.endian(); hdr_buf[index] = switch (endian) { .little => elf.ELFDATA2LSB, @@ -3120,10 +3115,10 @@ fn writeElfHeader(self: *Elf) !void { assert(index == 16); - const output_mode = self.base.comp.config.output_mode; - const link_mode = self.base.comp.config.link_mode; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; const elf_type: elf.ET = switch (output_mode) { - .Exe => if (self.base.options.pie) .DYN else .EXEC, + .Exe => if (comp.config.pie) .DYN else .EXEC, .Obj => .REL, .Lib => switch (link_mode) { .Static => @as(elf.ET, .REL), @@ -3283,7 +3278,7 @@ fn addLinkerDefinedSymbols(self: *Elf) !void { self.plt_index = try linker_defined.addGlobal("_PROCEDURE_LINKAGE_TABLE_", self); self.end_index = try linker_defined.addGlobal("_end", self); - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { self.gnu_eh_frame_hdr_index = try linker_defined.addGlobal("__GNU_EH_FRAME_HDR", self); } @@ -3314,7 +3309,8 @@ fn addLinkerDefinedSymbols(self: *Elf) !void { } fn allocateLinkerDefinedSymbols(self: *Elf) void { - const link_mode = self.base.comp.config.link_mode; + const comp = self.base.comp; + const link_mode = comp.config.link_mode; // _DYNAMIC if (self.dynamic_section_index) |shndx| { @@ -3398,7 +3394,7 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { // __rela_iplt_start, __rela_iplt_end if (self.rela_dyn_section_index) |shndx| blk: { - if (link_mode != .Static or self.base.options.pie) break :blk; + if (link_mode != .Static or comp.config.pie) break :blk; const shdr = &self.shdrs.items[shndx]; const end_addr = shdr.sh_addr + shdr.sh_size; const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela); @@ -3445,7 +3441,8 @@ fn initOutputSections(self: *Elf) !void { } fn initSyntheticSections(self: *Elf) !void { - const target = self.base.comp.root_mod.resolved_target.result; + const comp = self.base.comp; + const target = comp.root_mod.resolved_target.result; const ptr_size = self.ptrWidthBytes(); const needs_eh_frame = for (self.objects.items) |index| { @@ -3460,7 +3457,7 @@ fn initSyntheticSections(self: *Elf) !void { .offset = std.math.maxInt(u64), }); - if (self.base.options.eh_frame_hdr) { + if (self.eh_frame_hdr) { self.eh_frame_hdr_section_index = try self.addSection(.{ .name = ".eh_frame_hdr", .type = elf.SHT_PROGBITS, @@ -3554,7 +3551,7 @@ fn initSyntheticSections(self: *Elf) !void { // In this case, if we do generate .interp section and segment, we will get // a segfault in the dynamic linker trying to load a binary that is static // and doesn't contain .dynamic section. - if (self.isStatic() and !self.base.options.pie) break :blk false; + if (self.isStatic() and !comp.config.pie) break :blk false; break :blk target.dynamic_linker.get() != null; }; if (needs_interp) { @@ -3567,7 +3564,7 @@ fn initSyntheticSections(self: *Elf) !void { }); } - if (self.base.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) { + if (self.base.isDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) { self.dynstrtab_section_index = try self.addSection(.{ .name = ".dynstr", .flags = elf.SHF_ALLOC, @@ -3859,7 +3856,7 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void { } if (self.base.isDynLib()) { - if (self.base.options.soname) |soname| { + if (self.soname) |soname| { try self.dynamic.setSoname(soname, self); } } diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index b3d7b51d3e..dc330fa54b 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -543,7 +543,7 @@ fn scanReloc( try self.reportPicError(symbol, rel, elf_file), .copyrel => { - if (elf_file.base.options.z_nocopyreloc) { + if (elf_file.z_nocopyreloc) { if (symbol.isAbs(elf_file)) try self.reportNoPicError(symbol, rel, elf_file) else @@ -553,9 +553,9 @@ fn scanReloc( }, .dyn_copyrel => { - if (is_writeable or elf_file.base.options.z_nocopyreloc) { + if (is_writeable or elf_file.z_nocopyreloc) { if (!is_writeable) { - if (elf_file.base.options.z_notext) { + if (elf_file.z_notext) { elf_file.has_text_reloc = true; } else { try self.reportTextRelocError(symbol, rel, elf_file); @@ -587,7 +587,7 @@ fn scanReloc( .dynrel, .baserel, .ifunc => { if (!is_writeable) { - if (elf_file.base.options.z_notext) { + if (elf_file.z_notext) { elf_file.has_text_reloc = true; } else { try self.reportTextRelocError(symbol, rel, elf_file); @@ -657,11 +657,12 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { } fn outputType(elf_file: *Elf) u2 { + const comp = elf_file.base.comp; assert(!elf_file.isRelocatable()); return switch (elf_file.base.comp.config.output_mode) { .Obj => unreachable, .Lib => 0, - .Exe => if (elf_file.base.options.pie) 1 else 2, + .Exe => if (comp.config.pie) 1 else 2, }; } @@ -979,7 +980,7 @@ fn resolveDynAbsReloc( => try writer.writeInt(i32, @as(i32, @truncate(S + A)), .little), .dyn_copyrel => { - if (is_writeable or elf_file.base.options.z_nocopyreloc) { + if (is_writeable or elf_file.z_nocopyreloc) { elf_file.addRelaDynAssumeCapacity(.{ .offset = P, .sym = target.extra(elf_file).?.dynamic, diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 347f96d451..5fa31711e6 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -299,7 +299,7 @@ fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { if (mem.startsWith(u8, name, ".note")) break :blk true; if (mem.startsWith(u8, name, ".comment")) break :blk true; if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; - if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and + if (elf_file.base.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and mem.startsWith(u8, name, ".debug")) break :blk true; break :blk false; }; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 15ae3bb943..05ff55dd18 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -97,7 +97,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { symbol_ptr.esym_index = esym_index; if (elf_file.base.debug_format != .strip) { - self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32); + self.dwarf = Dwarf.init(&elf_file.base, .dwarf32); } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 1e7f2f4f9f..92d5318c02 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -32,7 +32,7 @@ pub const DynamicSection = struct { fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 { _ = dt; var flags: u64 = 0; - if (elf_file.base.options.z_now) { + if (elf_file.z_now) { flags |= elf.DF_BIND_NOW; } for (elf_file.got.entries.items) |entry| switch (entry.tag) { @@ -49,15 +49,16 @@ pub const DynamicSection = struct { } fn getFlags1(dt: DynamicSection, elf_file: *Elf) ?u64 { + const comp = elf_file.base.comp; _ = dt; var flags_1: u64 = 0; - if (elf_file.base.options.z_now) { + if (elf_file.z_now) { flags_1 |= elf.DF_1_NOW; } - if (elf_file.isExe() and elf_file.base.options.pie) { + if (elf_file.isExe() and comp.config.pie) { flags_1 |= elf.DF_1_PIE; } - // if (elf_file.base.options.z_nodlopen) { + // if (elf_file.z_nodlopen) { // flags_1 |= elf.DF_1_NOOPEN; // } return if (flags_1 > 0) flags_1 else null; @@ -246,12 +247,13 @@ pub const ZigGotSection = struct { } pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { + const comp = elf_file.base.comp; const index = try zig_got.allocateEntry(elf_file.base.allocator); const entry = &zig_got.entries.items[index]; entry.* = sym_index; const symbol = elf_file.symbol(sym_index); symbol.flags.has_zig_got = true; - if (elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) { + if (elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) { zig_got.flags.needs_rela = true; } if (symbol.extra(elf_file)) |extra| { @@ -478,6 +480,7 @@ pub const GotSection = struct { } pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index { + const comp = elf_file.base.comp; const index = try got.allocateEntry(elf_file.base.allocator); const entry = &got.entries.items[index]; entry.tag = .got; @@ -485,7 +488,7 @@ pub const GotSection = struct { const symbol = elf_file.symbol(sym_index); symbol.flags.has_got = true; if (symbol.flags.import or symbol.isIFunc(elf_file) or - ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and !symbol.isAbs(elf_file))) + ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file))) { got.flags.needs_rela = true; } @@ -561,6 +564,7 @@ pub const GotSection = struct { } pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void { + const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isDynLib(); const apply_relocs = true; // TODO add user option for this @@ -576,7 +580,7 @@ pub const GotSection = struct { if (symbol.?.flags.import) break :blk 0; if (symbol.?.isIFunc(elf_file)) break :blk if (apply_relocs) value else 0; - if ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and + if ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.?.isAbs(elf_file)) { break :blk if (apply_relocs) value else 0; @@ -623,6 +627,7 @@ pub const GotSection = struct { } pub fn addRela(got: GotSection, elf_file: *Elf) !void { + const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isDynLib(); try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file)); @@ -652,7 +657,7 @@ pub const GotSection = struct { }); continue; } - if ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and + if ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.?.isAbs(elf_file)) { elf_file.addRelaDynAssumeCapacity(.{ @@ -725,6 +730,7 @@ pub const GotSection = struct { } pub fn numRela(got: GotSection, elf_file: *Elf) usize { + const comp = elf_file.base.comp; const is_dyn_lib = elf_file.isDynLib(); var num: usize = 0; for (got.entries.items) |entry| { @@ -734,7 +740,7 @@ pub const GotSection = struct { }; switch (entry.tag) { .got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or - ((elf_file.isDynLib() or (elf_file.isExe() and elf_file.base.options.pie)) and + ((elf_file.isDynLib() or (elf_file.isExe() and comp.config.pie)) and !symbol.?.isAbs(elf_file))) { num += 1; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3da076ba56..87faec6537 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -252,7 +252,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { self.d_sym = .{ .allocator = gpa, - .dwarf = link.File.Dwarf.init(gpa, &self.base, .dwarf32), + .dwarf = link.File.Dwarf.init(&self.base, .dwarf32), .file = d_sym_file, }; } @@ -573,7 +573,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.writeLinkeditSegmentData(); - var codesig: ?CodeSignature = if (requiresCodeSignature(&self.base.options)) blk: { + var codesig: ?CodeSignature = if (self.requiresCodeSignature()) blk: { // Preallocate space for the code signature. // We need to do this at this stage so that we have the load commands with proper values // written out to the file. @@ -619,12 +619,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No }); }, .Lib => if (self.base.comp.config.link_mode == .Dynamic) { - try load_commands.writeDylibIdLC(gpa, &self.base.options, lc_writer); + try load_commands.writeDylibIdLC(self, lc_writer); }, else => {}, } - try load_commands.writeRpathLCs(gpa, &self.base.options, lc_writer); + try load_commands.writeRpathLCs(self, lc_writer); try lc_writer.writeStruct(macho.source_version_command{ .version = 0, }); @@ -713,7 +713,7 @@ pub fn resolveLibSystem( success: { if (self.sdk_layout) |sdk_layout| switch (sdk_layout) { .sdk => { - const dir = try fs.path.join(arena, &[_][]const u8{ self.base.options.sysroot.?, "usr", "lib" }); + const dir = try fs.path.join(arena, &[_][]const u8{ comp.sysroot.?, "usr", "lib" }); if (try accessLibPath(arena, &test_path, &checked_paths, dir, "libSystem")) break :success; }, .vendored => { @@ -1156,7 +1156,8 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void { // 2) afterwards, we parse dependents of the included dylibs // TODO this should not be performed if the user specifies `-flat_namespace` flag. // See ld64 manpages. - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; while (dependent_libs.readItem()) |dep_id| { defer dep_id.id.deinit(gpa); @@ -1176,7 +1177,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void { var checked_paths = std.ArrayList([]const u8).init(arena); success: { - if (self.base.options.sysroot) |root| { + if (comp.sysroot) |root| { const dir = try fs.path.join(arena, &[_][]const u8{ root, dirname }); if (try accessLibPath(gpa, &test_path, &checked_paths, dir, stem)) break :success; } @@ -1713,12 +1714,12 @@ pub fn resolveSymbols(self: *MachO) !void { // we search for it in libraries should there be no object files specified // on the linker line. if (output_mode == .Exe) { - const entry_name = self.base.options.entry orelse load_commands.default_entry_point; + const entry_name = comp.config.entry.?; _ = try self.addUndefined(entry_name, .{}); } // Force resolution of any symbols requested by the user. - for (self.base.options.force_undefined_symbols.keys()) |sym_name| { + for (self.base.force_undefined_symbols.keys()) |sym_name| { _ = try self.addUndefined(sym_name, .{}); } @@ -4367,7 +4368,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx { // We generate stabs last in order to ensure that the strtab always has debug info // strings trailing - if (!self.base.options.strip) { + if (self.base.debug_format != .strip) { for (self.objects.items) |object| { assert(self.d_sym == null); // TODO try self.generateSymbolStabs(object, &locals); @@ -5171,7 +5172,8 @@ pub fn getStubsEntryAddress(self: *MachO, sym_with_loc: SymbolWithLoc) ?u64 { /// Returns symbol location corresponding to the set entrypoint if any. /// Asserts output mode is executable. pub fn getEntryPoint(self: MachO) ?SymbolWithLoc { - const entry_name = self.base.options.entry orelse load_commands.default_entry_point; + const comp = self.base.comp; + const entry_name = comp.config.entry orelse return null; const global = self.getGlobal(entry_name) orelse return null; return global; } @@ -5189,11 +5191,13 @@ pub inline fn getPageSize(cpu_arch: std.Target.Cpu.Arch) u16 { }; } -pub fn requiresCodeSignature(options: *const link.Options) bool { - if (options.entitlements) |_| return true; - const cpu_arch = options.target.cpu.arch; - const os_tag = options.target.os.tag; - const abi = options.target.abi; +pub fn requiresCodeSignature(m: *MachO) bool { + if (m.entitlements) |_| return true; + const comp = m.base.comp; + const target = comp.root_mod.resolved_target.result; + const cpu_arch = target.cpu.arch; + const os_tag = target.os.tag; + const abi = target.abi; if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) return true; return false; } diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 2e7f8e49af..74a4afeb54 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -198,10 +198,10 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) u64 } pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { + const comp = macho_file.base.comp; // TODO This linker code currently assumes there is only 1 compilation unit // and it corresponds to the Zig source code. - const options = macho_file.base.options; - const module = options.module orelse return error.LinkingWithoutZigSourceUnimplemented; + const zcu = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; for (self.relocs.items) |*reloc| { const sym = switch (reloc.type) { @@ -245,7 +245,7 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { const text_section = macho_file.sections.items(.header)[macho_file.text_section_index.?]; const low_pc = text_section.addr; const high_pc = text_section.addr + text_section.size; - try self.dwarf.writeDbgInfoHeader(module, low_pc, high_pc); + try self.dwarf.writeDbgInfoHeader(zcu, low_pc, high_pc); self.debug_info_header_dirty = false; } @@ -572,6 +572,5 @@ const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; const Dwarf = @import("../Dwarf.zig"); const MachO = @import("../MachO.zig"); -const Module = @import("../../Module.zig"); const StringTable = @import("../StringTable.zig"); const Type = @import("../../type.zig").Type; diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index 51a43351ba..a92126c07e 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -60,7 +60,7 @@ fn collectRoots(macho_file: *MachO, roots: *AtomTable) !void { } // Add all symbols force-defined by the user. - for (macho_file.base.options.force_undefined_symbols.keys()) |sym_name| { + for (macho_file.base.force_undefined_symbols.keys()) |sym_name| { const global_index = macho_file.resolver.get(sym_name).?; const global = macho_file.globals.items[global_index]; const sym = macho_file.getSymbol(global); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index be8ac63642..3bffc7f73e 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -1,6 +1,3 @@ -/// Default implicit entrypoint symbol name. -pub const default_entry_point: []const u8 = "_main"; - /// Default path to dyld. pub const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; @@ -17,7 +14,9 @@ const CalcLCsSizeCtx = struct { wants_function_starts: bool = true, }; -fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 { +fn calcLCsSize(m: *MachO, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 { + const comp = m.base.comp; + const gpa = comp.gpa; var has_text_segment: bool = false; var sizeofcmds: u64 = 0; for (ctx.segments) |seg| { @@ -46,15 +45,15 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx false, ); // LC_MAIN - if (options.output_mode == .Exe) { + if (comp.config.output_mode == .Exe) { sizeofcmds += @sizeOf(macho.entry_point_command); } // LC_ID_DYLIB - if (options.output_mode == .Lib and options.link_mode == .Dynamic) { + if (comp.config.output_mode == .Lib and comp.config.link_mode == .Dynamic) { sizeofcmds += blk: { - const emit = options.emit.?; - const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); - defer if (options.install_name == null) gpa.free(install_name); + const emit = m.base.emit; + const install_name = m.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); + defer if (m.install_name == null) gpa.free(install_name); break :blk calcInstallNameLen( @sizeOf(macho.dylib_command), install_name, @@ -64,7 +63,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx } // LC_RPATH { - var it = RpathIterator.init(gpa, options.rpath_list); + var it = RpathIterator.init(gpa, m.rpath_list); defer it.deinit(); while (try it.next()) |rpath| { sizeofcmds += calcInstallNameLen( @@ -78,7 +77,8 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx sizeofcmds += @sizeOf(macho.source_version_command); // LC_BUILD_VERSION or LC_VERSION_MIN_ or nothing { - const platform = Platform.fromTarget(options.target); + const target = comp.root_mod.resolved_target.result; + const platform = Platform.fromTarget(target); if (platform.isBuildVersionCompatible()) { // LC_BUILD_VERSION sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version); @@ -100,19 +100,19 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx ); } // LC_CODE_SIGNATURE - if (MachO.requiresCodeSignature(options)) { + if (m.requiresCodeSignature()) { sizeofcmds += @sizeOf(macho.linkedit_data_command); } - return @as(u32, @intCast(sizeofcmds)); + return @intCast(sizeofcmds); } -pub fn calcMinHeaderPad(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx) !u64 { - var padding: u32 = (try calcLCsSize(gpa, options, ctx, false)) + (options.headerpad_size orelse 0); +pub fn calcMinHeaderPad(m: *MachO, ctx: CalcLCsSizeCtx) !u64 { + var padding: u32 = (try calcLCsSize(m, ctx, false)) + m.headerpad_size; log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)}); - if (options.headerpad_max_install_names) { - const min_headerpad_size: u32 = try calcLCsSize(gpa, options, ctx, true); + if (m.headerpad_max_install_names) { + const min_headerpad_size: u32 = try calcLCsSize(m, ctx, true); log.debug("headerpad_max_install_names minimum headerpad size 0x{x}", .{ min_headerpad_size + @sizeOf(macho.mach_header_64), }); diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 8b0aa90f96..f40aaea4db 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -499,7 +499,7 @@ pub fn linkWithZld( } // Write code signature padding if required - var codesig: ?CodeSignature = if (MachO.requiresCodeSignature(&macho_file.base.options)) blk: { + var codesig: ?CodeSignature = if (macho_file.requiresCodeSignature()) blk: { // Preallocate space for the code signature. // We need to do this at this stage so that we have the load commands with proper values // written out to the file. @@ -547,12 +547,12 @@ pub fn linkWithZld( }); }, .Lib => if (link_mode == .Dynamic) { - try load_commands.writeDylibIdLC(gpa, &macho_file.base.options, lc_writer); + try load_commands.writeDylibIdLC(macho_file, lc_writer); }, else => {}, } - try load_commands.writeRpathLCs(gpa, &macho_file.base.options, lc_writer); + try load_commands.writeRpathLCs(macho_file, lc_writer); try lc_writer.writeStruct(macho.source_version_command{ .version = 0, }); @@ -1072,11 +1072,10 @@ fn calcSectionSizes(macho_file: *MachO) !void { } fn allocateSegments(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; for (macho_file.segments.items, 0..) |*segment, segment_index| { const is_text_segment = mem.eql(u8, segment.segName(), "__TEXT"); const base_size = if (is_text_segment) - try load_commands.calcMinHeaderPad(gpa, &macho_file.base.options, .{ + try load_commands.calcMinHeaderPad(macho_file, .{ .segments = macho_file.segments.items, .dylibs = macho_file.dylibs.items, .referenced_dylibs = macho_file.referenced_dylibs.keys(), diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index 1cfc14cef0..846e496ec1 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -57,6 +57,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, .function_sections = options.function_sections, .data_sections = options.data_sections, }, @@ -66,7 +67,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { return nvptx; } -pub fn open(arena: Allocator, options: link.FileOpenOptions) !*NvPtx { +pub fn open(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { const target = options.comp.root_mod.resolved_target.result; assert(target.ofmt == .nvptx); return createEmpty(arena, options); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 247986d767..b3c08fb66b 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -295,26 +295,36 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { } pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { - _ = arena; - const target = options.comp.root_mod.resolved_target.result; - const gpa = options.comp.gpa; + const comp = options.comp; + const target = comp.root_mod.resolved_target.result; + const gpa = comp.gpa; + const optimize_mode = comp.root_mod.optimize_mode; + const output_mode = comp.config.output_mode; - const sixtyfour_bit: bool = switch (options.target.ptrBitWidth()) { + const sixtyfour_bit: bool = switch (target.ptrBitWidth()) { 0...32 => false, 33...64 => true, else => return error.UnsupportedP9Architecture, }; - const arena_allocator = std.heap.ArenaAllocator.init(gpa); - - const self = try gpa.create(Plan9); + const self = try arena.create(Plan9); self.* = .{ - .path_arena = arena_allocator, + .path_arena = std.heap.ArenaAllocator.init(gpa), .base = .{ .tag = .plan9, - .options = options, - .allocator = gpa, + .comp = comp, + .emit = options.emit, + .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .stack_size = options.stack_size orelse 16777216, + .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, + .disable_lld_caching = options.disable_lld_caching, + .build_id = options.build_id, + .rpath_list = options.rpath_list, + .force_undefined_symbols = options.force_undefined_symbols, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }, .sixtyfour_bit = sixtyfour_bit, .bases = undefined, @@ -602,7 +612,7 @@ pub fn flush(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) li const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; assert(!use_lld); - switch (self.base.options.effectiveOutputMode()) { + switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) { .Exe => {}, // plan9 object files are totally different .Obj => return error.TODOImplementPlan9Objs, diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 414ebcf987..d8f78c32f1 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -67,6 +67,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { .force_undefined_symbols = options.force_undefined_symbols, .function_sections = options.function_sections, .data_sections = options.data_sections, + .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, }, .object = codegen.Object.init(gpa), }; @@ -102,7 +103,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV { errdefer spirv.base.destroy(); // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.?.directory.handle.createFile(options.emit.sub_path, .{ + const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ .truncate = true, .read = true, }); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 0a728c7b6b..74d83e6c3c 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -37,6 +37,13 @@ pub const Relocation = types.Relocation; pub const base_tag: link.File.Tag = .wasm; base: link.File, +import_symbols: bool, +export_symbol_names: []const []const u8, +rdynamic: bool, +global_base: ?u64, +initial_memory: ?u64, +max_memory: ?u64, +wasi_emulated_libs: []const wasi_libc.CRTFile, /// Output name of the file name: []const u8, /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. @@ -368,13 +375,15 @@ pub const StringTable = struct { pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { if (build_options.only_c) unreachable; - const gpa = options.comp.gpa; - const target = options.comp.root_mod.resolved_target.result; + const comp = options.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .wasm); - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; - const output_mode = options.comp.config.output_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + const output_mode = comp.config.output_mode; + const shared_memory = comp.config.shared_memory; const wasm = try createEmpty(arena, options); errdefer wasm.base.destroy(); @@ -395,7 +404,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { }; // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.?.directory.handle.createFile(sub_path, .{ + const file = try options.emit.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = if (fs.has_executable_bit) @@ -480,7 +489,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { } // shared-memory symbols for TLS support - if (wasm.base.options.shared_memory) { + if (shared_memory) { { const loc = try wasm.createSyntheticSymbol("__tls_base", .global); const symbol = loc.getSymbol(wasm); @@ -522,14 +531,15 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { } pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { - const use_llvm = options.comp.config.use_llvm; - const output_mode = options.comp.config.output_mode; + const comp = options.comp; + const use_llvm = comp.config.use_llvm; + const output_mode = comp.config.output_mode; const wasm = try arena.create(Wasm); wasm.* = .{ .base = .{ .tag = .wasm, - .comp = options.comp, + .comp = comp, .emit = options.emit, .gc_sections = options.gc_sections orelse (output_mode != .Obj), .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB @@ -546,6 +556,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { .name = undefined, .import_table = options.import_table, .export_table = options.export_table, + .import_symbols = options.import_symbols, + .export_symbol_names = options.export_symbol_names, + .rdynamic = options.rdynamic, + .global_base = options.global_base, + .initial_memory = options.initial_memory, + .max_memory = options.max_memory, + .wasi_emulated_libs = options.wasi_emulated_libs, }; if (use_llvm) { @@ -909,7 +926,10 @@ fn writeI32Const(writer: anytype, val: u32) !void { } fn setupInitMemoryFunction(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; // Passive segments are used to avoid memory being reinitialized on each // thread's instantiation. These passive segments are initialized and @@ -920,7 +940,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { return; } - const flag_address: u32 = if (wasm.base.options.shared_memory) address: { + const flag_address: u32 = if (shared_memory) address: { // when we have passive initialization segments and shared memory // `setupMemory` will create this symbol and set its virtual address. const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?; @@ -934,7 +954,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { // we have 0 locals try leb.writeULEB128(writer, @as(u32, 0)); - if (wasm.base.options.shared_memory) { + if (shared_memory) { // destination blocks // based on values we jump to corresponding label try writer.writeByte(std.wasm.opcode(.block)); // $drop @@ -968,14 +988,14 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { var segment_index: u32 = 0; while (it.next()) |entry| : (segment_index += 1) { const segment: Segment = wasm.segments.items[entry.value_ptr.*]; - if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) { + if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { // For passive BSS segments we can simple issue a memory.fill(0). // For non-BSS segments we do a memory.init. Both these // instructions take as their first argument the destination // address. try writeI32Const(writer, segment.offset); - if (wasm.base.options.shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) { + if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) { // When we initialize the TLS segment we also set the `__tls_base` // global. This allows the runtime to use this static copy of the // TLS data for the first/main thread. @@ -1000,7 +1020,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { } } - if (wasm.base.options.shared_memory) { + if (shared_memory) { // we set the init memory flag to value '2' try writeI32Const(writer, flag_address); try writeI32Const(writer, 2); @@ -1043,12 +1063,12 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { while (it.next()) |entry| : (segment_index += 1) { const name = entry.key_ptr.*; const segment: Segment = wasm.segments.items[entry.value_ptr.*]; - if (segment.needsPassiveInitialization(wasm.base.options.import_memory, name) and + if (segment.needsPassiveInitialization(import_memory, name) and !std.mem.eql(u8, name, ".bss")) { // The TLS region should not be dropped since its is needed // during the initialization of each thread (__wasm_init_tls). - if (wasm.base.options.shared_memory and std.mem.eql(u8, name, ".tdata")) { + if (shared_memory and std.mem.eql(u8, name, ".tdata")) { continue; } @@ -1071,11 +1091,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { /// Constructs a synthetic function that performs runtime relocations for /// TLS symbols. This function is called by `__wasm_init_tls`. fn setupTLSRelocationsFunction(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; // When we have TLS GOT entries and shared memory is enabled, // we must perform runtime relocations or else we don't create the function. - if (!wasm.base.options.shared_memory or !wasm.requiresTLSReloc()) { + if (!shared_memory or !wasm.requiresTLSReloc()) { return; } @@ -1119,7 +1141,9 @@ fn validateFeatures( to_emit: *[@typeInfo(types.Feature.Tag).Enum.fields.len]bool, emit_features_count: *u32, ) !void { - const target = wasm.base.comp.root_mod.resolved_target.result; + const comp = wasm.base.comp; + const target = comp.root_mod.resolved_target.result; + const shared_memory = comp.config.shared_memory; const cpu_features = target.cpu.features; const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects. const known_features_count = @typeInfo(types.Feature.Tag).Enum.fields.len; @@ -1190,7 +1214,7 @@ fn validateFeatures( return error.InvalidFeatureSet; } - if (wasm.base.options.shared_memory) { + if (shared_memory) { const disallowed_feature = disallowed[@intFromEnum(types.Feature.Tag.shared_mem)]; if (@as(u1, @truncate(disallowed_feature)) != 0) { log.err( @@ -1255,7 +1279,9 @@ fn validateFeatures( /// if one or multiple undefined references exist. When none exist, the symbol will /// not be created, ensuring we don't unneccesarily emit unreferenced symbols. fn resolveLazySymbols(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; if (wasm.string_table.getOffset("__heap_base")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { @@ -1273,7 +1299,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void { } } - if (!wasm.base.options.shared_memory) { + if (!shared_memory) { if (wasm.string_table.getOffset("__tls_base")) |name_offset| { if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); @@ -1306,8 +1332,9 @@ pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc { } fn checkUndefinedSymbols(wasm: *const Wasm) !void { - if (wasm.base.comp.config.output_mode == .Obj) return; - if (wasm.base.options.import_symbols) return; + const comp = wasm.base.comp; + if (comp.config.output_mode == .Obj) return; + if (wasm.import_symbols) return; var found_undefined_symbols = false; for (wasm.undefs.values()) |undef| { @@ -2182,7 +2209,10 @@ const Kind = union(enum) { /// Parses an Atom and inserts its metadata into the corresponding sections. fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; const atom = wasm.getAtomPtr(atom_index); const symbol = (SymbolLoc{ .file = null, .index = atom.sym_index }).getSymbol(wasm); const do_garbage_collect = wasm.base.gc_sections; @@ -2233,7 +2263,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { // we set the entire region of it to zeroes. // We do not have to do this when exporting the memory (the default) because the runtime // will do it for us, and we do not emit the bss segment at all. - if ((wasm.base.comp.config.output_mode == .Obj or wasm.base.options.import_memory) and kind.data == .uninitialized) { + if ((wasm.base.comp.config.output_mode == .Obj or import_memory) and kind.data == .uninitialized) { @memset(atom.code.items, 0); } @@ -2250,7 +2280,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void { } else { const index: u32 = @intCast(wasm.segments.items.len); var flags: u32 = 0; - if (wasm.base.options.shared_memory) { + if (shared_memory) { flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); } try wasm.segments.append(gpa, .{ @@ -2679,9 +2709,11 @@ fn setupStartSection(wasm: *Wasm) !void { } fn initializeTLSFunction(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const shared_memory = comp.config.shared_memory; - if (!wasm.base.options.shared_memory) return; + if (!shared_memory) return; var function_body = std.ArrayList(u8).init(gpa); defer function_body.deinit(); @@ -2940,7 +2972,7 @@ fn setupExports(wasm: *Wasm) !void { if (wasm.base.comp.config.output_mode == .Obj) return; log.debug("Building exports from symbols", .{}); - const force_exp_names = wasm.base.options.export_symbol_names; + const force_exp_names = wasm.export_symbol_names; if (force_exp_names.len > 0) { var failed_exports = false; @@ -2962,7 +2994,7 @@ fn setupExports(wasm: *Wasm) !void { for (wasm.resolved_symbols.keys()) |sym_loc| { const symbol = sym_loc.getSymbol(wasm); - if (!symbol.isExported(wasm.base.options.rdynamic)) continue; + if (!symbol.isExported(wasm.rdynamic)) continue; const sym_name = sym_loc.getName(wasm); const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { @@ -2997,8 +3029,9 @@ fn setupExports(wasm: *Wasm) !void { } fn setupStart(wasm: *Wasm) !void { + const comp = wasm.base.comp; // do not export entry point if user set none or no default was set. - const entry_name = wasm.base.options.entry orelse return; + const entry_name = comp.config.entry orelse return; const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse { log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name}); @@ -3012,13 +3045,15 @@ fn setupStart(wasm: *Wasm) !void { } // Ensure the symbol is exported so host environment can access it - if (wasm.base.comp.config.output_mode != .Obj) { + if (comp.config.output_mode != .Obj) { symbol.setFlag(.WASM_SYM_EXPORTED); } } /// Sets up the memory section of the wasm module, as well as the stack. fn setupMemory(wasm: *Wasm) !void { + const comp = wasm.base.comp; + const shared_memory = comp.config.shared_memory; log.debug("Setting up memory layout", .{}); const page_size = std.wasm.page_size; // 64kb const stack_alignment: Alignment = .@"16"; // wasm's stack alignment as specified by tool-convention @@ -3027,12 +3062,12 @@ fn setupMemory(wasm: *Wasm) !void { // Always place the stack at the start by default // unless the user specified the global-base flag var place_stack_first = true; - var memory_ptr: u64 = if (wasm.base.options.global_base) |base| blk: { + var memory_ptr: u64 = if (wasm.global_base) |base| blk: { place_stack_first = false; break :blk base; } else 0; - const is_obj = wasm.base.comp.config.output_mode == .Obj; + const is_obj = comp.config.output_mode == .Obj; if (place_stack_first and !is_obj) { memory_ptr = stack_alignment.forward(memory_ptr); @@ -3059,7 +3094,7 @@ fn setupMemory(wasm: *Wasm) !void { } if (wasm.findGlobalSymbol("__tls_base")) |loc| { const sym = loc.getSymbol(wasm); - wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (wasm.base.options.shared_memory) + wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory) @as(i32, 0) else @as(i32, @intCast(memory_ptr)); @@ -3072,7 +3107,7 @@ fn setupMemory(wasm: *Wasm) !void { } // create the memory init flag which is used by the init memory function - if (wasm.base.options.shared_memory and wasm.hasPassiveInitializationSegments()) { + if (shared_memory and wasm.hasPassiveInitializationSegments()) { // align to pointer size memory_ptr = mem.alignForward(u64, memory_ptr, 4); const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data); @@ -3098,7 +3133,7 @@ fn setupMemory(wasm: *Wasm) !void { // For now we only support wasm32 by setting the maximum allowed memory size 2^32-1 const max_memory_allowed: u64 = (1 << 32) - 1; - if (wasm.base.options.initial_memory) |initial_memory| { + if (wasm.initial_memory) |initial_memory| { if (!std.mem.isAlignedGeneric(u64, initial_memory, page_size)) { log.err("Initial memory must be {d}-byte aligned", .{page_size}); return error.MissAlignment; @@ -3124,7 +3159,7 @@ fn setupMemory(wasm: *Wasm) !void { symbol.virtual_address = @as(u32, @intCast(memory_ptr)); } - if (wasm.base.options.max_memory) |max_memory| { + if (wasm.max_memory) |max_memory| { if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) { log.err("Maximum memory must be {d}-byte aligned", .{page_size}); return error.MissAlignment; @@ -3139,7 +3174,7 @@ fn setupMemory(wasm: *Wasm) !void { } wasm.memories.limits.max = @as(u32, @intCast(max_memory / page_size)); wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_HAS_MAX); - if (wasm.base.options.shared_memory) { + if (shared_memory) { wasm.memories.limits.setFlag(.WASM_LIMITS_FLAG_IS_SHARED); } log.debug("Maximum memory pages: {?d}", .{wasm.memories.limits.max}); @@ -3150,20 +3185,22 @@ fn setupMemory(wasm: *Wasm) !void { /// index of the segment within the final data section. When the segment does not yet /// exist, a new one will be initialized and appended. The new index will be returned in that case. pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 { - const gpa = wasm.base.comp.gpa; + const comp = wasm.base.comp; + const gpa = comp.gpa; const object: Object = wasm.objects.items[object_index]; const symbol = object.symtable[symbol_index]; const index: u32 = @intCast(wasm.segments.items.len); + const shared_memory = comp.config.shared_memory; switch (symbol.tag) { .data => { const segment_info = object.segment_info[symbol.index]; - const merge_segment = wasm.base.comp.config.output_mode != .Obj; + const merge_segment = comp.config.output_mode != .Obj; const result = try wasm.data_segments.getOrPut(gpa, segment_info.outputName(merge_segment)); if (!result.found_existing) { result.value_ptr.* = index; var flags: u32 = 0; - if (wasm.base.options.shared_memory) { + if (shared_memory) { flags |= @intFromEnum(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE); } try wasm.segments.append(gpa, .{ @@ -3445,6 +3482,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l defer tracy.end(); const gpa = wasm.base.comp.gpa; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; // Used for all temporary memory allocated during flushin var arena_instance = std.heap.ArenaAllocator.init(gpa); @@ -3509,8 +3548,8 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l man.hash.addOptionalBytes(wasm.base.comp.config.entry); man.hash.add(wasm.base.stack_size); man.hash.add(wasm.base.build_id); - man.hash.add(wasm.base.comp.config.import_memory); - man.hash.add(wasm.base.comp.config.shared_memory); + man.hash.add(import_memory); + man.hash.add(shared_memory); man.hash.add(wasm.import_table); man.hash.add(wasm.export_table); man.hash.addOptional(wasm.initial_memory); @@ -3726,8 +3765,12 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) { // for safe build modes, we store the atom in the data segment, // whereas for unsafe build modes we store it in bss. - const is_initialized = wasm.base.options.optimize_mode == .Debug or - wasm.base.options.optimize_mode == .ReleaseSafe; + const decl_namespace = mod.namespacePtr(decl.src_namespace); + const optimize_mode = decl_namespace.file_scope.mod.optimize_mode; + const is_initialized = switch (optimize_mode) { + .Debug, .ReleaseSafe => true, + .ReleaseFast, .ReleaseSmall => false, + }; try wasm.parseAtom(atom_index, .{ .data = if (is_initialized) .initialized else .uninitialized }); } else { // when the decl is all zeroes, we store the atom in the bss segment, @@ -3788,9 +3831,13 @@ fn writeToFile( feature_count: u32, arena: Allocator, ) !void { - const gpa = wasm.base.comp.gpa; - const use_llvm = wasm.base.comp.config.use_llvm; - const use_lld = build_options.have_llvm and wasm.base.comp.config.use_lld; + const comp = wasm.base.comp; + const gpa = comp.gpa; + const use_llvm = comp.config.use_llvm; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const shared_memory = comp.config.shared_memory; + const import_memory = comp.config.import_memory; + const export_memory = comp.config.export_memory; // Size of each section header const header_size = 5 + 1; @@ -3800,7 +3847,7 @@ fn writeToFile( var code_section_index: ?u32 = null; // Index of the data section. Used to tell relocation table where the section lives. var data_section_index: ?u32 = null; - const is_obj = wasm.base.comp.config.output_mode == .Obj or (!use_llvm and use_lld); + const is_obj = comp.config.output_mode == .Obj or (!use_llvm and use_lld); var binary_bytes = std.ArrayList(u8).init(gpa); defer binary_bytes.deinit(); @@ -3840,8 +3887,6 @@ fn writeToFile( } // Import section - const import_memory = wasm.base.options.import_memory or is_obj; - const export_memory = wasm.base.options.export_memory; if (wasm.imports.count() != 0 or import_memory) { const header_offset = try reserveVecSectionHeader(&binary_bytes); @@ -4018,7 +4063,7 @@ fn writeToFile( // When the shared-memory option is enabled, we *must* emit the 'data count' section. const data_segments_count = wasm.data_segments.count() - @intFromBool(wasm.data_segments.contains(".bss") and !import_memory); - if (data_segments_count != 0 and wasm.base.options.shared_memory) { + if (data_segments_count != 0 and shared_memory) { const header_offset = try reserveVecSectionHeader(&binary_bytes); try writeVecSectionHeader( binary_bytes.items, @@ -4160,11 +4205,11 @@ fn writeToFile( if (data_section_index) |data_index| { try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table); } - } else if (!wasm.base.options.strip) { + } else if (wasm.base.debug_format != .strip) { try wasm.emitNameSection(&binary_bytes, arena); } - if (!wasm.base.options.strip) { + if (wasm.base.debug_format != .strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. switch (wasm.base.build_id) { @@ -4193,7 +4238,7 @@ fn writeToFile( } // if (wasm.dwarf) |*dwarf| { - // const mod = wasm.base.comp.module.?; + // const mod = comp.module.?; // try dwarf.writeDbgAbbrev(); // // for debug info and ranges, the address is always 0, // // as locations are always offsets relative to 'code' section. @@ -4380,6 +4425,8 @@ fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []con } fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void { + const comp = wasm.base.comp; + const import_memory = comp.config.import_memory; const Name = struct { index: u32, name: []const u8, @@ -4418,7 +4465,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem for (wasm.data_segments.keys()) |key| { // bss section is not emitted when this condition holds true, so we also // do not output a name for it. - if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue; + if (!import_memory and std.mem.eql(u8, key, ".bss")) continue; segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key }); data_segment_index += 1; } @@ -4528,6 +4575,11 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! const tracy = trace(@src()); defer tracy.end(); + const shared_memory = comp.config.shared_memory; + const export_memory = comp.config.export_memory; + const import_memory = comp.config.import_memory; + const target = comp.root_mod.resolved_target.result; + const gpa = wasm.base.comp.gpa; var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); @@ -4560,8 +4612,6 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! break :blk null; }; - const target = wasm.base.comp.root_mod.resolved_target.result; - const id_symlink_basename = "lld.id"; var man: Cache.Manifest = undefined; @@ -4577,7 +4627,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! comptime assert(Compilation.link_hash_implementation_version == 10); - for (wasm.base.options.objects) |obj| { + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); } @@ -4589,17 +4639,17 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! man.hash.addOptionalBytes(wasm.base.comp.config.entry); man.hash.add(wasm.base.stack_size); man.hash.add(wasm.base.build_id); - man.hash.add(wasm.base.options.import_memory); - man.hash.add(wasm.base.options.export_memory); + man.hash.add(import_memory); + man.hash.add(export_memory); man.hash.add(wasm.import_table); man.hash.add(wasm.export_table); - man.hash.addOptional(wasm.base.options.initial_memory); - man.hash.addOptional(wasm.base.options.max_memory); - man.hash.add(wasm.base.options.shared_memory); - man.hash.addOptional(wasm.base.options.global_base); - man.hash.add(wasm.base.options.export_symbol_names.len); + man.hash.addOptional(wasm.initial_memory); + man.hash.addOptional(wasm.max_memory); + man.hash.add(shared_memory); + man.hash.addOptional(wasm.global_base); + man.hash.add(wasm.export_symbol_names.len); // strip does not need to go into the linker hash because it is part of the hash namespace - for (wasm.base.options.export_symbol_names) |symbol_name| { + for (wasm.export_symbol_names) |symbol_name| { man.hash.addBytes(symbol_name); } @@ -4637,8 +4687,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // here. TODO: think carefully about how we can avoid this redundant operation when doing // build-obj. See also the corresponding TODO in linkAsArchive. const the_object_path = blk: { - if (wasm.base.options.objects.len != 0) - break :blk wasm.base.options.objects[0].path; + if (comp.objects.len != 0) + break :blk comp.objects[0].path; if (comp.c_object_table.count() != 0) break :blk comp.c_object_table.keys()[0].status.success.object_path; @@ -4666,19 +4716,19 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); try argv.append("--error-limit=0"); - if (wasm.base.options.lto) { - switch (wasm.base.options.optimize_mode) { + if (comp.config.lto) { + switch (comp.root_mod.optimize_mode) { .Debug => {}, .ReleaseSmall => try argv.append("-O2"), .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), } } - if (wasm.base.options.import_memory) { + if (import_memory) { try argv.append("--import-memory"); } - if (wasm.base.options.export_memory) { + if (export_memory) { try argv.append("--export-memory"); } @@ -4698,25 +4748,25 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append("--no-gc-sections"); } - if (wasm.base.options.strip) { + if (wasm.base.debug_format == .strip) { try argv.append("-s"); } - if (wasm.base.options.initial_memory) |initial_memory| { + if (wasm.initial_memory) |initial_memory| { const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory}); try argv.append(arg); } - if (wasm.base.options.max_memory) |max_memory| { + if (wasm.max_memory) |max_memory| { const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory}); try argv.append(arg); } - if (wasm.base.options.shared_memory) { + if (shared_memory) { try argv.append("--shared-memory"); } - if (wasm.base.options.global_base) |global_base| { + if (wasm.global_base) |global_base| { const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base}); try argv.append(arg); } else { @@ -4728,16 +4778,16 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } // Users are allowed to specify which symbols they want to export to the wasm host. - for (wasm.base.options.export_symbol_names) |symbol_name| { + for (wasm.export_symbol_names) |symbol_name| { const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); try argv.append(arg); } - if (wasm.base.options.rdynamic) { + if (wasm.rdynamic) { try argv.append("--export-dynamic"); } - if (wasm.base.options.entry) |entry| { + if (comp.config.entry) |entry| { try argv.append("--entry"); try argv.append(entry); } else { @@ -4749,14 +4799,14 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}), }); - if (wasm.base.options.import_symbols) { + if (wasm.import_symbols) { try argv.append("--allow-undefined"); } if (wasm.base.comp.config.output_mode == .Lib and wasm.base.comp.config.link_mode == .Dynamic) { try argv.append("--shared"); } - if (wasm.base.options.pie) { + if (comp.config.pie) { try argv.append("--pie"); } @@ -4782,15 +4832,15 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! )); } - if (wasm.base.options.link_libc) { + if (comp.config.link_libc) { try argv.append(try comp.get_libc_crt_file( arena, - wasi_libc.execModelCrtFileFullName(wasm.base.options.wasi_exec_model), + wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model), )); try argv.append(try comp.get_libc_crt_file(arena, "libc.a")); } - if (wasm.base.options.link_libcpp) { + if (comp.config.link_libcpp) { try argv.append(comp.libcxx_static_lib.?.full_object_path); try argv.append(comp.libcxxabi_static_lib.?.full_object_path); } @@ -4799,7 +4849,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! // Positional arguments to the linker such as object files. var whole_archive = false; - for (wasm.base.options.objects) |obj| { + for (comp.objects) |obj| { if (obj.must_link and !whole_archive) { try argv.append("-whole-archive"); whole_archive = true; @@ -4822,8 +4872,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! } if (wasm.base.comp.config.output_mode != .Obj and - !wasm.base.options.skip_linker_dependencies and - !wasm.base.options.link_libc) + !comp.skip_linker_dependencies and + !comp.config.link_libc) { try argv.append(comp.libc_static_lib.?.full_object_path); } @@ -5168,10 +5218,13 @@ fn emitDataRelocations( } fn hasPassiveInitializationSegments(wasm: *const Wasm) bool { + const comp = wasm.base.comp; + const import_memory = comp.config.import_memory; + var it = wasm.data_segments.iterator(); while (it.next()) |entry| { const segment: Segment = wasm.segments.items[entry.value_ptr.*]; - if (segment.needsPassiveInitialization(wasm.base.options.import_memory, entry.key_ptr.*)) { + if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) { return true; } } @@ -5227,14 +5280,14 @@ fn markReferences(wasm: *Wasm) !void { for (wasm.resolved_symbols.keys()) |sym_loc| { const sym = sym_loc.getSymbol(wasm); - if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { + if (sym.isExported(wasm.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { try wasm.mark(sym_loc); continue; } // Debug sections may require to be parsed and marked when it contains // relocations to alive symbols. - if (sym.tag == .section and !wasm.base.options.strip) { + if (sym.tag == .section and wasm.base.debug_format != .strip) { const file = sym_loc.file orelse continue; // Incremental debug info is done independently const object = &wasm.objects.items[file]; const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm); -- cgit v1.2.3 From f5ddef1e45fb5e6defcad21e50736c6e0f63c089 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 13 Dec 2023 13:05:57 -0700 Subject: update references to module (to be renamed to zcu) --- src/Compilation.zig | 64 ++++++------ src/arch/aarch64/CodeGen.zig | 136 ++++++++++++------------ src/arch/arm/CodeGen.zig | 140 ++++++++++++------------- src/arch/riscv64/CodeGen.zig | 44 ++++---- src/arch/sparc64/CodeGen.zig | 86 ++++++++-------- src/arch/wasm/CodeGen.zig | 2 +- src/arch/x86_64/CodeGen.zig | 240 +++++++++++++++++++++---------------------- src/codegen.zig | 16 +-- src/codegen/llvm.zig | 2 +- 9 files changed, 365 insertions(+), 365 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 1abd124af4..9d2e80cb5a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1915,7 +1915,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } pub fn destroy(self: *Compilation) void { - const optional_module = self.bin_file.options.module; + const optional_module = self.module; self.bin_file.destroy(); if (optional_module) |module| module.deinit(); @@ -2017,7 +2017,7 @@ fn restorePrevZigCacheArtifactDirectory(comp: *Compilation, directory: *Director // Restore the Module's previous zig_cache_artifact_directory // This is only for cleanup purposes; Module.deinit calls close // on the handle of zig_cache_artifact_directory. - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { const builtin_mod = module.main_mod.deps.get("builtin").?; module.zig_cache_artifact_directory = builtin_mod.root.root_dir; } @@ -2109,7 +2109,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void }; // This updates the output directory for linker outputs. - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { module.zig_cache_artifact_directory = tmp_artifact_directory.?; } @@ -2155,7 +2155,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void } } - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { module.compile_log_text.shrinkAndFree(module.gpa, 0); module.generation += 1; @@ -2206,7 +2206,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void try comp.performAllTheWork(main_progress_node); - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { if (builtin.mode == .Debug and comp.verbose_intern_pool) { std.debug.print("intern pool stats for '{s}':\n", .{ comp.bin_file.options.root_name, @@ -2277,7 +2277,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void } // This is intentionally sandwiched between renameTmpIntoCache() and writeManifest(). - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { // We need to set the zig_cache_artifact_directory for -femit-asm, -femit-llvm-ir, // etc to know where to output to. var artifact_dir = try comp.local_cache_directory.handle.openDir(o_sub_path, .{}); @@ -2322,7 +2322,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // to it, and (2) generic instantiations, comptime calls, inline calls will need // to reference the ZIR. if (!comp.keep_source_files_loaded) { - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { for (module.import_table.values()) |file| { file.unloadTree(comp.gpa); file.unloadSource(comp.gpa); @@ -2332,7 +2332,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void } fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !void { - const mod = comp.bin_file.options.module orelse return; + const mod = comp.module orelse return; // TODO: do this in a separate job during performAllTheWork(). The // file copies at the end of generate() can also be extracted to // separate jobs @@ -2360,7 +2360,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { }; comp.link_error_flags = comp.bin_file.errorFlags(); - if (comp.bin_file.options.module) |module| { + if (comp.module) |module| { try link.File.C.flushEmitH(module); } } @@ -2421,7 +2421,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes comptime assert(link_hash_implementation_version == 10); - if (comp.bin_file.options.module) |mod| { + if (comp.module) |mod| { const main_zig_file = try mod.main_mod.root.joinString(arena, mod.main_mod.root_src_path); _ = try man.addFile(main_zig_file, null); try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.main_mod, .{ .files = man }); @@ -2559,7 +2559,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes } fn emitOthers(comp: *Compilation) void { - if (comp.bin_file.options.output_mode != .Obj or comp.bin_file.options.module != null or + if (comp.bin_file.options.output_mode != .Obj or comp.module != null or comp.c_object_table.count() == 0) { return; @@ -2727,7 +2727,7 @@ pub fn saveState(comp: *Compilation) !void { const emit = comp.bin_file.options.emit orelse return; - if (comp.bin_file.options.module) |mod| { + if (comp.module) |mod| { const ip = &mod.intern_pool; const header: Header = .{ .intern_pool = .{ @@ -2792,7 +2792,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { } } - if (self.bin_file.options.module) |module| { + if (self.module) |module| { total += module.failed_exports.count(); total += module.failed_embed_files.count(); @@ -2844,7 +2844,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { // Compile log errors only count if there are no other errors. if (total == 0) { - if (self.bin_file.options.module) |module| { + if (self.module) |module| { total += @intFromBool(module.compile_log_decls.count() != 0); } } @@ -2896,7 +2896,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { .msg = try bundle.addString("memory allocation failure"), }); } - if (self.bin_file.options.module) |module| { + if (self.module) |module| { for (module.failed_files.keys(), module.failed_files.values()) |file, error_msg| { if (error_msg) |msg| { try addModuleErrorMsg(module, &bundle, msg.*); @@ -3002,7 +3002,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { } } - if (self.bin_file.options.module) |module| { + if (self.module) |module| { if (bundle.root_list.items.len == 0 and module.compile_log_decls.count() != 0) { const keys = module.compile_log_decls.keys(); const values = module.compile_log_decls.values(); @@ -3030,7 +3030,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { assert(self.totalErrorCount() == bundle.root_list.items.len); - const compile_log_text = if (self.bin_file.options.module) |m| m.compile_log_text.items else ""; + const compile_log_text = if (self.module) |m| m.compile_log_text.items else ""; return bundle.toOwnedBundle(compile_log_text); } @@ -3314,7 +3314,7 @@ pub fn performAllTheWork( // 1. to avoid race condition of zig processes truncating each other's builtin.zig files // 2. optimization; in the hot path it only incurs a stat() syscall, which happens // in the `astgen_wait_group`. - if (comp.bin_file.options.module) |mod| { + if (comp.module) |mod| { if (mod.job_queued_update_builtin_zig) { mod.job_queued_update_builtin_zig = false; @@ -3356,15 +3356,15 @@ pub fn performAllTheWork( } } - if (comp.bin_file.options.module) |mod| { + if (comp.module) |mod| { try reportMultiModuleErrors(mod); } - if (comp.bin_file.options.module) |mod| { + if (comp.module) |mod| { mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); mod.sema_prog_node.activate(); } - defer if (comp.bin_file.options.module) |mod| { + defer if (comp.module) |mod| { mod.sema_prog_node.end(); mod.sema_prog_node = undefined; }; @@ -3398,7 +3398,7 @@ pub fn performAllTheWork( fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !void { switch (job) { .codegen_decl => |decl_index| { - const module = comp.bin_file.options.module.?; + const module = comp.module.?; const decl = module.declPtr(decl_index); switch (decl.analysis) { @@ -3436,14 +3436,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v const named_frame = tracy.namedFrame("codegen_func"); defer named_frame.end(); - const module = comp.bin_file.options.module.?; + const module = comp.module.?; module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => return, }; }, .emit_h_decl => |decl_index| { - const module = comp.bin_file.options.module.?; + const module = comp.module.?; const decl = module.declPtr(decl_index); switch (decl.analysis) { @@ -3502,7 +3502,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v } }, .analyze_decl => |decl_index| { - const module = comp.bin_file.options.module.?; + const module = comp.module.?; module.ensureDeclAnalyzed(decl_index) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => return, @@ -3520,7 +3520,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v defer named_frame.end(); const gpa = comp.gpa; - const module = comp.bin_file.options.module.?; + const module = comp.module.?; const decl = module.declPtr(decl_index); comp.bin_file.updateDeclLineNumber(module, decl_index) catch |err| { try module.failed_decls.ensureUnusedCapacity(gpa, 1); @@ -3537,7 +3537,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v const named_frame = tracy.namedFrame("analyze_mod"); defer named_frame.end(); - const module = comp.bin_file.options.module.?; + const module = comp.module.?; module.semaPkg(pkg) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => return, @@ -3716,7 +3716,7 @@ fn workerAstGenFile( child_prog_node.activate(); defer child_prog_node.end(); - const mod = comp.bin_file.options.module.?; + const mod = comp.module.?; mod.astGenFile(file) catch |err| switch (err) { error.AnalysisFail => return, else => { @@ -3819,7 +3819,7 @@ fn workerCheckEmbedFile( } fn detectEmbedFileUpdate(comp: *Compilation, embed_file: *Module.EmbedFile) !void { - const mod = comp.bin_file.options.module.?; + const mod = comp.module.?; const ip = &mod.intern_pool; const sub_file_path = ip.stringToSlice(embed_file.sub_file_path); var file = try embed_file.owner.root.openFile(sub_file_path, .{}); @@ -4142,7 +4142,7 @@ fn reportRetryableAstGenError( file: *Module.File, err: anyerror, ) error{OutOfMemory}!void { - const mod = comp.bin_file.options.module.?; + const mod = comp.module.?; const gpa = mod.gpa; file.status = .retryable_failure; @@ -4181,7 +4181,7 @@ fn reportRetryableEmbedFileError( embed_file: *Module.EmbedFile, err: anyerror, ) error{OutOfMemory}!void { - const mod = comp.bin_file.options.module.?; + const mod = comp.module.?; const gpa = mod.gpa; const src_loc = embed_file.src_loc; const ip = &mod.intern_pool; @@ -4248,7 +4248,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P // Special case when doing build-obj for just one C file. When there are more than one object // file and building an object we need to link them together, but with just one it should go // directly to the output file. - const direct_o = comp.c_source_files.len == 1 and comp.bin_file.options.module == null and + const direct_o = comp.c_source_files.len == 1 and comp.module == null and comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0; const o_basename_noext = if (direct_o) comp.bin_file.options.root_name diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 9ad7b0bbaa..c70b61c30d 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -341,7 +341,7 @@ pub fn generate( @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const func = mod.funcInfo(func_index); const fn_owner_decl = mod.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); @@ -476,7 +476,7 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { } fn gen(self: *Self) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const cc = self.fn_type.fnCallingConvention(mod); if (cc != .Naked) { // stp fp, lr, [sp, #-16]! @@ -656,7 +656,7 @@ fn gen(self: *Self) !void { } fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const air_tags = self.air.instructions.items(.tag); @@ -1028,7 +1028,7 @@ fn allocMem( /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst).childType(mod); if (!elem_ty.hasRuntimeBits(mod)) { @@ -1048,7 +1048,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); }; @@ -1139,7 +1139,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { } fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = switch (self.ret_mcv) { .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, .stack_offset => blk: { @@ -1176,7 +1176,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const operand = ty_op.operand; const operand_mcv = try self.resolveInst(operand); const operand_ty = self.typeOf(operand); @@ -1257,7 +1257,7 @@ fn trunc( operand_ty: Type, dest_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const info_a = operand_ty.intInfo(mod); const info_b = dest_ty.intInfo(mod); @@ -1320,7 +1320,7 @@ fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void { fn airNot(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); @@ -1415,7 +1415,7 @@ fn minMax( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM min/max on floats", .{}), .Vector => return self.fail("TODO ARM min/max on vectors", .{}), @@ -1905,7 +1905,7 @@ fn addSub( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO binary operations on floats", .{}), .Vector => return self.fail("TODO binary operations on vectors", .{}), @@ -1966,7 +1966,7 @@ fn mul( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { @@ -1998,7 +1998,7 @@ fn divFloat( _ = rhs_ty; _ = maybe_inst; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO div_float", .{}), .Vector => return self.fail("TODO div_float on vectors", .{}), @@ -2014,7 +2014,7 @@ fn divTrunc( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO div on floats", .{}), .Vector => return self.fail("TODO div on vectors", .{}), @@ -2048,7 +2048,7 @@ fn divFloor( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO div on floats", .{}), .Vector => return self.fail("TODO div on vectors", .{}), @@ -2081,7 +2081,7 @@ fn divExact( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO div on floats", .{}), .Vector => return self.fail("TODO div on vectors", .{}), @@ -2117,7 +2117,7 @@ fn rem( ) InnerError!MCValue { _ = maybe_inst; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO rem/mod on floats", .{}), .Vector => return self.fail("TODO rem/mod on vectors", .{}), @@ -2188,7 +2188,7 @@ fn modulo( _ = rhs_ty; _ = maybe_inst; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO mod on floats", .{}), .Vector => return self.fail("TODO mod on vectors", .{}), @@ -2206,7 +2206,7 @@ fn wrappingArithmetic( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { @@ -2241,7 +2241,7 @@ fn bitwise( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { @@ -2276,7 +2276,7 @@ fn shiftExact( ) InnerError!MCValue { _ = rhs_ty; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { @@ -2326,7 +2326,7 @@ fn shiftNormal( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO binary operations on vectors", .{}), .Int => { @@ -2366,7 +2366,7 @@ fn booleanOp( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Bool => { assert((try lhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema @@ -2393,7 +2393,7 @@ fn ptrArithmetic( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Pointer => { assert(rhs_ty.eql(Type.usize, mod)); @@ -2516,7 +2516,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; @@ -2644,7 +2644,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = result: { const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; @@ -2868,7 +2868,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = result: { const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; @@ -3016,7 +3016,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { } fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty: Type) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const payload_ty = optional_ty.optionalChild(mod); if (!payload_ty.hasRuntimeBits(mod)) return MCValue.none; if (optional_ty.isPtrLikeOptional(mod)) { @@ -3060,7 +3060,7 @@ fn errUnionErr( error_union_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_ty = error_union_ty.errorUnionSet(mod); const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { @@ -3140,7 +3140,7 @@ fn errUnionPayload( error_union_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_ty = error_union_ty.errorUnionSet(mod); const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { @@ -3252,7 +3252,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { } fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; if (self.liveness.isUnused(inst)) { @@ -3297,7 +3297,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { /// T to E!T fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = ty_op.ty.toType(); @@ -3323,7 +3323,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const error_union_ty = ty_op.ty.toType(); const error_ty = error_union_ty.errorUnionSet(mod); const payload_ty = error_union_ty.errorUnionPayload(mod); @@ -3426,7 +3426,7 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { } fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const slice_ty = self.typeOf(bin_op.lhs); const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { @@ -3450,7 +3450,7 @@ fn ptrElemVal( ptr_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = ptr_ty.childType(mod); const elem_size = @as(u32, @intCast(elem_ty.abiSize(mod))); @@ -3492,7 +3492,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { } fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); const result: MCValue = if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { @@ -3615,7 +3615,7 @@ fn reuseOperand( } fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = ptr_ty.childType(mod); const elem_size = elem_ty.abiSize(mod); @@ -3863,7 +3863,7 @@ fn genInlineMemsetCode( } fn airLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const elem_ty = self.typeOfIndex(inst); const elem_size = elem_ty.abiSize(mod); @@ -3894,7 +3894,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { } fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); const tag: Mir.Inst.Tag = switch (abi_size) { @@ -3917,7 +3917,7 @@ fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type } fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); const tag: Mir.Inst.Tag = switch (abi_size) { @@ -3939,7 +3939,7 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type } fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; log.debug("store: storing {} to {}", .{ value, ptr }); const abi_size = value_ty.abiSize(mod); @@ -4092,7 +4092,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { return if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv = try self.resolveInst(operand); const ptr_ty = self.typeOf(operand); const struct_ty = ptr_ty.childType(mod); @@ -4117,7 +4117,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const operand = extra.struct_operand; const index = extra.field_index; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv = try self.resolveInst(operand); const struct_ty = self.typeOf(operand); const struct_field_ty = struct_ty.structFieldType(index, mod); @@ -4167,7 +4167,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { } fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { @@ -4195,7 +4195,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { while (self.args[arg_index] == .none) arg_index += 1; self.arg_index = arg_index + 1; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty = self.typeOfIndex(inst); const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const src_index = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.src_index; @@ -4250,7 +4250,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const extra = self.air.extraData(Air.Call, pl_op.payload); const args = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len])); const ty = self.typeOf(callee); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const fn_ty = switch (ty.zigTypeTag(mod)) { .Fn => ty, @@ -4422,7 +4422,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier } fn airRet(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); const ret_ty = self.fn_type.fnReturnType(mod); @@ -4454,7 +4454,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { } fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ptr = try self.resolveInst(un_op); const ptr_ty = self.typeOf(un_op); @@ -4514,7 +4514,7 @@ fn cmp( lhs_ty: Type, op: math.CompareOperator, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const int_ty = switch (lhs_ty.zigTypeTag(mod)) { .Optional => blk: { const payload_ty = lhs_ty.optionalChild(mod); @@ -4622,7 +4622,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const func = mod.funcInfo(ty_fn.func); // TODO emit debug info for function change _ = func; @@ -4830,7 +4830,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { } fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const sentinel: struct { ty: Type, bind: ReadArg.Bind } = if (!operand_ty.isPtrLikeOptional(mod)) blk: { const payload_ty = operand_ty.optionalChild(mod); if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) @@ -4886,7 +4886,7 @@ fn isErr( error_union_bind: ReadArg.Bind, error_union_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const error_type = error_union_ty.errorUnionSet(mod); if (error_type.errorSetIsEmpty(mod)) { @@ -4928,7 +4928,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { } fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -4955,7 +4955,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { } fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -4982,7 +4982,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { } fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -5009,7 +5009,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { } fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -5226,7 +5226,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { } fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const block_data = self.blocks.getPtr(block).?; if (self.typeOf(operand).hasRuntimeBits(mod)) { @@ -5403,7 +5403,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { } fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = @as(u32, @intCast(ty.abiSize(mod))); switch (mcv) { .dead => unreachable, @@ -5573,7 +5573,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro } fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (mcv) { .dead => unreachable, .unreach, .none => return, // Nothing to do. @@ -5735,7 +5735,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void } fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = @as(u32, @intCast(ty.abiSize(mod))); switch (mcv) { .dead => unreachable, @@ -5934,7 +5934,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { } fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const ptr_ty = self.typeOf(ty_op.operand); @@ -6054,7 +6054,7 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const vector_ty = self.typeOfIndex(inst); const len = vector_ty.vectorLen(mod); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; @@ -6098,7 +6098,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { } fn airTry(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = self.air.extraData(Air.Try, pl_op.payload); const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); @@ -6135,7 +6135,7 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { } fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; // If the type has no codegen bits, no need to store it. const inst_ty = self.typeOf(inst); @@ -6200,7 +6200,7 @@ const CallMCValues = struct { /// Caller must call `CallMCValues.deinit`. fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const fn_info = mod.typeToFunc(fn_ty).?; const cc = fn_info.cc; @@ -6363,7 +6363,7 @@ fn parseRegName(name: []const u8) ?Register { } fn registerAlias(self: *Self, reg: Register, ty: Type) Register { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); switch (reg.class()) { @@ -6392,11 +6392,11 @@ fn registerAlias(self: *Self, reg: Register, ty: Type) Register { } fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOf(inst, &mod.intern_pool); } fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOfIndex(inst, &mod.intern_pool); } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index ef3ee3871b..8304e06b4c 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -260,7 +260,7 @@ const DbgInfoReloc = struct { } fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) error{OutOfMemory}!void { - const mod = function.bin_file.options.module.?; + const mod = function.bin_file.comp.module.?; switch (function.debug_output) { .dwarf => |dw| { const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (reloc.mcv) { @@ -289,7 +289,7 @@ const DbgInfoReloc = struct { } fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { - const mod = function.bin_file.options.module.?; + const mod = function.bin_file.comp.module.?; const is_ptr = switch (reloc.tag) { .dbg_var_ptr => true, .dbg_var_val => false, @@ -348,7 +348,7 @@ pub fn generate( @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const func = mod.funcInfo(func_index); const fn_owner_decl = mod.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); @@ -482,7 +482,7 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { } fn gen(self: *Self) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const cc = self.fn_type.fnCallingConvention(mod); if (cc != .Naked) { // push {fp, lr} @@ -642,7 +642,7 @@ fn gen(self: *Self) !void { } fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const air_tags = self.air.instructions.items(.tag); @@ -1010,7 +1010,7 @@ fn allocMem( /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst).childType(mod); if (!elem_ty.hasRuntimeBits(mod)) { @@ -1031,7 +1031,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); }; @@ -1118,7 +1118,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { } fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = switch (self.ret_mcv) { .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, .stack_offset => blk: { @@ -1151,7 +1151,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { } fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); @@ -1217,7 +1217,7 @@ fn trunc( operand_ty: Type, dest_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const info_a = operand_ty.intInfo(mod); const info_b = dest_ty.intInfo(mod); @@ -1281,7 +1281,7 @@ fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void { fn airNot(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; const operand_ty = self.typeOf(ty_op.operand); @@ -1377,7 +1377,7 @@ fn minMax( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM min/max on floats", .{}), .Vector => return self.fail("TODO ARM min/max on vectors", .{}), @@ -1586,7 +1586,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; @@ -1699,7 +1699,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = result: { const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; @@ -1863,7 +1863,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = result: { const lhs_ty = self.typeOf(extra.lhs); const rhs_ty = self.typeOf(extra.rhs); @@ -2019,7 +2019,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { } fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const optional_ty = self.typeOfIndex(inst); @@ -2042,7 +2042,7 @@ fn errUnionErr( error_union_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_ty = error_union_ty.errorUnionSet(mod); const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { @@ -2119,7 +2119,7 @@ fn errUnionPayload( error_union_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_ty = error_union_ty.errorUnionSet(mod); const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { @@ -2229,7 +2229,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { /// T to E!T fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = ty_op.ty.toType(); @@ -2253,7 +2253,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { /// E to E!T fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = ty_op.ty.toType(); @@ -2370,7 +2370,7 @@ fn ptrElemVal( ptr_ty: Type, maybe_inst: ?Air.Inst.Index, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = ptr_ty.childType(mod); const elem_size: u32 = @intCast(elem_ty.abiSize(mod)); @@ -2429,7 +2429,7 @@ fn ptrElemVal( } fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const slice_ty = self.typeOf(bin_op.lhs); const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { @@ -2472,7 +2472,7 @@ fn arrayElemVal( array_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = array_ty.childType(mod); const mcv = try array_bind.resolveToMcv(self); @@ -2528,7 +2528,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { } fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); const result: MCValue = if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { @@ -2662,7 +2662,7 @@ fn reuseOperand( } fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = ptr_ty.childType(mod); const elem_size: u32 = @intCast(elem_ty.abiSize(mod)); @@ -2739,7 +2739,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo } fn airLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const elem_ty = self.typeOfIndex(inst); const result: MCValue = result: { @@ -2768,7 +2768,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { } fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_size: u32 = @intCast(value_ty.abiSize(mod)); switch (ptr) { @@ -2888,7 +2888,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { return if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv = try self.resolveInst(operand); const ptr_ty = self.typeOf(operand); const struct_ty = ptr_ty.childType(mod); @@ -2912,7 +2912,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; const operand = extra.struct_operand; const index = extra.field_index; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const mcv = try self.resolveInst(operand); const struct_ty = self.typeOf(operand); @@ -3002,7 +3002,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { } fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { @@ -3396,7 +3396,7 @@ fn addSub( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3452,7 +3452,7 @@ fn mul( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3485,7 +3485,7 @@ fn divFloat( _ = rhs_ty; _ = maybe_inst; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3501,7 +3501,7 @@ fn divTrunc( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3544,7 +3544,7 @@ fn divFloor( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3592,7 +3592,7 @@ fn divExact( _ = rhs_ty; _ = maybe_inst; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3609,7 +3609,7 @@ fn rem( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3678,7 +3678,7 @@ fn modulo( _ = rhs_ty; _ = maybe_inst; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO ARM binary operations on floats", .{}), .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), @@ -3696,7 +3696,7 @@ fn wrappingArithmetic( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { @@ -3734,7 +3734,7 @@ fn bitwise( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { @@ -3779,7 +3779,7 @@ fn shiftExact( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { @@ -3818,7 +3818,7 @@ fn shiftNormal( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), .Int => { @@ -3861,7 +3861,7 @@ fn booleanOp( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Bool => { const lhs_immediate = try lhs_bind.resolveToImmediate(self); @@ -3895,7 +3895,7 @@ fn ptrArithmetic( rhs_ty: Type, maybe_inst: ?Air.Inst.Index, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lhs_ty.zigTypeTag(mod)) { .Pointer => { assert(rhs_ty.eql(Type.usize, mod)); @@ -3932,7 +3932,7 @@ fn ptrArithmetic( } fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); const tag: Mir.Inst.Tag = switch (abi_size) { @@ -3967,7 +3967,7 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) } fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); const tag: Mir.Inst.Tag = switch (abi_size) { @@ -4174,7 +4174,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { while (self.args[arg_index] == .none) arg_index += 1; self.arg_index = arg_index + 1; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty = self.typeOfIndex(inst); const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const src_index = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.src_index; @@ -4229,7 +4229,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const extra = self.air.extraData(Air.Call, pl_op.payload); const args: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]); const ty = self.typeOf(callee); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const fn_ty = switch (ty.zigTypeTag(mod)) { .Fn => ty, @@ -4380,7 +4380,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier } fn airRet(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); const ret_ty = self.fn_type.fnReturnType(mod); @@ -4412,7 +4412,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { } fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ptr = try self.resolveInst(un_op); const ptr_ty = self.typeOf(un_op); @@ -4473,7 +4473,7 @@ fn cmp( lhs_ty: Type, op: math.CompareOperator, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const int_ty = switch (lhs_ty.zigTypeTag(mod)) { .Optional => blk: { const payload_ty = lhs_ty.optionalChild(mod); @@ -4580,7 +4580,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const func = mod.funcInfo(ty_fn.func); // TODO emit debug info for function change _ = func; @@ -4795,7 +4795,7 @@ fn isNull( operand_bind: ReadArg.Bind, operand_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (operand_ty.isPtrLikeOptional(mod)) { assert(operand_ty.abiSize(mod) == 4); @@ -4829,7 +4829,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { } fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -4856,7 +4856,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { } fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -4876,7 +4876,7 @@ fn isErr( error_union_bind: ReadArg.Bind, error_union_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const error_type = error_union_ty.errorUnionSet(mod); if (error_type.errorSetIsEmpty(mod)) { @@ -4918,7 +4918,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { } fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -4945,7 +4945,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { } fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand_ptr = try self.resolveInst(un_op); @@ -5160,7 +5160,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { } fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const block_data = self.blocks.getPtr(block).?; if (self.typeOf(operand).hasRuntimeBits(mod)) { @@ -5331,7 +5331,7 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { } fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); switch (mcv) { .dead => unreachable, @@ -5493,7 +5493,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro } fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (mcv) { .dead => unreachable, .unreach, .none => return, // Nothing to do. @@ -5740,7 +5740,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void } fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); switch (mcv) { .dead => unreachable, @@ -5896,7 +5896,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { } fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const ptr_ty = self.typeOf(ty_op.operand); @@ -6015,7 +6015,7 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const vector_ty = self.typeOfIndex(inst); const len = vector_ty.vectorLen(mod); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; @@ -6066,7 +6066,7 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { const result: MCValue = result: { const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; const error_union_ty = self.typeOf(pl_op.operand); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const error_union_size: u32 = @intCast(error_union_ty.abiSize(mod)); const error_union_align = error_union_ty.abiAlignment(mod); @@ -6097,7 +6097,7 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { } fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; // If the type has no codegen bits, no need to store it. const inst_ty = self.typeOf(inst); @@ -6125,7 +6125,7 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, @@ -6161,7 +6161,7 @@ const CallMCValues = struct { /// Caller must call `CallMCValues.deinit`. fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const fn_info = mod.typeToFunc(fn_ty).?; const cc = fn_info.cc; @@ -6312,11 +6312,11 @@ fn parseRegName(name: []const u8) ?Register { } fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOf(inst, &mod.intern_pool); } fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOfIndex(inst, &mod.intern_pool); } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index c217288e63..4de9313a94 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -229,7 +229,7 @@ pub fn generate( @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const func = mod.funcInfo(func_index); const fn_owner_decl = mod.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); @@ -350,7 +350,7 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { } fn gen(self: *Self) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const cc = self.fn_type.fnCallingConvention(mod); if (cc != .Naked) { // TODO Finish function prologue and epilogue for riscv64. @@ -474,7 +474,7 @@ fn gen(self: *Self) !void { } fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const air_tags = self.air.instructions.items(.tag); @@ -805,7 +805,7 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignme /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst).childType(mod); const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); @@ -816,7 +816,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst); const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); @@ -893,7 +893,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const operand_ty = self.typeOf(ty_op.operand); const operand = try self.resolveInst(ty_op.operand); const info_a = operand_ty.intInfo(mod); @@ -1069,7 +1069,7 @@ fn binOp( lhs_ty: Type, rhs_ty: Type, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (tag) { // Arithmetic operations on integers and floats .add, @@ -1332,7 +1332,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const optional_ty = self.typeOfIndex(inst); // Optional with a zero-bit payload type is just a boolean true @@ -1506,7 +1506,7 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind } fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = ptr_ty.childType(mod); switch (ptr) { .none => unreachable, @@ -1532,7 +1532,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo } fn airLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const elem_ty = self.typeOfIndex(inst); const result: MCValue = result: { @@ -1633,7 +1633,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { } fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; const ty = arg.ty.toType(); const owner_decl = mod.funcOwnerDeclIndex(self.func_index); @@ -1710,7 +1710,7 @@ fn airFence(self: *Self) !void { } fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const fn_ty = self.typeOf(pl_op.operand); @@ -1812,7 +1812,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier } fn ret(self: *Self, mcv: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ret_ty = self.fn_type.fnReturnType(mod); try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); // Just add space for an instruction, patch this later @@ -1843,7 +1843,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); const ty = self.typeOf(bin_op.lhs); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; assert(ty.eql(self.typeOf(bin_op.rhs), mod)); if (ty.zigTypeTag(mod) == .ErrorSet) return self.fail("TODO implement cmp for errors", .{}); @@ -1887,7 +1887,7 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const func = mod.funcInfo(ty_fn.func); // TODO emit debug info for function change _ = func; @@ -2125,7 +2125,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { const block_data = self.blocks.getPtr(block).?; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (self.typeOf(operand).hasRuntimeBits(mod)) { const operand_mcv = try self.resolveInst(operand); const block_mcv = block_data.mcv; @@ -2508,7 +2508,7 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const vector_ty = self.typeOfIndex(inst); const len = vector_ty.vectorLen(mod); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; @@ -2553,7 +2553,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { } fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; // If the type has no codegen bits, no need to store it. const inst_ty = self.typeOf(inst); @@ -2581,7 +2581,7 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, @@ -2617,7 +2617,7 @@ const CallMCValues = struct { /// Caller must call `CallMCValues.deinit`. fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const fn_info = mod.typeToFunc(fn_ty).?; const cc = fn_info.cc; @@ -2739,11 +2739,11 @@ fn parseRegName(name: []const u8) ?Register { } fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOf(inst, &mod.intern_pool); } fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOfIndex(inst, &mod.intern_pool); } diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 79dd6ec8d8..f252563b35 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -272,7 +272,7 @@ pub fn generate( @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const func = mod.funcInfo(func_index); const fn_owner_decl = mod.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); @@ -364,7 +364,7 @@ pub fn generate( } fn gen(self: *Self) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const cc = self.fn_type.fnCallingConvention(mod); if (cc != .Naked) { // TODO Finish function prologue and epilogue for sparc64. @@ -492,7 +492,7 @@ fn gen(self: *Self) !void { } fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const air_tags = self.air.instructions.items(.tag); @@ -762,7 +762,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const lhs = try self.resolveInst(extra.lhs); const rhs = try self.resolveInst(extra.rhs); @@ -840,7 +840,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const vector_ty = self.typeOfIndex(inst); const len = vector_ty.vectorLen(mod); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; @@ -874,7 +874,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { } fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const ptr_ty = self.typeOf(ty_op.operand); @@ -1011,7 +1011,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { } fn airArg(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const arg_index = self.arg_index; self.arg_index += 1; @@ -1206,7 +1206,7 @@ fn airBreakpoint(self: *Self) !void { } fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; // We have hardware byteswapper in SPARCv9, don't let mainstream compilers mislead you. @@ -1298,7 +1298,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier const extra = self.air.extraData(Air.Call, pl_op.payload); const args = @as([]const Air.Inst.Ref, @ptrCast(self.air.extra[extra.end .. extra.end + extra.data.args_len])); const ty = self.typeOf(callee); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const fn_ty = switch (ty.zigTypeTag(mod)) { .Fn => ty, .Pointer => ty.childType(mod), @@ -1430,7 +1430,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const lhs = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); @@ -1662,7 +1662,7 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const func = mod.funcInfo(ty_fn.func); // TODO emit debug info for function change _ = func; @@ -1758,7 +1758,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const operand_ty = self.typeOf(ty_op.operand); const operand = try self.resolveInst(ty_op.operand); const info_a = operand_ty.intInfo(mod); @@ -1819,7 +1819,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { } fn airLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const elem_ty = self.typeOfIndex(inst); const elem_size = elem_ty.abiSize(mod); @@ -1903,7 +1903,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { const rhs = try self.resolveInst(bin_op.rhs); const lhs_ty = self.typeOf(bin_op.lhs); const rhs_ty = self.typeOf(bin_op.rhs); - assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?)); + assert(lhs_ty.eql(rhs_ty, self.bin_file.comp.module.?)); if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); @@ -2045,7 +2045,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { //const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const lhs = try self.resolveInst(extra.lhs); const rhs = try self.resolveInst(extra.rhs); @@ -2109,7 +2109,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { fn airNot(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); @@ -2341,7 +2341,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const lhs = try self.resolveInst(extra.lhs); const rhs = try self.resolveInst(extra.rhs); @@ -2446,7 +2446,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { } fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const is_volatile = false; // TODO const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; @@ -2571,7 +2571,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const operand = extra.struct_operand; const index = extra.field_index; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv = try self.resolveInst(operand); const struct_ty = self.typeOf(operand); const struct_field_offset = @as(u32, @intCast(struct_ty.structFieldOffset(index, mod))); @@ -2704,7 +2704,7 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { } fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.typeOf(ty_op.operand); @@ -2718,7 +2718,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { } fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = self.typeOf(ty_op.operand); @@ -2732,7 +2732,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { /// E to E!T fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const error_union_ty = ty_op.ty.toType(); @@ -2753,7 +2753,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { } fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { const optional_ty = self.typeOfIndex(inst); @@ -2793,7 +2793,7 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: Alignme /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst).childType(mod); if (!elem_ty.hasRuntimeBits(mod)) { @@ -2813,7 +2813,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { } fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = self.typeOfIndex(inst); const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); @@ -2860,7 +2860,7 @@ fn binOp( rhs_ty: Type, metadata: ?BinOpMetadata, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (tag) { .add, .sub, @@ -3401,7 +3401,7 @@ fn binOpRegister( fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { const block_data = self.blocks.getPtr(block).?; - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (self.typeOf(operand).hasRuntimeBits(mod)) { const operand_mcv = try self.resolveInst(operand); const block_mcv = block_data.mcv; @@ -3521,7 +3521,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { /// Given an error union, returns the payload fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_ty = error_union_ty.errorUnionSet(mod); const payload_ty = error_union_ty.errorUnionPayload(mod); if (err_ty.errorSetIsEmpty(mod)) { @@ -3591,7 +3591,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live } fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; const ty = arg.ty.toType(); const owner_decl = mod.funcOwnerDeclIndex(self.func_index); @@ -3740,7 +3740,7 @@ fn genLoadASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Reg } fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (mcv) { .dead => unreachable, .unreach, .none => return, // Nothing to do. @@ -3951,7 +3951,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void } fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); switch (mcv) { .dead => unreachable, @@ -4125,7 +4125,7 @@ fn genStoreASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Re } fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv: MCValue = switch (try codegen.genTypedValue( self.bin_file, self.src_loc, @@ -4161,7 +4161,7 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { } fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const error_type = ty.errorUnionSet(mod); const payload_type = ty.errorUnionPayload(mod); @@ -4259,7 +4259,7 @@ fn jump(self: *Self, inst: Mir.Inst.Index) !void { } fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const elem_ty = ptr_ty.childType(mod); const elem_size = elem_ty.abiSize(mod); @@ -4330,7 +4330,7 @@ fn minMax( lhs_ty: Type, rhs_ty: Type, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; assert(lhs_ty.eql(rhs_ty, mod)); switch (lhs_ty.zigTypeTag(mod)) { .Float => return self.fail("TODO min/max on floats", .{}), @@ -4450,7 +4450,7 @@ fn realStackOffset(off: u32) u32 { /// Caller must call `CallMCValues.deinit`. fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const fn_info = mod.typeToFunc(fn_ty).?; const cc = fn_info.cc; @@ -4542,7 +4542,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) } fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty = self.typeOf(ref); // If the type has no codegen bits, no need to store it. @@ -4559,7 +4559,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { } fn ret(self: *Self, mcv: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ret_ty = self.fn_type.fnReturnType(mod); try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); @@ -4661,7 +4661,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void } fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = value_ty.abiSize(mod); switch (ptr) { @@ -4703,7 +4703,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { return if (self.liveness.isUnused(inst)) .dead else result: { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mcv = try self.resolveInst(operand); const ptr_ty = self.typeOf(operand); const struct_ty = ptr_ty.childType(mod); @@ -4745,7 +4745,7 @@ fn trunc( operand_ty: Type, dest_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const info_a = operand_ty.intInfo(mod); const info_b = dest_ty.intInfo(mod); @@ -4866,11 +4866,11 @@ fn wantSafety(self: *Self) bool { } fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOf(inst, &mod.intern_pool); } fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOfIndex(inst, &mod.intern_pool); } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index e0be273c26..819cc3e9a0 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1210,7 +1210,7 @@ pub fn generate( debug_output: codegen.DebugInfoOutput, ) codegen.CodeGenError!codegen.Result { _ = src_loc; - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const func = mod.funcInfo(func_index); var code_gen: CodeGen = .{ .gpa = bin_file.allocator, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 0a4c9844dc..9a4c73c74d 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -131,7 +131,7 @@ const Owner = union(enum) { fn getSymbolIndex(owner: Owner, ctx: *Self) !u32 { switch (owner) { .func_index => |func_index| { - const mod = ctx.bin_file.options.module.?; + const mod = ctx.bin_file.comp.module.?; const decl_index = mod.funcOwnerDeclIndex(func_index); if (ctx.bin_file.cast(link.File.Elf)) |elf_file| { return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index); @@ -799,7 +799,7 @@ pub fn generate( @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const func = mod.funcInfo(func_index); const fn_owner_decl = mod.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); @@ -1060,7 +1060,7 @@ fn formatDecl( } fn fmtDecl(self: *Self, decl_index: InternPool.DeclIndex) std.fmt.Formatter(formatDecl) { return .{ .data = .{ - .mod = self.bin_file.options.module.?, + .mod = self.bin_file.comp.module.?, .decl_index = decl_index, } }; } @@ -1077,7 +1077,7 @@ fn formatAir( ) @TypeOf(writer).Error!void { @import("../../print_air.zig").dumpInst( data.inst, - data.self.bin_file.options.module.?, + data.self.bin_file.comp.module.?, data.self.air, data.self.liveness, ); @@ -1683,7 +1683,7 @@ fn asmMemoryRegisterImmediate( } fn gen(self: *Self) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const fn_info = mod.typeToFunc(self.fn_type).?; const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); if (cc != .Naked) { @@ -1885,7 +1885,7 @@ fn gen(self: *Self) InnerError!void { } fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const air_tags = self.air.instructions.items(.tag); @@ -2167,7 +2167,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { } fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (lazy_sym.ty.zigTypeTag(mod)) { .Enum => { const enum_ty = lazy_sym.ty; @@ -2418,7 +2418,7 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { /// Use a pointer instruction as the basis for allocating stack memory. fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ptr_ty = self.typeOfIndex(inst); const val_ty = ptr_ty.childType(mod); return self.allocFrameIndex(FrameAlloc.init(.{ @@ -2438,7 +2438,7 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { } fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = math.cast(u32, ty.abiSize(mod)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); }; @@ -2471,7 +2471,7 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b } fn regClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return switch (ty.zigTypeTag(mod)) { .Float => switch (ty.floatBits(self.target.*)) { 80 => abi.RegisterClass.x87, @@ -2884,7 +2884,7 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { } fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = result: { const src_ty = self.typeOf(ty_op.operand); @@ -2975,7 +2975,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { } fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const dst_ty = self.typeOfIndex(inst); @@ -3102,7 +3102,7 @@ fn airIntFromBool(self: *Self, inst: Air.Inst.Index) !void { } fn airSlice(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; @@ -3131,7 +3131,7 @@ fn airUnOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { } fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs); @@ -3172,7 +3172,7 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void } fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const air_tag = self.air.instructions.items(.tag); const air_data = self.air.instructions.items(.data); @@ -3206,7 +3206,7 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { } fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const result = result: { const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; @@ -3432,7 +3432,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { } fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ty = self.typeOf(bin_op.lhs); if (ty.zigTypeTag(mod) == .Vector or ty.abiSize(mod) > 8) return self.fail( @@ -3515,7 +3515,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { } fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ty = self.typeOf(bin_op.lhs); if (ty.zigTypeTag(mod) == .Vector or ty.abiSize(mod) > 8) return self.fail( @@ -3591,7 +3591,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { } fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ty = self.typeOf(bin_op.lhs); @@ -3731,7 +3731,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { } fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const result: MCValue = result: { @@ -3792,7 +3792,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { } fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const result: MCValue = result: { @@ -3871,7 +3871,7 @@ fn genSetFrameTruncatedOverflowCompare( src_mcv: MCValue, overflow_cc: ?Condition, ) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const src_lock = switch (src_mcv) { .register => |reg| self.register_manager.lockReg(reg), else => null, @@ -3935,7 +3935,7 @@ fn genSetFrameTruncatedOverflowCompare( } fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; const tuple_ty = self.typeOfIndex(inst); @@ -4169,7 +4169,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { /// Clobbers .rax and .rdx registers. /// Quotient is saved in .rax and remainder in .rdx. fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); const bit_size: u32 = @intCast(self.regBitSize(ty)); if (abi_size > 8) { @@ -4219,7 +4219,7 @@ fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue /// Always returns a register. /// Clobbers .rax and .rdx registers. fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); const int_info = ty.intInfo(mod); const dividend = switch (lhs) { @@ -4271,7 +4271,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa } fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const air_tags = self.air.instructions.items(.tag); @@ -4546,7 +4546,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { } fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = result: { const pl_ty = self.typeOfIndex(inst); @@ -4592,7 +4592,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { } fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result = result: { const dst_ty = self.typeOfIndex(inst); @@ -4626,7 +4626,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { } fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const err_union_ty = self.typeOf(ty_op.operand); const err_ty = err_union_ty.errorUnionSet(mod); @@ -4678,7 +4678,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { // *(E!T) -> E fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const src_ty = self.typeOf(ty_op.operand); @@ -4725,7 +4725,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { } fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = result: { const src_ty = self.typeOf(ty_op.operand); @@ -4785,7 +4785,7 @@ fn genUnwrapErrUnionPayloadMir( err_union_ty: Type, err_union: MCValue, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const payload_ty = err_union_ty.errorUnionPayload(mod); const result: MCValue = result: { @@ -4833,7 +4833,7 @@ fn genUnwrapErrUnionPayloadPtrMir( ptr_ty: Type, ptr_mcv: MCValue, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_union_ty = ptr_ty.childType(mod); const payload_ty = err_union_ty.errorUnionPayload(mod); @@ -4867,7 +4867,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { } fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = result: { const pl_ty = self.typeOf(ty_op.operand); @@ -4921,7 +4921,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { /// T to E!T fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const eu_ty = ty_op.ty.toType(); @@ -4944,7 +4944,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { /// E to E!T fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const eu_ty = ty_op.ty.toType(); @@ -5003,7 +5003,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { } fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const src_ty = self.typeOf(ty_op.operand); @@ -5071,7 +5071,7 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi } fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const slice_ty = self.typeOf(lhs); const slice_mcv = try self.resolveInst(lhs); const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) { @@ -5107,7 +5107,7 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { } fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const result: MCValue = result: { @@ -5132,7 +5132,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { } fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const result: MCValue = result: { @@ -5246,7 +5246,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { } fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_ty = self.typeOf(bin_op.lhs); @@ -5296,7 +5296,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { } fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; @@ -5341,7 +5341,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { } fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_union_ty = self.typeOf(bin_op.lhs); const union_ty = ptr_union_ty.childType(mod); @@ -5385,7 +5385,7 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { } fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const tag_ty = self.typeOfIndex(inst); @@ -5439,7 +5439,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { } fn airClz(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result = result: { const dst_ty = self.typeOfIndex(inst); @@ -5598,7 +5598,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { } fn airCtz(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result = result: { const dst_ty = self.typeOfIndex(inst); @@ -5716,7 +5716,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { } fn airPopCount(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const result: MCValue = result: { try self.spillEflagsIfOccupied(); @@ -5779,7 +5779,7 @@ fn genPopCount( src_mcv: MCValue, dst_contains_src: bool, ) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const src_abi_size: u32 = @intCast(src_ty.abiSize(mod)); if (self.hasFeature(.popcnt)) return self.genBinOpMir( @@ -5871,7 +5871,7 @@ fn genByteSwap( src_mcv: MCValue, mem_ok: bool, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; if (src_ty.zigTypeTag(mod) == .Vector) return self.fail( @@ -5962,7 +5962,7 @@ fn genByteSwap( } fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const src_ty = self.typeOf(ty_op.operand); @@ -5984,7 +5984,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { } fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const src_ty = self.typeOf(ty_op.operand); @@ -6106,7 +6106,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { } fn floatSign(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: Type) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; const result = result: { @@ -6282,7 +6282,7 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: RoundMode) !void { } fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(mod)) { .Float => switch (ty.floatBits(self.target.*)) { 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, @@ -6314,7 +6314,7 @@ fn getRoundTag(self: *Self, ty: Type) ?Mir.Inst.FixedTag { } fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (self.getRoundTag(ty)) |_| return .none; if (ty.zigTypeTag(mod) != .Float) @@ -6338,7 +6338,7 @@ fn genRoundLibcall(self: *Self, ty: Type, src_mcv: MCValue, mode: RoundMode) !MC } fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: RoundMode) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const mir_tag = self.getRoundTag(ty) orelse { const result = try self.genRoundLibcall(ty, src_mcv, mode); return self.genSetReg(dst_reg, ty, result); @@ -6380,7 +6380,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: Ro } fn airAbs(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const ty = self.typeOf(ty_op.operand); @@ -6520,7 +6520,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { } fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ty = self.typeOf(un_op); const abi_size: u32 = @intCast(ty.abiSize(mod)); @@ -6765,7 +6765,7 @@ fn reuseOperandAdvanced( } fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ptr_info = ptr_ty.ptrInfo(mod); const val_ty = Type.fromInterned(ptr_info.child); @@ -6864,7 +6864,7 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn } fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const dst_ty = ptr_ty.childType(mod); if (!dst_ty.hasRuntimeBitsIgnoreComptime(mod)) return; switch (ptr_mcv) { @@ -6905,7 +6905,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro } fn airLoad(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const elem_ty = self.typeOfIndex(inst); const result: MCValue = result: { @@ -6962,7 +6962,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { } fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ptr_info = ptr_ty.ptrInfo(mod); const src_ty = Type.fromInterned(ptr_info.child); if (!src_ty.hasRuntimeBitsIgnoreComptime(mod)) return; @@ -7059,7 +7059,7 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In } fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const src_ty = ptr_ty.childType(mod); if (!src_ty.hasRuntimeBitsIgnoreComptime(mod)) return; switch (ptr_mcv) { @@ -7100,7 +7100,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr } fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; result: { @@ -7138,7 +7138,7 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { } fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ptr_field_ty = self.typeOfIndex(inst); const ptr_container_ty = self.typeOf(operand); const ptr_container_ty_info = ptr_container_ty.ptrInfo(mod); @@ -7163,7 +7163,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 } fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; const result: MCValue = result: { @@ -7451,7 +7451,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { } fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; @@ -7470,7 +7470,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { } fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const src_ty = self.typeOf(src_air); if (src_ty.zigTypeTag(mod) == .Vector) return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(mod)}); @@ -7558,7 +7558,7 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: } fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(mod) }); switch (dst_mcv) { @@ -7605,7 +7605,7 @@ fn genShiftBinOpMir( lhs_mcv: MCValue, shift_mcv: MCValue, ) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const rhs_mcv: MCValue = rhs: { switch (shift_mcv) { .immediate => |imm| switch (imm) { @@ -7975,7 +7975,7 @@ fn genShiftBinOp( lhs_ty: Type, rhs_ty: Type, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (lhs_ty.zigTypeTag(mod) == .Vector) return self.fail("TODO implement genShiftBinOp for {}", .{ lhs_ty.fmt(mod), }); @@ -8041,7 +8041,7 @@ fn genMulDivBinOp( lhs_mcv: MCValue, rhs_mcv: MCValue, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; if (dst_ty.zigTypeTag(mod) == .Vector or dst_ty.zigTypeTag(mod) == .Float) return self.fail( "TODO implement genMulDivBinOp for {s} from {} to {}", .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) }, @@ -8283,7 +8283,7 @@ fn genBinOp( lhs_air: Air.Inst.Ref, rhs_air: Air.Inst.Ref, ) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const lhs_ty = self.typeOf(lhs_air); const rhs_ty = self.typeOf(rhs_air); const abi_size: u32 = @intCast(lhs_ty.abiSize(mod)); @@ -10015,7 +10015,7 @@ fn genBinOpMir( dst_mcv: MCValue, src_mcv: MCValue, ) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); try self.spillEflagsIfOccupied(); switch (dst_mcv) { @@ -10435,7 +10435,7 @@ fn genBinOpMir( /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. /// Does not support byte-size operands. fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(dst_ty.abiSize(mod)); try self.spillEflagsIfOccupied(); switch (dst_mcv) { @@ -10560,7 +10560,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M } fn airArg(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; // skip zero-bit arguments as they don't have a corresponding arg instruction var arg_index = self.arg_index; while (self.args[arg_index] == .none) arg_index += 1; @@ -10593,7 +10593,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { } fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (self.debug_output) { .dwarf => |dw| { const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { @@ -10629,7 +10629,7 @@ fn genVarDbgInfo( mcv: MCValue, name: [:0]const u8, ) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const is_ptr = switch (tag) { .dbg_var_ptr => true, .dbg_var_val => false, @@ -10748,7 +10748,7 @@ fn genCall(self: *Self, info: union(enum) { callee: []const u8, }, }, arg_types: []const Type, args: []const MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const fn_ty = switch (info) { .air => |callee| fn_info: { @@ -10969,7 +10969,7 @@ fn genCall(self: *Self, info: union(enum) { } fn airRet(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ret_ty = self.fn_type.fnReturnType(mod); @@ -11018,7 +11018,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { } fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ty = self.typeOf(bin_op.lhs); @@ -11412,7 +11412,7 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { } fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); @@ -11551,7 +11551,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { } fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); switch (mcv) { .eflags => |cc| { @@ -11624,7 +11624,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { } fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (opt_mcv) { .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() }, else => {}, @@ -11732,7 +11732,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC } fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const opt_ty = ptr_ty.childType(mod); const pl_ty = opt_ty.optionalChild(mod); @@ -11768,7 +11768,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) } fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const err_ty = eu_ty.errorUnionSet(mod); if (err_ty.errorSetIsEmpty(mod)) return MCValue{ .immediate = 0 }; // always false @@ -11815,7 +11815,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) } fn isErrPtr(self: *Self, maybe_inst: ?Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const eu_ty = ptr_ty.childType(mod); const err_ty = eu_ty.errorUnionSet(mod); if (err_ty.errorSetIsEmpty(mod)) return MCValue{ .immediate = 0 }; // always false @@ -12097,7 +12097,7 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { } fn airBr(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br; const block_ty = self.typeOfIndex(br.block_inst); @@ -12158,7 +12158,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { } fn airAsm(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Asm, ty_pl.payload); const clobbers_len: u31 = @truncate(extra.data.flags); @@ -12865,7 +12865,7 @@ const MoveStrategy = union(enum) { } }; fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !MoveStrategy { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; switch (class) { .general_purpose, .segment => return .{ .move = .{ ._, .mov } }, .x87 => return .x87_load_store, @@ -13164,7 +13164,7 @@ fn moveStrategy(self: *Self, ty: Type, class: Register.Class, aligned: bool) !Mo } fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; defer if (src_lock) |lock| self.register_manager.unlockReg(lock); @@ -13262,7 +13262,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError } fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); if (ty.bitSize(mod) > dst_reg.bitSize()) return self.fail("genSetReg called with a value larger than dst_reg", .{}); @@ -13561,7 +13561,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr } fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCValue) InnerError!void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size: u32 = @intCast(ty.abiSize(mod)); const dst_ptr_mcv: MCValue = switch (base) { .none => .{ .immediate = @bitCast(@as(i64, disp)) }, @@ -13922,7 +13922,7 @@ fn airIntFromPtr(self: *Self, inst: Air.Inst.Index) !void { } fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const dst_ty = self.typeOfIndex(inst); const src_ty = self.typeOf(ty_op.operand); @@ -13980,7 +13980,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { } fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const slice_ty = self.typeOfIndex(inst); @@ -14003,7 +14003,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { } fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const dst_ty = self.typeOfIndex(inst); @@ -14082,7 +14082,7 @@ fn airFloatFromInt(self: *Self, inst: Air.Inst.Index) !void { } fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const dst_ty = self.typeOfIndex(inst); @@ -14153,7 +14153,7 @@ fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void { } fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; @@ -14249,7 +14249,7 @@ fn atomicOp( rmw_op: ?std.builtin.AtomicRmwOp, order: std.builtin.AtomicOrder, ) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ptr_lock = switch (ptr_mcv) { .register => |reg| self.register_manager.lockReg(reg), else => null, @@ -14653,7 +14653,7 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr } fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; result: { @@ -14781,7 +14781,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { } fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); @@ -14836,7 +14836,7 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { } fn airTagName(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const inst_ty = self.typeOfIndex(inst); const enum_ty = self.typeOf(un_op); @@ -14878,7 +14878,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { } fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const err_ty = self.typeOf(un_op); @@ -14980,7 +14980,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { } fn airSplat(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const vector_ty = self.typeOfIndex(inst); const vector_len = vector_ty.vectorLen(mod); @@ -15332,7 +15332,7 @@ fn airShuffle(self: *Self, inst: Air.Inst.Index) !void { } fn airReduce(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce; const result: MCValue = result: { @@ -15389,7 +15389,7 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { } fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const result_ty = self.typeOfIndex(inst); const len: usize = @intCast(result_ty.arrayLen(mod)); const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; @@ -15562,7 +15562,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { } fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; @@ -15613,7 +15613,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { } fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = self.air.extraData(Air.Bin, pl_op.payload).data; const ty = self.typeOfIndex(inst); @@ -15780,7 +15780,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { } fn airVaStart(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const va_list_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty; const ptr_anyopaque_ty = try mod.singleMutPtrType(Type.anyopaque); @@ -15833,7 +15833,7 @@ fn airVaStart(self: *Self, inst: Air.Inst.Index) !void { } fn airVaArg(self: *Self, inst: Air.Inst.Index) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const ty = self.typeOfIndex(inst); const promote_ty = self.promoteVarArg(ty); @@ -16042,7 +16042,7 @@ fn airVaEnd(self: *Self, inst: Air.Inst.Index) !void { } fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ty = self.typeOf(ref); // If the type has no codegen bits, no need to store it. @@ -16116,7 +16116,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV } fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl(mod))) { .mcv => |mcv| switch (mcv) { .none => .none, @@ -16156,7 +16156,7 @@ fn resolveCallingConventionValues( var_args: []const Type, stack_frame_base: FrameIndex, ) !CallMCValues { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const ip = &mod.intern_pool; const cc = fn_info.cc; const param_types = try self.gpa.alloc(Type, fn_info.param_types.len + var_args.len); @@ -16468,7 +16468,7 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { } fn memSize(self: *Self, ty: Type) Memory.Size { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return switch (ty.zigTypeTag(mod)) { .Float => Memory.Size.fromBitSize(ty.floatBits(self.target.*)), else => Memory.Size.fromSize(@intCast(ty.abiSize(mod))), @@ -16476,7 +16476,7 @@ fn memSize(self: *Self, ty: Type) Memory.Size { } fn splitType(self: *Self, ty: Type) ![2]Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const classes = mem.sliceTo(&abi.classifySystemV(ty, mod, .other), .none); var parts: [2]Type = undefined; if (classes.len == 2) for (&parts, classes, 0..) |*part, class, part_i| { @@ -16505,7 +16505,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type { /// Truncates the value in the register in place. /// Clobbers any remaining bits. fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const int_info = if (ty.isAbiInt(mod)) ty.intInfo(mod) else std.builtin.Type.Int{ .signedness = .unsigned, .bits = @intCast(ty.bitSize(mod)), @@ -16550,7 +16550,7 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { } fn regBitSize(self: *Self, ty: Type) u64 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const abi_size = ty.abiSize(mod); return switch (ty.zigTypeTag(mod)) { else => switch (abi_size) { @@ -16569,7 +16569,7 @@ fn regBitSize(self: *Self, ty: Type) u64 { } fn regExtraBits(self: *Self, ty: Type) u64 { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.regBitSize(ty) - ty.bitSize(mod); } @@ -16584,12 +16584,12 @@ fn hasAllFeatures(self: *Self, features: anytype) bool { } fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOf(inst, &mod.intern_pool); } fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; return self.air.typeOfIndex(inst, &mod.intern_pool); } @@ -16641,7 +16641,7 @@ fn floatLibcAbiSuffix(ty: Type) []const u8 { } fn promoteInt(self: *Self, ty: Type) Type { - const mod = self.bin_file.options.module.?; + const mod = self.bin_file.comp.module.?; const int_info: InternPool.Key.IntType = switch (ty.toIntern()) { .bool_type => .{ .signedness = .unsigned, .bits = 1 }, else => if (ty.isAbiInt(mod)) ty.intInfo(mod) else return ty, diff --git a/src/codegen.zig b/src/codegen.zig index 5efde3985c..54bdf295b3 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -110,7 +110,7 @@ pub fn generateLazySymbol( const target = bin_file.options.target; const endian = target.cpu.arch.endian(); - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; log.debug("generateLazySymbol: kind = {s}, ty = {}", .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(mod), @@ -165,7 +165,7 @@ pub fn generateSymbol( const tracy = trace(@src()); defer tracy.end(); - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const ip = &mod.intern_pool; const typed_value = arg_tv; @@ -662,7 +662,7 @@ fn lowerParentPtr( debug_output: DebugInfoOutput, reloc_info: RelocInfo, ) CodeGenError!Result { - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr; assert(ptr.len == .none); return switch (ptr.addr) { @@ -766,7 +766,7 @@ fn lowerAnonDeclRef( ) CodeGenError!Result { _ = debug_output; const target = bin_file.options.target; - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8); const decl_val = anon_decl.val; @@ -812,7 +812,7 @@ fn lowerDeclRef( _ = src_loc; _ = debug_output; const target = bin_file.options.target; - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const ptr_width = target.ptrBitWidth(); const decl = mod.declPtr(decl_index); @@ -902,7 +902,7 @@ fn genDeclRef( tv: TypedValue, ptr_decl_index: InternPool.DeclIndex, ) CodeGenError!GenResult { - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(mod), tv.val.fmtValue(tv.ty, mod) }); const target = bin_file.options.target; @@ -1010,7 +1010,7 @@ fn genUnnamedConst( tv: TypedValue, owner_decl_index: InternPool.DeclIndex, ) CodeGenError!GenResult { - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmt(mod), tv.val.fmtValue(tv.ty, mod) }); const target = bin_file.options.target; @@ -1038,7 +1038,7 @@ pub fn genTypedValue( arg_tv: TypedValue, owner_decl_index: InternPool.DeclIndex, ) CodeGenError!GenResult { - const mod = bin_file.options.module.?; + const mod = bin_file.comp.module.?; const typed_value = arg_tv; log.debug("genTypedValue: ty = {}, val = {}", .{ diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 522da0f8c9..40fffcfd5f 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1227,7 +1227,7 @@ pub const Object = struct { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const mod = comp.bin_file.options.module.?; + const mod = comp.module.?; const cache_dir = mod.zig_cache_artifact_directory; if (std.debug.runtime_safety and !try self.builder.verify()) { -- cgit v1.2.3 From b162c3c820d8a6446bbdfba90b3c135ebcd76fcb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 13 Dec 2023 15:26:22 -0700 Subject: update bin_file.options references in Module (Zcu) --- src/Module.zig | 14 +++++--------- src/codegen/llvm.zig | 13 ++++++++++--- src/link/Coff.zig | 3 +++ 3 files changed, 18 insertions(+), 12 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Module.zig b/src/Module.zig index 018037a46a..aa107ea3f7 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3335,7 +3335,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaEr const comp = mod.comp; - const no_bin_file = (comp.bin_file.options.emit == null and + const no_bin_file = (comp.bin_file == null and comp.emit_asm == null and comp.emit_llvm_ir == null and comp.emit_llvm_bc == null); @@ -4311,14 +4311,14 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err 1 => blk: { // test decl with no name. Skip the part where we check against // the test name filter. - if (!comp.bin_file.options.is_test) break :blk false; + if (!comp.config.is_test) break :blk false; if (decl_mod != mod.main_mod) break :blk false; try mod.test_functions.put(gpa, new_decl_index, {}); break :blk true; }, else => blk: { if (!is_named_test) break :blk false; - if (!comp.bin_file.options.is_test) break :blk false; + if (!comp.config.is_test) break :blk false; if (decl_mod != mod.main_mod) break :blk false; if (comp.test_filter) |test_filter| { if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) { @@ -4627,7 +4627,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato // If we don't get an error return trace from a caller, create our own. if (func.analysis(ip).calls_or_awaits_errorable_fn and - mod.comp.bin_file.options.error_return_tracing and + mod.comp.config.error_tracing and !sema.fn_ret_ty.isError(mod)) { sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { @@ -5475,7 +5475,7 @@ pub fn populateTestFunctions( pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { const comp = mod.comp; - const no_bin_file = (comp.bin_file.options.emit == null and + const no_bin_file = (comp.bin_file == null and comp.emit_asm == null and comp.emit_llvm_ir == null and comp.emit_llvm_bc == null); @@ -5597,10 +5597,6 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u } } -pub fn wantDllExports(mod: Module) bool { - return mod.comp.bin_file.options.dll_export_fns and mod.getTarget().os.tag == .windows; -} - pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export { if (mod.decl_exports.get(decl_index)) |l| { return l.items; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 40fffcfd5f..beb3e5e9f6 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -15,6 +15,7 @@ const link = @import("../link.zig"); const Compilation = @import("../Compilation.zig"); const build_options = @import("build_options"); const Module = @import("../Module.zig"); +const Zcu = Module; const InternPool = @import("../InternPool.zig"); const Package = @import("../Package.zig"); const TypedValue = @import("../TypedValue.zig"); @@ -1723,7 +1724,7 @@ pub const Object = struct { try global_index.rename(decl_name, &self.builder); global_index.setLinkage(.external, &self.builder); global_index.setUnnamedAddr(.default, &self.builder); - if (mod.wantDllExports()) global_index.setDllStorageClass(.default, &self.builder); + if (wantDllExports(mod)) global_index.setDllStorageClass(.default, &self.builder); if (self.di_map.get(decl)) |di_node| { const decl_name_slice = decl_name.slice(&self.builder).?; if (try decl.isFunction(mod)) { @@ -1789,7 +1790,7 @@ pub const Object = struct { ); try global_index.rename(fqn, &self.builder); global_index.setLinkage(.internal, &self.builder); - if (mod.wantDllExports()) global_index.setDllStorageClass(.default, &self.builder); + if (wantDllExports(mod)) global_index.setDllStorageClass(.default, &self.builder); global_index.setUnnamedAddr(.unnamed_addr, &self.builder); if (decl.val.getVariable(mod)) |decl_var| { const decl_namespace = mod.namespacePtr(decl.namespace_index); @@ -1848,7 +1849,7 @@ pub const Object = struct { exports: []const *Module.Export, ) link.File.UpdateExportsError!void { global_index.setUnnamedAddr(.default, &o.builder); - if (mod.wantDllExports()) global_index.setDllStorageClass(.dllexport, &o.builder); + if (wantDllExports(mod)) global_index.setDllStorageClass(.dllexport, &o.builder); global_index.setLinkage(switch (exports[0].opts.linkage) { .Internal => unreachable, .Strong => .external, @@ -11767,3 +11768,9 @@ fn constraintAllowsRegister(constraint: []const u8) bool { } } else return false; } + +fn wantDllExports(zcu: *const Zcu) bool { + const lf = zcu.bin_file.?; + const coff = lf.cast(link.File.Coff) orelse return false; + return coff.dll_export_fns; +} diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 6bb2e6b1f8..41cf524ec0 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -9,6 +9,7 @@ llvm_object: ?*LlvmObject = null, base: link.File, image_base: u64, error_flags: link.File.ErrorFlags = .{}, +dll_export_fns: bool, ptr_width: PtrWidth, page_size: u32, @@ -400,6 +401,8 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { .Lib => 0x10000000, .Obj => 0, }, + + .dll_export_fns = options.dll_export_fns, }; const use_llvm = comp.config.use_llvm; -- cgit v1.2.3 From 33cdf33b95676dca9f91216e0f8742f9cf7e84fb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 13 Dec 2023 18:28:00 -0700 Subject: compiler: update many references to bin_file.options --- src/Compilation.zig | 370 +++++++++++++++++++++------------------ src/Package/Module.zig | 17 ++ src/codegen/llvm.zig | 2 +- src/codegen/spirv.zig | 12 +- src/link.zig | 19 +- src/link/Coff.zig | 24 ++- src/link/Elf.zig | 60 ++++++- src/link/MachO/load_commands.zig | 2 +- src/link/MachO/zld.zig | 2 +- src/link/SpirV.zig | 2 + src/main.zig | 40 ++--- 11 files changed, 319 insertions(+), 231 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index be9fb2a989..5f99c85ba0 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -77,6 +77,7 @@ system_libs: std.StringArrayHashMapUnmanaged(SystemLib), version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, skip_linker_dependencies: bool, +no_builtin: bool, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = @@ -988,10 +989,9 @@ pub const InitOptions = struct { linker_tsaware: bool = false, linker_nxcompat: bool = false, linker_dynamicbase: bool = true, - linker_optimization: ?u8 = null, - linker_compress_debug_sections: ?link.CompressDebugSections = null, + linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null, linker_module_definition_file: ?[]const u8 = null, - linker_sort_section: ?link.SortSection = null, + linker_sort_section: ?link.File.Elf.SortSection = null, major_subsystem_version: ?u32 = null, minor_subsystem_version: ?u32 = null, clang_passthrough_mode: bool = false, @@ -1011,7 +1011,7 @@ pub const InitOptions = struct { /// building such dependencies themselves, this flag must be set to avoid /// infinite recursion. skip_linker_dependencies: bool = false, - hash_style: link.HashStyle = .both, + hash_style: link.File.Elf.HashStyle = .both, entry: ?[]const u8 = null, force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{}, stack_size: ?u64 = null, @@ -1049,8 +1049,6 @@ pub const InitOptions = struct { /// (Windows) PDB output path pdb_out_path: ?[]const u8 = null, error_limit: ?Compilation.Module.ErrorInt = null, - /// (SPIR-V) whether to generate a structured control flow graph or not - want_structured_cfg: ?bool = null, }; fn addModuleTableToCacheHash( @@ -1277,10 +1275,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - const linker_optimization: u8 = options.linker_optimization orelse switch (options.root_mod.optimize_mode) { - .Debug => @as(u8, 0), - else => @as(u8, 3), - }; // TODO: https://github.com/ziglang/zig/issues/17969 const formatted_panics = options.formatted_panics orelse (options.root_mod.optimize_mode == .Debug); @@ -1359,7 +1353,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { hash.add(formatted_panics); hash.add(options.emit_h != null); hash.add(error_limit); - hash.addOptional(options.want_structured_cfg); // In the case of incremental cache mode, this `zig_cache_artifact_directory` // is computed based on a hash of non-linker inputs, and it is where all @@ -1641,13 +1634,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .framework_dirs = options.framework_dirs, .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, .skip_linker_dependencies = options.skip_linker_dependencies, + .no_builtin = options.no_builtin, }; if (bin_file_emit) |emit| { comp.bin_file = try link.File.open(arena, .{ .comp = comp, .emit = emit, - .optimization = linker_optimization, .linker_script = options.linker_script, .z_nodelete = options.linker_z_nodelete, .z_notext = options.linker_z_notext, @@ -1666,7 +1659,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .symbol_wrap_set = options.symbol_wrap_set, .function_sections = options.function_sections, .data_sections = options.data_sections, - .no_builtin = options.no_builtin, .allow_shlib_undefined = options.linker_allow_shlib_undefined, .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, .compress_debug_sections = options.linker_compress_debug_sections orelse .none, @@ -1713,7 +1705,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .force_undefined_symbols = options.force_undefined_symbols, .pdb_source_path = options.pdb_source_path, .pdb_out_path = options.pdb_out_path, - .want_structured_cfg = options.want_structured_cfg, .entry_addr = null, // CLI does not expose this option (yet?) }); } @@ -2076,7 +2067,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void }; if (is_hit) { comp.last_update_was_cache_hit = true; - log.debug("CacheMode.whole cache hit for {s}", .{comp.bin_file.options.root_name}); + log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); const digest = man.final(); comp.wholeCacheModeSetBinFilePath(&digest); @@ -2085,7 +2076,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void comp.bin_file.lock = man.toOwnedLock(); return; } - log.debug("CacheMode.whole cache miss for {s}", .{comp.bin_file.options.root_name}); + log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); // Initialize `bin_file.emit` with a temporary Directory so that compilation can // continue on the same path as incremental, using the temporary Directory. @@ -2169,7 +2160,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // import_table here. // Likewise, in the case of `zig test`, the test runner is the root source file, // and so there is nothing to import the main file. - if (comp.bin_file.options.is_test) { + if (comp.config.is_test) { _ = try module.importPkg(module.main_mod); } @@ -2194,7 +2185,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void } try comp.work_queue.writeItem(.{ .analyze_mod = std_mod }); - if (comp.bin_file.options.is_test) { + if (comp.config.is_test) { try comp.work_queue.writeItem(.{ .analyze_mod = module.main_mod }); } @@ -2208,20 +2199,20 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void if (comp.module) |module| { if (builtin.mode == .Debug and comp.verbose_intern_pool) { std.debug.print("intern pool stats for '{s}':\n", .{ - comp.bin_file.options.root_name, + comp.root_name, }); module.intern_pool.dump(); } if (builtin.mode == .Debug and comp.verbose_generic_instances) { std.debug.print("generic instances for '{s}:0x{x}':\n", .{ - comp.bin_file.options.root_name, + comp.root_name, @as(usize, @intFromPtr(module)), }); module.intern_pool.dumpGenericInstances(comp.gpa); } - if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { + if (comp.config.is_test and comp.totalErrorCount() == 0) { // The `test_functions` decl has been intentionally postponed until now, // at which point we must populate it with the list of test functions that // have been discovered and not filtered out. @@ -2336,7 +2327,7 @@ fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !voi // file copies at the end of generate() can also be extracted to // separate jobs if (!build_options.only_c and !build_options.only_core_functionality) { - if (comp.bin_file.options.docs_emit) |emit| { + if (comp.docs_emit) |emit| { var dir = try emit.directory.handle.makeOpenPath(emit.sub_path, .{}); defer dir.close(); @@ -2426,24 +2417,16 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.main_mod, .{ .files = man }); // Synchronize with other matching comments: ZigOnlyHashStuff - man.hash.add(comp.config.use_llvm); - man.hash.add(comp.config.use_lib_llvm); - man.hash.add(comp.bin_file.options.dll_export_fns); - man.hash.add(comp.bin_file.options.is_test); - man.hash.add(comp.test_evented_io); + man.hash.add(comp.config.test_evented_io); man.hash.addOptionalBytes(comp.test_filter); man.hash.addOptionalBytes(comp.test_name_prefix); man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.formatted_panics); man.hash.add(mod.emit_h != null); man.hash.add(mod.error_limit); - man.hash.add(comp.bin_file.options.want_structured_cfg); } - try man.addOptionalFile(comp.bin_file.options.linker_script); - try man.addOptionalFile(comp.bin_file.options.version_script); - - for (comp.bin_file.options.objects) |obj| { + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); man.hash.add(obj.loption); @@ -2469,39 +2452,19 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes } } + man.hash.addOptionalBytes(comp.sysroot); + man.hash.addOptional(comp.version); man.hash.addListOfBytes(comp.rc_include_dir_list); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc); - man.hash.add(comp.bin_file.stack_size); - man.hash.add(comp.bin_file.options.gc_sections); - man.hash.add(comp.bin_file.options.eh_frame_hdr); - man.hash.add(comp.bin_file.options.emit_relocs); - man.hash.add(comp.bin_file.options.rdynamic); - man.hash.addListOfBytes(comp.bin_file.options.lib_dirs); - man.hash.addListOfBytes(comp.bin_file.options.rpath_list); - man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); - man.hash.add(comp.bin_file.options.each_lib_rpath); - man.hash.add(comp.bin_file.build_id); man.hash.add(comp.skip_linker_dependencies); - man.hash.add(comp.bin_file.options.z_nodelete); - man.hash.add(comp.bin_file.options.z_notext); - man.hash.add(comp.bin_file.options.z_defs); - man.hash.add(comp.bin_file.options.z_origin); - man.hash.add(comp.bin_file.options.z_nocopyreloc); - man.hash.add(comp.bin_file.options.z_now); - man.hash.add(comp.bin_file.options.z_relro); - man.hash.add(comp.bin_file.options.z_common_page_size orelse 0); - man.hash.add(comp.bin_file.options.z_max_page_size orelse 0); - man.hash.add(comp.bin_file.options.hash_style); - man.hash.add(comp.bin_file.options.compress_debug_sections); man.hash.add(comp.include_compiler_rt); - man.hash.add(comp.bin_file.options.sort_section); if (comp.config.link_libc) { - man.hash.add(comp.bin_file.options.libc_installation != null); - if (comp.bin_file.options.libc_installation) |libc_installation| { + man.hash.add(comp.libc_installation != null); + if (comp.libc_installation) |libc_installation| { man.hash.addOptionalBytes(libc_installation.crt_dir); if (target.abi == .msvc) { man.hash.addOptionalBytes(libc_installation.msvc_lib_dir); @@ -2510,55 +2473,93 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes } man.hash.addOptionalBytes(target.dynamic_linker.get()); } - man.hash.addOptionalBytes(comp.bin_file.options.soname); - man.hash.add(comp.bin_file.options.version); try link.hashAddSystemLibs(man, comp.system_libs); - man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys()); - man.hash.add(comp.bin_file.allow_shlib_undefined); - man.hash.add(comp.bin_file.options.bind_global_refs_locally); - man.hash.add(comp.bin_file.options.tsan); - man.hash.addOptionalBytes(comp.bin_file.options.sysroot); - man.hash.add(comp.bin_file.options.linker_optimization); - - switch (comp.bin_file.tag) { - .elf => { - const elf = comp.bin_file.cast(link.File.Elf).?; - man.hash.add(elf.image_base); - }, - .wasm => { - const wasm = comp.bin_file.cast(link.File.Wasm).?; - man.hash.add(comp.config.import_memory); - man.hash.add(comp.config.export_memory); - man.hash.add(comp.config.shared_memory); - man.hash.add(wasm.initial_memory); - man.hash.add(wasm.max_memory); - man.hash.add(wasm.global_base); - }, - .macho => { - const macho = comp.bin_file.cast(link.File.MachO).?; - man.hash.addListOfBytes(comp.framework_dirs); - try link.hashAddFrameworks(man, macho.frameworks); - try man.addOptionalFile(macho.entitlements); - man.hash.add(macho.pagezero_size); - man.hash.add(macho.headerpad_size); - man.hash.add(macho.headerpad_max_install_names); - man.hash.add(macho.dead_strip_dylibs); - }, - .coff => { - const coff = comp.bin_file.cast(link.File.Coff).?; - man.hash.add(coff.image_base); - man.hash.add(coff.subsystem); - man.hash.add(coff.tsaware); - man.hash.add(coff.nxcompat); - man.hash.add(coff.dynamicbase); - man.hash.add(coff.major_subsystem_version); - man.hash.add(coff.minor_subsystem_version); - }, + + man.hash.add(comp.config.use_llvm); + man.hash.add(comp.config.use_lib_llvm); + man.hash.add(comp.config.is_test); + man.hash.add(comp.config.import_memory); + man.hash.add(comp.config.export_memory); + man.hash.add(comp.config.shared_memory); + + if (comp.bin_file) |lf| { + man.hash.add(lf.stack_size); + man.hash.add(lf.gc_sections); + man.hash.addListOfBytes(lf.rpath_list); + man.hash.add(lf.build_id); + man.hash.addListOfBytes(lf.force_undefined_symbols.keys()); + man.hash.add(lf.allow_shlib_undefined); + + switch (lf.tag) { + .elf => { + const elf = lf.cast(link.File.Elf).?; + man.hash.add(elf.rdynamic); + man.hash.add(elf.eh_frame_hdr); + man.hash.add(elf.image_base); + man.hash.add(elf.emit_relocs); + man.hash.add(elf.z_nodelete); + man.hash.add(elf.z_notext); + man.hash.add(elf.z_defs); + man.hash.add(elf.z_origin); + man.hash.add(elf.z_nocopyreloc); + man.hash.add(elf.z_now); + man.hash.add(elf.z_relro); + man.hash.add(elf.z_common_page_size orelse 0); + man.hash.add(elf.z_max_page_size orelse 0); + man.hash.addListOfBytes(elf.lib_dirs); + man.hash.add(elf.hash_style); + man.hash.add(elf.compress_debug_sections); + man.hash.addListOfBytes(elf.symbol_wrap_set.keys()); + man.hash.add(elf.each_lib_rpath); + man.hash.addOptional(elf.sort_section); + man.hash.addOptionalBytes(elf.soname); + man.hash.add(elf.bind_global_refs_locally); + try man.addOptionalFile(elf.linker_script); + try man.addOptionalFile(elf.version_script); + }, + .wasm => { + const wasm = lf.cast(link.File.Wasm).?; + man.hash.add(wasm.rdynamic); + man.hash.add(wasm.initial_memory); + man.hash.add(wasm.max_memory); + man.hash.add(wasm.global_base); + }, + .macho => { + const macho = lf.cast(link.File.MachO).?; + man.hash.addListOfBytes(comp.framework_dirs); + try link.File.MachO.hashAddFrameworks(man, macho.frameworks); + try man.addOptionalFile(macho.entitlements); + man.hash.add(macho.pagezero_vmsize); + man.hash.add(macho.headerpad_size); + man.hash.add(macho.headerpad_max_install_names); + man.hash.add(macho.dead_strip_dylibs); + }, + .coff => { + const coff = lf.cast(link.File.Coff).?; + man.hash.add(coff.dll_export_fns); + man.hash.add(coff.image_base); + man.hash.addOptional(coff.subsystem); + man.hash.add(coff.tsaware); + man.hash.add(coff.nxcompat); + man.hash.add(coff.dynamicbase); + man.hash.add(coff.major_subsystem_version); + man.hash.add(coff.minor_subsystem_version); + man.hash.addListOfBytes(coff.lib_dirs); + }, + .spirv => { + const spirv = lf.cast(link.File.SpirV).?; + _ = spirv; + // TODO + }, + .c => {}, // TODO + .plan9 => {}, // TODO + .nvptx => {}, // TODO + } } } fn emitOthers(comp: *Compilation) void { - if (comp.bin_file.options.output_mode != .Obj or comp.module != null or + if (comp.config.output_mode != .Obj or comp.module != null or comp.c_object_table.count() == 0) { return; @@ -2724,10 +2725,10 @@ pub fn saveState(comp: *Compilation) !void { var bufs_list: [6]std.os.iovec_const = undefined; var bufs_len: usize = 0; - const emit = comp.bin_file.options.emit orelse return; + const lf = comp.bin_file orelse return; - if (comp.module) |mod| { - const ip = &mod.intern_pool; + if (comp.module) |zcu| { + const ip = &zcu.intern_pool; const header: Header = .{ .intern_pool = .{ .items_len = @intCast(ip.items.len), @@ -2751,7 +2752,7 @@ pub fn saveState(comp: *Compilation) !void { } var basename_buf: [255]u8 = undefined; const basename = std.fmt.bufPrint(&basename_buf, "{s}.zcs", .{ - comp.bin_file.options.root_name, + comp.root_name, }) catch o: { basename_buf[basename_buf.len - 4 ..].* = ".zcs".*; break :o &basename_buf; @@ -2759,7 +2760,7 @@ pub fn saveState(comp: *Compilation) !void { // Using an atomic file prevents a crash or power failure from corrupting // the previous incremental compilation state. - var af = try emit.directory.handle.atomicFile(basename, .{}); + var af = try lf.emit.directory.handle.atomicFile(basename, .{}); defer af.deinit(); try af.file.pwritevAll(bufs_list[0..bufs_len], 0); try af.finish(); @@ -3507,7 +3508,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v error.AnalysisFail => return, }; const decl = module.declPtr(decl_index); - if (decl.kind == .@"test" and comp.bin_file.options.is_test) { + if (decl.kind == .@"test" and comp.config.is_test) { // Tests are always emitted in test binaries. The decl_refs are created by // Module.populateTestFunctions, but this will not queue body analysis, so do // that now. @@ -3850,7 +3851,7 @@ pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { // based on the zig library directory alone. The zig lib directory file // path is purposefully either in the cache or not in the cache. The // decision should not be overridden here. - if (comp.bin_file.options.libc_installation != null) { + if (comp.libc_installation != null) { man.hash.addListOfBytes(comp.libc_include_dir_list); } @@ -4248,9 +4249,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P // file and building an object we need to link them together, but with just one it should go // directly to the output file. const direct_o = comp.c_source_files.len == 1 and comp.module == null and - comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0; + comp.config.output_mode == .Obj and comp.objects.len == 0; const o_basename_noext = if (direct_o) - comp.bin_file.options.root_name + comp.root_name else c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; @@ -4304,8 +4305,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P try argv.appendSlice(c_object.src.extra_flags); try argv.appendSlice(c_object.src.cache_exempt_flags); - const out_obj_path = if (comp.bin_file.options.emit) |emit| - try emit.directory.join(arena, &.{emit.sub_path}) + const out_obj_path = if (comp.bin_file) |lf| + try lf.emit.directory.join(arena, &.{lf.emit.sub_path}) else "/dev/null"; @@ -4883,8 +4884,9 @@ pub fn addCCArgs( argv: *std.ArrayList([]const u8), ext: FileExt, out_dep_path: ?[]const u8, + mod: *Package.Module, ) !void { - const target = comp.getTarget(); + const target = mod.resolved_target.result; // As of Clang 16.x, it will by default read extra flags from /etc/clang. // I'm sure the person who implemented this means well, but they have a lot @@ -4905,15 +4907,15 @@ pub fn addCCArgs( try argv.append("-fno-caret-diagnostics"); } - if (comp.bin_file.options.function_sections) { + if (comp.bin_file.function_sections) { try argv.append("-ffunction-sections"); } - if (comp.bin_file.options.data_sections) { + if (comp.bin_file.data_sections) { try argv.append("-fdata-sections"); } - if (comp.bin_file.options.no_builtin) { + if (comp.no_builtin) { try argv.append("-fno-builtin"); } @@ -4953,7 +4955,7 @@ pub fn addCCArgs( })); } - if (comp.bin_file.options.link_libunwind) { + if (comp.config.link_libunwind) { const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "libunwind", "include", }); @@ -4987,7 +4989,7 @@ pub fn addCCArgs( "-nostdinc", "-fno-spell-checking", }); - if (comp.bin_file.options.lto) { + if (comp.config.lto) { try argv.append("-flto"); } @@ -5042,9 +5044,8 @@ pub fn addCCArgs( argv.appendAssumeCapacity(arg); } } - const code_model = comp.bin_file.options.machine_code_model; - if (code_model != .default) { - try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(code_model)})); + if (mod.code_model != .default) { + try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)})); } switch (target.os.tag) { @@ -5093,7 +5094,7 @@ pub fn addCCArgs( try argv.append("-mthumb"); } - if (comp.sanitize_c and !comp.bin_file.options.tsan) { + if (mod.sanitize_c and !mod.sanitize_thread) { try argv.append("-fsanitize=undefined"); try argv.append("-fsanitize-trap=undefined"); // It is very common, and well-defined, for a pointer on one side of a C ABI @@ -5104,27 +5105,27 @@ pub fn addCCArgs( // Without this flag, Clang would invoke UBSAN when such an extern // function was called. try argv.append("-fno-sanitize=function"); - } else if (comp.sanitize_c and comp.bin_file.options.tsan) { + } else if (mod.sanitize_c and mod.sanitize_thread) { try argv.append("-fsanitize=undefined,thread"); try argv.append("-fsanitize-trap=undefined"); try argv.append("-fno-sanitize=function"); - } else if (!comp.sanitize_c and comp.bin_file.options.tsan) { + } else if (!mod.sanitize_c and mod.sanitize_thread) { try argv.append("-fsanitize=thread"); } - if (comp.bin_file.options.red_zone) { + if (mod.red_zone) { try argv.append("-mred-zone"); } else if (target_util.hasRedZone(target)) { try argv.append("-mno-red-zone"); } - if (comp.bin_file.options.omit_frame_pointer) { + if (mod.omit_frame_pointer) { try argv.append("-fomit-frame-pointer"); } else { try argv.append("-fno-omit-frame-pointer"); } - const ssp_buf_size = comp.bin_file.options.stack_protector; + const ssp_buf_size = mod.stack_protector; if (ssp_buf_size != 0) { try argv.appendSlice(&[_][]const u8{ "-fstack-protector-strong", @@ -5135,7 +5136,7 @@ pub fn addCCArgs( try argv.append("-fno-stack-protector"); } - switch (comp.bin_file.options.optimize_mode) { + switch (mod.optimize_mode) { .Debug => { // windows c runtime requires -D_DEBUG if using debug libraries try argv.append("-D_DEBUG"); @@ -5165,7 +5166,7 @@ pub fn addCCArgs( }, } - if (target_util.supports_fpic(target) and comp.bin_file.options.pic) { + if (target_util.supports_fpic(target) and mod.pic) { try argv.append("-fPIC"); } @@ -5940,7 +5941,7 @@ pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const { return comp.crt_files.get(basename).?.full_object_path; } - const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; + const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable; const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir; const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename }); return full_path; @@ -6112,7 +6113,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool { pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend { const target = comp.root_mod.resolved_target.result; - return target_util.zigBackend(target, comp.bin_file.options.use_llvm); + return target_util.zigBackend(target, comp.config.use_llvm); } pub fn updateSubCompilation( @@ -6165,6 +6166,9 @@ fn buildOutputFromZig( assert(output_mode != .Exe); + const lf = comp.bin_file.?; + const unwind_tables = if (lf.cast(link.File.Elf)) |elf| elf.eh_frame_hdr else false; + const config = try Config.resolve(.{ .output_mode = output_mode, .resolved_target = comp.root_mod.resolved_target, @@ -6173,6 +6177,7 @@ fn buildOutputFromZig( .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), .link_libc = comp.config.link_libc, + .any_unwind_tables = unwind_tables, }); const root_mod = Package.Module.create(.{ @@ -6187,9 +6192,10 @@ fn buildOutputFromZig( .stack_protector = 0, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, - .unwind_tables = comp.bin_file.options.eh_frame_hdr, + .unwind_tables = unwind_tables, .pic = comp.root_mod.pic, .optimize_mode = comp.compilerRtOptMode(), + .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = &.{}, @@ -6210,21 +6216,21 @@ fn buildOutputFromZig( .global_cache_directory = comp.global_cache_directory, .local_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, + .self_exe_path = comp.self_exe_path, .resolved = config, .root_mod = root_mod, .cache_mode = .whole, .root_name = root_name, .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, + .libc_installation = comp.libc_installation, .emit_bin = emit_bin, .link_mode = .Static, .function_sections = true, .data_sections = true, .no_builtin = true, .emit_h = null, - .self_exe_path = comp.self_exe_path, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_intern_pool = comp.verbose_intern_pool, .verbose_generic_instances = comp.verbose_intern_pool, @@ -6234,7 +6240,6 @@ fn buildOutputFromZig( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); @@ -6242,8 +6247,8 @@ fn buildOutputFromZig( assert(out.* == null); out.* = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }; @@ -6260,51 +6265,70 @@ pub fn build_crt_file( const tracy_trace = trace(@src()); defer tracy_trace.end(); - const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(comp.gpa, .{ + const gpa = comp.gpa; + const basename = try std.zig.binNameAlloc(gpa, .{ .root_name = root_name, - .target = target, + .target = comp.root_mod.resolved_target.result, .output_mode = output_mode, }); - errdefer comp.gpa.free(basename); + errdefer gpa.free(basename); - const sub_compilation = try Compilation.create(comp.gpa, .{ + const config = try Config.resolve(.{ + .output_mode = output_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = comp.compilerRtOptMode(), + .link_libc = false, + .lto = switch (output_mode) { + .Lib => comp.config.lto, + .Obj, .Exe => false, + }, + }); + const root_mod = Package.Module.create(.{ + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .strip = comp.compilerRtStrip(), + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = false, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .unwind_tables = false, + .pic = comp.root_mod.pic, + .optimize_mode = comp.compilerRtOptMode(), + .structured_cfg = comp.root_mod.structured_cfg, + }, + .global = config, + .cc_argv = &.{}, + }); + + const sub_compilation = try Compilation.create(gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, + .self_exe_path = comp.self_exe_path, .cache_mode = .whole, - .target = target, + .resolved = config, + .root_mod = root_mod, .root_name = root_name, - .main_mod = null, - .output_mode = output_mode, .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, + .libc_installation = comp.libc_installation, .emit_bin = .{ .directory = null, // Put it in the cache directory. .basename = basename, }, - .optimize_mode = comp.compilerRtOptMode(), - .want_sanitize_c = false, - .want_stack_check = false, - .want_stack_protector = 0, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = false, - .want_pic = comp.bin_file.options.pic, - .want_pie = null, - .want_lto = switch (output_mode) { - .Lib => comp.bin_file.options.lto, - .Obj, .Exe => false, - }, .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, .c_source_files = c_source_files, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_intern_pool = comp.verbose_intern_pool, .verbose_generic_instances = comp.verbose_generic_instances, @@ -6314,17 +6338,16 @@ pub fn build_crt_file( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); - try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1); + try comp.crt_files.ensureUnusedCapacity(gpa, 1); comp.crt_files.putAssumeCapacityNoClobber(basename, .{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(gpa, &[_][]const u8{ + sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }); @@ -6357,10 +6380,11 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { /// compiler-rt, libcxx, libc, libunwind, etc. pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode { if (comp.debug_compiler_runtime_libs) { - return comp.bin_file.options.optimize_mode; + return comp.root_mod.optimize_mode; } - switch (comp.bin_file.options.optimize_mode) { - .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(comp.getTarget()), + const target = comp.root_mod.resolved_target.result; + switch (comp.root_mod.optimize_mode) { + .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(target), .ReleaseFast => return .ReleaseFast, .ReleaseSmall => return .ReleaseSmall, } @@ -6369,5 +6393,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode { /// This decides whether to strip debug info for all zig-provided libraries, including /// compiler-rt, libcxx, libc, libunwind, etc. pub fn compilerRtStrip(comp: Compilation) bool { - return comp.bin_file.options.strip; + return comp.root_mod.strip; } diff --git a/src/Package/Module.zig b/src/Package/Module.zig index f1e7091855..0916742876 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -30,6 +30,8 @@ sanitize_c: bool, sanitize_thread: bool, unwind_tables: bool, cc_argv: []const []const u8, +/// (SPIR-V) whether to generate a structured control flow graph or not +structured_cfg: bool, /// The contents of `@import("builtin")` for this module. generated_builtin_source: []const u8, @@ -82,6 +84,7 @@ pub const CreateOptions = struct { unwind_tables: ?bool = null, sanitize_c: ?bool = null, sanitize_thread: ?bool = null, + structured_cfg: ?bool = null, }; }; @@ -268,6 +271,17 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { break :sp target_util.default_stack_protector_buffer_size; }; + const structured_cfg = b: { + if (options.inherited.structured_cfg) |x| break :b x; + if (options.parent) |p| break :b p.structured_cfg; + // We always want a structured control flow in shaders. This option is + // only relevant for OpenCL kernels. + break :b switch (target.os.tag) { + .opencl => false, + else => true, + }; + }; + const llvm_cpu_features: ?[*:0]const u8 = b: { if (resolved_target.llvm_cpu_features) |x| break :b x; if (!options.global.use_llvm) break :b null; @@ -350,6 +364,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = &.{}, + .structured_cfg = structured_cfg, }; break :b new; }; @@ -381,6 +396,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = options.cc_argv, + .structured_cfg = structured_cfg, }; try mod.deps.ensureUnusedCapacity(arena, 1); @@ -422,6 +438,7 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P .unwind_tables = undefined, .cc_argv = undefined, .generated_builtin_source = undefined, + .structured_cfg = undefined, }; return mod; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index beb3e5e9f6..ee9e3de086 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3084,7 +3084,7 @@ pub const Object = struct { if (comp.unwind_tables) { try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); } - if (comp.skip_linker_dependencies or comp.bin_file.options.no_builtin) { + if (comp.skip_linker_dependencies or comp.no_builtin) { // The intent here is for compiler-rt and libc functions to not generate // infinite recursion. For example, if we are compiling the memcpy function, // and llvm detects that the body is equivalent to memcpy, it may replace the diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index fb1f2bb827..6b2587e3cb 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -191,13 +191,9 @@ pub const Object = struct { air: Air, liveness: Liveness, ) !void { - const target = mod.getTarget(); - // We always want a structured control flow in shaders. This option is only relevant - // for OpenCL kernels. - const want_structured_cfg = switch (target.os.tag) { - .opencl => mod.comp.bin_file.options.want_structured_cfg orelse false, - else => true, - }; + const decl = mod.declPtr(decl_index); + const namespace = mod.namespacePtr(decl.src_namespace); + const structured_cfg = namespace.file_scope.mod.structured_cfg; var decl_gen = DeclGen{ .gpa = self.gpa, @@ -208,7 +204,7 @@ pub const Object = struct { .air = air, .liveness = liveness, .type_map = &self.type_map, - .control_flow = switch (want_structured_cfg) { + .control_flow = switch (structured_cfg) { true => .{ .structured = .{} }, false => .{ .unstructured = .{} }, }, diff --git a/src/link.zig b/src/link.zig index 580b2d7daf..5908a07dec 100644 --- a/src/link.zig +++ b/src/link.zig @@ -32,8 +32,6 @@ pub const SystemLib = struct { path: ?[]const u8, }; -pub const SortSection = enum { name, alignment }; - pub const CacheMode = enum { incremental, whole }; pub fn hashAddSystemLibs( @@ -51,10 +49,6 @@ pub fn hashAddSystemLibs( pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version; -pub const HashStyle = enum { sysv, gnu, both }; - -pub const CompressDebugSections = enum { none, zlib, zstd }; - pub const File = struct { tag: Tag, @@ -105,12 +99,9 @@ pub const File = struct { image_base: ?u64, function_sections: bool, data_sections: bool, - no_builtin: bool, eh_frame_hdr: bool, emit_relocs: bool, rdynamic: bool, - optimization: u8, - linker_script: ?[]const u8, z_nodelete: bool, z_notext: bool, z_defs: bool, @@ -123,7 +114,7 @@ pub const File = struct { tsaware: bool, nxcompat: bool, dynamicbase: bool, - compress_debug_sections: CompressDebugSections, + compress_debug_sections: Elf.CompressDebugSections, bind_global_refs_locally: bool, import_symbols: bool, import_table: bool, @@ -136,13 +127,14 @@ pub const File = struct { each_lib_rpath: bool, build_id: std.zig.BuildId, disable_lld_caching: bool, - hash_style: HashStyle, - sort_section: ?SortSection, + hash_style: Elf.HashStyle, + sort_section: ?Elf.SortSection, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, gc_sections: ?bool, allow_shlib_undefined: ?bool, subsystem: ?std.Target.SubSystem, + linker_script: ?[]const u8, version_script: ?[]const u8, soname: ?[]const u8, print_gc_sections: bool, @@ -192,9 +184,6 @@ pub const File = struct { /// (Windows) .def file to specify when linking module_definition_file: ?[]const u8, - /// (SPIR-V) whether to generate a structured control flow graph or not - want_structured_cfg: ?bool, - wasi_emulated_libs: []const wasi_libc.CRTFile, }; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 41cf524ec0..db99ba189c 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -10,6 +10,15 @@ base: link.File, image_base: u64, error_flags: link.File.ErrorFlags = .{}, dll_export_fns: bool, +subsystem: ?std.Target.SubSystem, +tsaware: bool, +nxcompat: bool, +dynamicbase: bool, +/// TODO this and minor_subsystem_version should be combined into one property and left as +/// default or populated together. They should not be separate fields. +major_subsystem_version: u32, +minor_subsystem_version: u32, +lib_dirs: []const []const u8, ptr_width: PtrWidth, page_size: u32, @@ -403,6 +412,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { }, .dll_export_fns = options.dll_export_fns, + .subsystem = options.subsystem, + .tsaware = options.tsaware, + .nxcompat = options.nxcompat, + .dynamicbase = options.dynamicbase, + .major_subsystem_version = options.major_subsystem_version orelse 6, + .minor_subsystem_version = options.minor_subsystem_version orelse 0, + .lib_dirs = options.lib_dirs, }; const use_llvm = comp.config.use_llvm; @@ -2305,8 +2321,8 @@ fn writeHeader(self: *Coff) !void { .minor_operating_system_version = 0, .major_image_version = 0, .minor_image_version = 0, - .major_subsystem_version = 6, - .minor_subsystem_version = 0, + .major_subsystem_version = self.major_subsystem_version, + .minor_subsystem_version = self.minor_subsystem_version, .win32_version_value = 0, .size_of_image = size_of_image, .size_of_headers = size_of_headers, @@ -2339,8 +2355,8 @@ fn writeHeader(self: *Coff) !void { .minor_operating_system_version = 0, .major_image_version = 0, .minor_image_version = 0, - .major_subsystem_version = 6, - .minor_subsystem_version = 0, + .major_subsystem_version = self.major_subsystem_version, + .minor_subsystem_version = self.minor_subsystem_version, .win32_version_value = 0, .size_of_image = size_of_image, .size_of_headers = size_of_headers, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a116c46d2f..b54bde325f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1,6 +1,29 @@ base: link.File, image_base: u64, rdynamic: bool, +eh_frame_hdr: bool, +emit_relocs: bool, +z_nodelete: bool, +z_notext: bool, +z_defs: bool, +z_origin: bool, +z_nocopyreloc: bool, +z_now: bool, +z_relro: bool, +/// TODO make this non optional and resolve the default in open() +z_common_page_size: ?u64, +/// TODO make this non optional and resolve the default in open() +z_max_page_size: ?u64, +lib_dirs: []const []const u8, +hash_style: HashStyle, +compress_debug_sections: CompressDebugSections, +symbol_wrap_set: std.StringArrayHashMapUnmanaged(void), +each_lib_rpath: bool, +sort_section: ?SortSection, +soname: ?[]const u8, +bind_global_refs_locally: bool, +linker_script: ?[]const u8, +version_script: ?[]const u8, ptr_width: PtrWidth, @@ -201,6 +224,9 @@ const minimum_atom_size = 64; pub const min_text_capacity = padToIdeal(minimum_atom_size); pub const PtrWidth = enum { p32, p64 }; +pub const HashStyle = enum { sysv, gnu, both }; +pub const CompressDebugSections = enum { none, zlib, zstd }; +pub const SortSection = enum { name, alignment }; pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { if (build_options.only_c) unreachable; @@ -374,6 +400,27 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { }, .rdynamic = options.rdynamic, + .eh_frame_hdr = options.eh_frame_hdr, + .emit_relocs = options.emit_relocs, + .z_nodelete = options.z_nodelete, + .z_notext = options.z_notext, + .z_defs = options.z_defs, + .z_origin = options.z_origin, + .z_nocopyreloc = options.z_nocopyreloc, + .z_now = options.z_now, + .z_relro = options.z_relro, + .z_common_page_size = options.z_common_page_size, + .z_max_page_size = options.z_max_page_size, + .lib_dirs = options.lib_dirs, + .hash_style = options.hash_style, + .compress_debug_sections = options.compress_debug_sections, + .symbol_wrap_set = options.symbol_wrap_set, + .each_lib_rpath = options.each_lib_rpath, + .sort_section = options.sort_section, + .soname = options.soname, + .bind_global_refs_locally = options.bind_global_refs_locally, + .linker_script = options.linker_script, + .version_script = options.version_script, }; if (use_llvm and comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, options); @@ -2424,8 +2471,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.add(self.bind_global_refs_locally); man.hash.add(self.compress_debug_sections); man.hash.add(comp.config.any_sanitize_thread); - man.hash.addOptionalBytes(self.sysroot); - man.hash.add(self.optimization); + man.hash.addOptionalBytes(comp.sysroot); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -2500,7 +2546,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--error-limit=0"); - if (self.sysroot) |sysroot| { + if (comp.sysroot) |sysroot| { try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); } @@ -2511,9 +2557,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), } } - try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{ - self.optimization, - })); + switch (comp.root_mod.optimize_mode) { + .Debug => {}, + .ReleaseSmall => try argv.append("-O2"), + .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + } if (comp.config.entry) |entry| { try argv.append("--entry"); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 3bffc7f73e..8bcf439354 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -476,7 +476,7 @@ pub fn inferSdkVersion(gpa: Allocator, comp: *const Compilation) ?std.SemanticVe const sdk_layout = macho_file.sdk_layout orelse return null; const sdk_dir = switch (sdk_layout) { - .sdk => macho_file.sysroot.?, + .sdk => comp.sysroot.?, .vendored => std.fs.path.join(arena, &.{ comp.zig_lib_directory.path.?, "libc", "darwin" }) catch return null, }; if (readSdkVersionFromSettings(arena, sdk_dir)) |ver| { diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index f40aaea4db..06fede6e1b 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -249,7 +249,7 @@ pub fn linkWithZld( } } - if (macho_file.sysroot) |syslibroot| { + if (comp.sysroot) |syslibroot| { try argv.append("-syslibroot"); try argv.append(syslibroot); } diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index d8f78c32f1..bb278a8e4a 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -47,6 +47,8 @@ base: link.File, object: codegen.Object, +pub const base_tag: link.File.Tag = .spirv; + pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { const gpa = options.comp.gpa; const target = options.comp.root_mod.resolved_target.result; diff --git a/src/main.zig b/src/main.zig index 5f65908b5c..9acad1a0ca 100644 --- a/src/main.zig +++ b/src/main.zig @@ -828,9 +828,9 @@ fn buildOutputType( var linker_script: ?[]const u8 = null; var version_script: ?[]const u8 = null; var disable_c_depfile = false; - var linker_sort_section: ?link.SortSection = null; + var linker_sort_section: ?link.File.Elf.SortSection = null; var linker_gc_sections: ?bool = null; - var linker_compress_debug_sections: ?link.CompressDebugSections = null; + var linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null; var linker_allow_shlib_undefined: ?bool = null; var linker_bind_global_refs_locally: ?bool = null; var linker_import_symbols: bool = false; @@ -855,7 +855,7 @@ fn buildOutputType( var linker_tsaware = false; var linker_nxcompat = false; var linker_dynamicbase = true; - var linker_optimization: ?u8 = null; + var linker_optimization: ?[]const u8 = null; var linker_module_definition_file: ?[]const u8 = null; var test_no_exec = false; var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{}; @@ -881,7 +881,7 @@ fn buildOutputType( var enable_link_snapshots: bool = false; var debug_incremental: bool = false; var install_name: ?[]const u8 = null; - var hash_style: link.HashStyle = .both; + var hash_style: link.File.Elf.HashStyle = .both; var entitlements: ?[]const u8 = null; var pagezero_size: ?u64 = null; var lib_search_strategy: SystemLib.SearchStrategy = .paths_first; @@ -894,7 +894,6 @@ fn buildOutputType( var pdb_out_path: ?[]const u8 = null; var debug_format: ?link.File.DebugFormat = null; var error_limit: ?Module.ErrorInt = null; - var want_structured_cfg: ?bool = null; // These are before resolving sysroot. var lib_dir_args: std.ArrayListUnmanaged([]const u8) = .{}; var extra_cflags: std.ArrayListUnmanaged([]const u8) = .{}; @@ -1110,9 +1109,9 @@ fn buildOutputType( try extra_rcflags.append(arena, next_arg); } } else if (mem.startsWith(u8, arg, "-fstructured-cfg")) { - want_structured_cfg = true; + mod_opts.structured_cfg = true; } else if (mem.startsWith(u8, arg, "-fno-structured-cfg")) { - want_structured_cfg = false; + mod_opts.structured_cfg = false; } else if (mem.eql(u8, arg, "--color")) { const next_arg = args_iter.next() orelse { fatal("expected [auto|on|off] after --color", .{}); @@ -1152,11 +1151,11 @@ fn buildOutputType( install_name = args_iter.nextOrFatal(); } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) { const param = arg["--compress-debug-sections=".len..]; - linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, param) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, param) orelse { fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param}); }; } else if (mem.eql(u8, arg, "--compress-debug-sections")) { - linker_compress_debug_sections = link.CompressDebugSections.zlib; + linker_compress_debug_sections = link.File.Elf.CompressDebugSections.zlib; } else if (mem.eql(u8, arg, "-pagezero_size")) { const next_arg = args_iter.nextOrFatal(); pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { @@ -2067,7 +2066,7 @@ fn buildOutputType( if (it.only_arg.len == 0) { linker_compress_debug_sections = .zlib; } else { - linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, it.only_arg) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, it.only_arg) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{it.only_arg}); }; } @@ -2138,14 +2137,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { version_script = linker_args_it.nextOrFatal(); } else if (mem.eql(u8, arg, "-O")) { - const opt = linker_args_it.nextOrFatal(); - linker_optimization = std.fmt.parseUnsigned(u8, opt, 10) catch |err| { - fatal("unable to parse optimization level '{s}': {s}", .{ opt, @errorName(err) }); - }; + linker_optimization = linker_args_it.nextOrFatal(); } else if (mem.startsWith(u8, arg, "-O")) { - linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| { - fatal("unable to parse optimization level '{s}': {s}", .{ arg, @errorName(err) }); - }; + linker_optimization = arg["-O".len..]; } else if (mem.eql(u8, arg, "-pagezero_size")) { const next_arg = linker_args_it.nextOrFatal(); pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { @@ -2176,7 +2170,7 @@ fn buildOutputType( linker_print_map = true; } else if (mem.eql(u8, arg, "--sort-section")) { const arg1 = linker_args_it.nextOrFatal(); - linker_sort_section = std.meta.stringToEnum(link.SortSection, arg1) orelse { + linker_sort_section = std.meta.stringToEnum(link.File.Elf.SortSection, arg1) orelse { fatal("expected [name|alignment] after --sort-section, found '{s}'", .{arg1}); }; } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or @@ -2222,7 +2216,7 @@ fn buildOutputType( try linker_export_symbol_names.append(arena, linker_args_it.nextOrFatal()); } else if (mem.eql(u8, arg, "--compress-debug-sections")) { const arg1 = linker_args_it.nextOrFatal(); - linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, arg1) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, arg1) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1}); }; } else if (mem.startsWith(u8, arg, "-z")) { @@ -2405,7 +2399,7 @@ fn buildOutputType( mem.eql(u8, arg, "--hash-style")) { const next_arg = linker_args_it.nextOrFatal(); - hash_style = std.meta.stringToEnum(link.HashStyle, next_arg) orelse { + hash_style = std.meta.stringToEnum(link.File.Elf.HashStyle, next_arg) orelse { fatal("expected [sysv|gnu|both] after --hash-style, found '{s}'", .{ next_arg, }); @@ -2625,6 +2619,10 @@ fn buildOutputType( }; defer global_cache_directory.handle.close(); + if (linker_optimization) |o| { + warn("ignoring deprecated linker optimization setting '{s}'", .{o}); + } + create_module.global_cache_directory = global_cache_directory; create_module.opts.emit_llvm_ir = emit_llvm_ir != .no; create_module.opts.emit_llvm_bc = emit_llvm_bc != .no; @@ -3409,7 +3407,6 @@ fn buildOutputType( .linker_tsaware = linker_tsaware, .linker_nxcompat = linker_nxcompat, .linker_dynamicbase = linker_dynamicbase, - .linker_optimization = linker_optimization, .linker_compress_debug_sections = linker_compress_debug_sections, .linker_module_definition_file = linker_module_definition_file, .major_subsystem_version = major_subsystem_version, @@ -3458,7 +3455,6 @@ fn buildOutputType( .reference_trace = reference_trace, .pdb_out_path = pdb_out_path, .error_limit = error_limit, - .want_structured_cfg = want_structured_cfg, }) catch |err| switch (err) { error.LibCUnavailable => { const triple_name = try target.zigTriple(arena); -- cgit v1.2.3 From f54471b54c471bb6f8e51a1383be09d01c24d0c3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Dec 2023 16:41:20 -0700 Subject: compiler: miscellaneous branch progress implement builtin.zig file population for all modules rather than assuming there is only one global builtin.zig module. move some fields from link.File to Compilation move some fields from Module to Compilation compute debug_format in global Compilation config resolution wire up C compilation to the concept of owner modules make whole cache mode call link.File.createEmpty() instead of link.File.open() --- src/Builtin.zig | 62 ++++++++++++++- src/Compilation.zig | 183 +++++++++++++++++++++++++-------------------- src/Compilation/Config.zig | 31 ++++++++ src/Module.zig | 69 ----------------- src/Package/Module.zig | 31 ++++++-- src/Sema.zig | 7 +- src/codegen/llvm.zig | 16 +--- src/libunwind.zig | 3 +- src/link.zig | 41 +++++----- src/link/C.zig | 26 +++---- src/link/Coff.zig | 42 ++++++----- src/link/Coff/lld.zig | 2 +- src/link/Elf.zig | 48 ++++++------ src/link/Elf/Object.zig | 3 +- src/link/Elf/ZigObject.zig | 12 ++- src/link/MachO.zig | 39 +++++----- src/link/NvPtx.zig | 33 ++++---- src/link/Plan9.zig | 36 +++++---- src/link/SpirV.zig | 35 +++++---- src/link/Wasm.zig | 41 +++++----- src/main.zig | 33 ++++---- 21 files changed, 457 insertions(+), 336 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Builtin.zig b/src/Builtin.zig index 7224a6fd24..4c8038019c 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -20,8 +20,11 @@ wasi_exec_model: std.builtin.WasiExecModel, pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 { var buffer = std.ArrayList(u8).init(allocator); - defer buffer.deinit(); + try append(opts, &buffer); + return buffer.toOwnedSliceSentinel(0); +} +pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { const target = opts.target; const generic_arch_name = target.cpu.arch.genericName(); const zig_backend = opts.zig_backend; @@ -231,10 +234,65 @@ pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 { ); } } +} - return buffer.toOwnedSliceSentinel(0); +pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void { + assert(file.source_loaded == true); + + if (mod.root.statFile(mod.root_src_path)) |stat| { + if (stat.size != file.source.len) { + std.log.warn( + "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++ + "Overwriting with correct file contents now", + .{ mod.root, mod.root_src_path, file.source.len, stat.size }, + ); + + try writeFile(file, mod); + } else { + file.stat = .{ + .size = stat.size, + .inode = stat.inode, + .mtime = stat.mtime, + }; + } + } else |err| switch (err) { + error.BadPathName => unreachable, // it's always "builtin.zig" + error.NameTooLong => unreachable, // it's always "builtin.zig" + error.PipeBusy => unreachable, // it's not a pipe + error.WouldBlock => unreachable, // not asking for non-blocking I/O + + error.FileNotFound => try writeFile(file, mod), + + else => |e| return e, + } + + file.tree = try std.zig.Ast.parse(comp.gpa, file.source, .zig); + file.tree_loaded = true; + assert(file.tree.errors.len == 0); // builtin.zig must parse + + file.zir = try AstGen.generate(comp.gpa, file.tree); + file.zir_loaded = true; + file.status = .success_zir; +} + +fn writeFile(file: *File, mod: *Module) !void { + var af = try mod.root.atomicFile(mod.root_src_path, .{}); + defer af.deinit(); + try af.file.writeAll(file.source); + try af.finish(); + + file.stat = .{ + .size = file.source.len, + .inode = 0, // dummy value + .mtime = 0, // dummy value + }; } const std = @import("std"); const Allocator = std.mem.Allocator; const build_options = @import("build_options"); +const Module = @import("Package/Module.zig"); +const assert = std.debug.assert; +const AstGen = @import("AstGen.zig"); +const File = @import("Module.zig").File; +const Compilation = @import("Compilation.zig"); diff --git a/src/Compilation.zig b/src/Compilation.zig index 8cf7a66fbc..35ee243617 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -37,6 +37,7 @@ const Zir = @import("Zir.zig"); const Autodoc = @import("Autodoc.zig"); const Color = @import("main.zig").Color; const resinator = @import("resinator.zig"); +const Builtin = @import("Builtin.zig"); pub const Config = @import("Compilation/Config.zig"); @@ -59,7 +60,10 @@ root_mod: *Package.Module, /// User-specified settings that have all the defaults resolved into concrete values. config: Config, -/// This is `null` when `-fno-emit-bin` is used. +/// The main output file. +/// In whole cache mode, this is null except for during the body of the update +/// function. In incremental cache mode, this is a long-lived object. +/// In both cases, this is `null` when `-fno-emit-bin` is used. bin_file: ?*link.File, /// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin) @@ -80,6 +84,8 @@ version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, skip_linker_dependencies: bool, no_builtin: bool, +function_sections: bool, +data_sections: bool, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = @@ -120,7 +126,6 @@ failed_win32_resources: if (build_options.only_core_functionality) void else std /// Miscellaneous things that can fail. misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{}, -keep_source_files_loaded: bool, /// When this is `true` it means invoking clang as a sub-process is expected to inherit /// stdin, stdout, stderr, and if it returns non success, to forward the exit code. /// Otherwise we attempt to parse the error messages and expose them via the Compilation API. @@ -144,6 +149,7 @@ debug_compiler_runtime_libs: bool, debug_compile_errors: bool, job_queued_compiler_rt_lib: bool = false, job_queued_compiler_rt_obj: bool = false, +job_queued_update_builtin_zig: bool, alloc_failure_occurred: bool = false, formatted_panics: bool = false, last_update_was_cache_hit: bool = false, @@ -814,13 +820,13 @@ pub const cache_helpers = struct { addEmitLoc(hh, optional_emit_loc orelse return); } - pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?link.File.DebugFormat) void { + pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?Config.DebugFormat) void { hh.add(x != null); addDebugFormat(hh, x orelse return); } - pub fn addDebugFormat(hh: *Cache.HashHelper, x: link.File.DebugFormat) void { - const tag: @typeInfo(link.File.DebugFormat).Union.tag_type.? = x; + pub fn addDebugFormat(hh: *Cache.HashHelper, x: Config.DebugFormat) void { + const tag: @typeInfo(Config.DebugFormat).Union.tag_type.? = x; hh.add(tag); switch (x) { .strip, .code_view => {}, @@ -860,11 +866,11 @@ pub const SystemLib = link.SystemLib; pub const CacheMode = enum { incremental, whole }; -pub const CacheUse = union(CacheMode) { +const CacheUse = union(CacheMode) { incremental: *Incremental, whole: *Whole, - pub const Whole = struct { + const Whole = struct { /// This is a pointer to a local variable inside `update()`. cache_manifest: ?*Cache.Manifest = null, cache_manifest_mutex: std.Thread.Mutex = .{}, @@ -873,12 +879,14 @@ pub const CacheUse = union(CacheMode) { /// of exactly the correct size for "o/[digest]/[basename]". /// The basename is of the outputted binary file in case we don't know the directory yet. bin_sub_path: ?[]u8, - /// Same as `whole_bin_sub_path` but for implibs. + /// Same as `bin_sub_path` but for implibs. implib_sub_path: ?[]u8, docs_sub_path: ?[]u8, + lf_open_opts: link.File.OpenOptions, + tmp_artifact_directory: ?Cache.Directory, }; - pub const Incremental = struct { + const Incremental = struct { /// Where build artifacts and incremental compilation metadata serialization go. artifact_directory: Compilation.Directory, }; @@ -937,7 +945,6 @@ pub const InitOptions = struct { /// this flag would be set to disable this machinery to avoid false positives. disable_lld_caching: bool = false, cache_mode: CacheMode = .incremental, - keep_source_files_loaded: bool = false, lib_dirs: []const []const u8 = &[0][]const u8{}, rpath_list: []const []const u8 = &[0][]const u8{}, symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{}, @@ -1040,7 +1047,6 @@ pub const InitOptions = struct { test_name_prefix: ?[]const u8 = null, test_runner_path: ?[]const u8 = null, subsystem: ?std.Target.SubSystem = null, - debug_format: ?link.File.DebugFormat = null, /// (Zig compiler development) Enable dumping linker's state as JSON. enable_link_snapshots: bool = false, /// (Darwin) Install name of the dylib @@ -1327,7 +1333,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { cache.hash.add(options.config.link_libcpp); cache.hash.add(options.config.link_libunwind); cache.hash.add(output_mode); - cache_helpers.addOptionalDebugFormat(&cache.hash, options.debug_format); + cache_helpers.addDebugFormat(&cache.hash, comp.config.debug_format); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs); @@ -1380,7 +1386,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { }; errdefer if (opt_zcu) |zcu| zcu.deinit(); - const system_libs = try std.StringArrayHashMapUnmanaged(SystemLib).init( + var system_libs = try std.StringArrayHashMapUnmanaged(SystemLib).init( gpa, options.system_lib_names, options.system_lib_infos, @@ -1409,7 +1415,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa), .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa), .embed_file_work_queue = std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic).init(gpa), - .keep_source_files_loaded = options.keep_source_files_loaded, .c_source_files = options.c_source_files, .rc_source_files = options.rc_source_files, .cache_parent = cache, @@ -1451,10 +1456,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, .skip_linker_dependencies = options.skip_linker_dependencies, .no_builtin = options.no_builtin, + .job_queued_update_builtin_zig = have_zcu, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }; const lf_open_opts: link.File.OpenOptions = .{ - .comp = comp, .linker_script = options.linker_script, .z_nodelete = options.linker_z_nodelete, .z_notext = options.linker_z_notext, @@ -1471,8 +1478,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .lib_dirs = options.lib_dirs, .rpath_list = options.rpath_list, .symbol_wrap_set = options.symbol_wrap_set, - .function_sections = options.function_sections, - .data_sections = options.data_sections, .allow_shlib_undefined = options.linker_allow_shlib_undefined, .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, .compress_debug_sections = options.linker_compress_debug_sections orelse .none, @@ -1507,7 +1512,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .build_id = build_id, .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, .subsystem = options.subsystem, - .debug_format = options.debug_format, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, .install_name = options.install_name, @@ -1572,17 +1576,17 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .directory = emit_bin.directory orelse artifact_directory, .sub_path = emit_bin.basename, }; - comp.bin_file = try link.File.open(arena, emit, lf_open_opts); + comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts); } - if (options.implib_emit) |emit_implib| { + if (options.emit_implib) |emit_implib| { comp.implib_emit = .{ .directory = emit_implib.directory orelse artifact_directory, .sub_path = emit_implib.basename, }; } - if (options.docs_emit) |emit_docs| { + if (options.emit_docs) |emit_docs| { comp.docs_emit = .{ .directory = emit_docs.directory orelse artifact_directory, .sub_path = emit_docs.basename, @@ -1610,6 +1614,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .bin_sub_path = try prepareWholeEmitSubPath(arena, options.emit_bin), .implib_sub_path = try prepareWholeEmitSubPath(arena, options.emit_implib), .docs_sub_path = try prepareWholeEmitSubPath(arena, options.emit_docs), + .tmp_artifact_directory = null, }; comp.cache_use = .{ .whole = whole }; }, @@ -1662,7 +1667,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - const have_bin_emit = comp.bin_file != null or comp.whole_bin_sub_path != null; + const have_bin_emit = switch (comp.cache_use) { + .whole => |whole| whole.bin_sub_path != null, + .incremental => comp.bin_file != null, + }; if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) { if (target.isDarwin()) { @@ -1814,8 +1822,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { pub fn destroy(self: *Compilation) void { if (self.bin_file) |lf| lf.destroy(); if (self.module) |zcu| zcu.deinit(); + switch (self.cache_use) { + .incremental => |incremental| { + incremental.artifact_directory.handle.close(); + }, + .whole => {}, + } - const gpa = self.gpa; self.work_queue.deinit(); self.anon_work_queue.deinit(); self.c_object_work_queue.deinit(); @@ -1825,6 +1838,9 @@ pub fn destroy(self: *Compilation) void { self.astgen_work_queue.deinit(); self.embed_file_work_queue.deinit(); + const gpa = self.gpa; + self.system_libs.deinit(gpa); + { var it = self.crt_files.iterator(); while (it.next()) |entry| { @@ -1914,7 +1930,7 @@ pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.C } fn cleanupAfterUpdate(comp: *Compilation) void { - switch (comp) { + switch (comp.cache_use) { .incremental => return, .whole => |whole| { if (whole.cache_manifest) |man| { @@ -1971,7 +1987,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); const digest = man.final(); - comp.wholeCacheModeSetBinFilePath(&digest); + comp.wholeCacheModeSetBinFilePath(whole, &digest); assert(comp.bin_file.lock == null); comp.bin_file.lock = man.toOwnedLock(); @@ -2001,21 +2017,21 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // Now that the directory is known, it is time to create the Emit // objects and call link.File.open. - if (comp.whole_implib_sub_path) |sub_path| { + if (whole.implib_sub_path) |sub_path| { comp.implib_emit = .{ .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), }; } - if (comp.whole_docs_sub_path) |sub_path| { + if (whole.docs_sub_path) |sub_path| { comp.docs_emit = .{ .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), }; } - if (comp.whole_bin_sub_path) |sub_path| { + if (whole.bin_sub_path) |sub_path| { const emit: Emit = .{ .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), @@ -2024,7 +2040,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // but in practice it won't leak much and usually whole cache mode // will be combined with exactly one call to update(). const arena = comp.arena.allocator(); - comp.bin_file = try link.File.open(arena, emit, whole.lf_open_opts); + comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts); } }, .incremental => {}, @@ -2158,7 +2174,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void const o_sub_path = "o" ++ s ++ digest; try renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path); - comp.wholeCacheModeSetBinFilePath(&digest); + comp.wholeCacheModeSetBinFilePath(whole, &digest); // Failure here only means an unnecessary cache miss. man.writeManifest() catch |err| { @@ -2170,19 +2186,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void }, .incremental => {}, } - - // Unload all source files to save memory. - // The ZIR needs to stay loaded in memory because (1) Decl objects contain references - // to it, and (2) generic instantiations, comptime calls, inline calls will need - // to reference the ZIR. - if (!comp.keep_source_files_loaded) { - if (comp.module) |module| { - for (module.import_table.values()) |file| { - file.unloadTree(comp.gpa); - file.unloadSource(comp.gpa); - } - } - } } /// This function is called by the frontend before flush(). It communicates that @@ -2274,10 +2277,14 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { } /// Communicate the output binary location to parent Compilations. -fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_digest_len]u8) void { +fn wholeCacheModeSetBinFilePath( + comp: *Compilation, + whole: *CacheUse.Whole, + digest: *const [Cache.hex_digest_len]u8, +) void { const digest_start = 2; // "o/[digest]/[basename]" - if (comp.whole_bin_sub_path) |sub_path| { + if (whole.bin_sub_path) |sub_path| { @memcpy(sub_path[digest_start..][0..digest.len], digest); comp.bin_file.?.emit = .{ @@ -2286,7 +2293,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di }; } - if (comp.whole_implib_sub_path) |sub_path| { + if (whole.implib_sub_path) |sub_path| { @memcpy(sub_path[digest_start..][0..digest.len], digest); comp.implib_emit = .{ @@ -2295,7 +2302,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di }; } - if (comp.whole_docs_sub_path) |sub_path| { + if (whole.docs_sub_path) |sub_path| { @memcpy(sub_path[digest_start..][0..digest.len], digest); comp.docs_emit = .{ @@ -3232,13 +3239,25 @@ pub fn performAllTheWork( // 1. to avoid race condition of zig processes truncating each other's builtin.zig files // 2. optimization; in the hot path it only incurs a stat() syscall, which happens // in the `astgen_wait_group`. - if (comp.module) |mod| { - if (mod.job_queued_update_builtin_zig) { - mod.job_queued_update_builtin_zig = false; + if (comp.job_queued_update_builtin_zig) b: { + comp.job_queued_update_builtin_zig = false; + const zcu = comp.module orelse break :b; + _ = zcu; + // TODO put all the modules in a flat array to make them easy to iterate. + var seen: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{}; + defer seen.deinit(comp.gpa); + try seen.put(comp.gpa, comp.root_mod); + var i: usize = 0; + while (i < seen.count()) : (i += 1) { + const mod = seen.keys()[i]; + for (mod.deps.values()) |dep| + try seen.put(comp.gpa, dep); + + const file = mod.builtin_file orelse continue; comp.astgen_wait_group.start(); try comp.thread_pool.spawn(workerUpdateBuiltinZigFile, .{ - comp, mod, &comp.astgen_wait_group, + comp, mod, file, &comp.astgen_wait_group, }); } } @@ -3702,19 +3721,17 @@ fn workerAstGenFile( fn workerUpdateBuiltinZigFile( comp: *Compilation, - mod: *Module, + mod: *Package.Module, + file: *Module.File, wg: *WaitGroup, ) void { defer wg.finish(); - - mod.populateBuiltinFile() catch |err| { - const dir_path: []const u8 = mod.zig_cache_artifact_directory.path orelse "."; - + Builtin.populateFile(comp, mod, file) catch |err| { comp.mutex.lock(); defer comp.mutex.unlock(); - comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{ - dir_path, @errorName(err), + comp.setMiscFailure(.write_builtin_zig, "unable to write '{}{s}': {s}", .{ + mod.root, mod.root_src_path, @errorName(err), }); }; } @@ -3755,14 +3772,17 @@ fn detectEmbedFileUpdate(comp: *Compilation, embed_file: *Module.EmbedFile) !voi @panic("TODO: handle embed file incremental update"); } -pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { +pub fn obtainCObjectCacheManifest( + comp: *const Compilation, + owner_mod: *Package.Module, +) Cache.Manifest { var man = comp.cache_parent.obtain(); // Only things that need to be added on top of the base hash, and only things // that apply both to @cImport and compiling C objects. No linking stuff here! // Also nothing that applies only to compiling .zig code. - man.hash.add(comp.sanitize_c); - man.hash.addListOfBytes(comp.clang_argv); + man.hash.add(owner_mod.sanitize_c); + man.hash.addListOfBytes(owner_mod.clang_argv); man.hash.add(comp.config.link_libcpp); // When libc_installation is null it means that Zig generated this dir list @@ -3797,19 +3817,19 @@ pub const CImportResult = struct { /// Caller owns returned memory. /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked /// a bit when we want to start using it from self-hosted. -pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { +pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult { if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build"); const tracy_trace = trace(@src()); defer tracy_trace.end(); const cimport_zig_basename = "cimport.zig"; - var man = comp.obtainCObjectCacheManifest(); + var man = comp.obtainCObjectCacheManifest(owner_mod); defer man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects man.hash.addBytes(c_src); - man.hash.add(comp.c_frontend); + man.hash.add(comp.config.c_frontend); // If the previous invocation resulted in clang errors, we will see a hit // here with 0 files in the manifest, in which case it is actually a miss. @@ -3846,15 +3866,15 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { var argv = std.ArrayList([]const u8).init(comp.gpa); defer argv.deinit(); - try argv.append(@tagName(comp.c_frontend)); // argv[0] is program name, actual args start at [1] - try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path); + try argv.append(@tagName(comp.config.c_frontend)); // argv[0] is program name, actual args start at [1] + try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path, owner_mod); try argv.append(out_h_path); if (comp.verbose_cc) { dump_argv(argv.items); } - var tree = switch (comp.c_frontend) { + var tree = switch (comp.config.c_frontend) { .aro => tree: { const translate_c = @import("aro_translate_c.zig"); _ = translate_c; @@ -4119,7 +4139,7 @@ fn reportRetryableEmbedFileError( } fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void { - if (comp.c_frontend == .aro) { + if (comp.config.c_frontend == .aro) { return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); } if (!build_options.have_llvm) { @@ -4142,7 +4162,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P _ = comp.failed_c_objects.swapRemove(c_object); } - var man = comp.obtainCObjectCacheManifest(); + var man = comp.obtainCObjectCacheManifest(c_object.src.owner); defer man.deinit(); man.hash.add(comp.clang_preprocessor_mode); @@ -4219,7 +4239,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P if (std.process.can_execv and direct_o and comp.disable_c_depfile and comp.clang_passthrough_mode) { - try comp.addCCArgs(arena, &argv, ext, null); + try comp.addCCArgs(arena, &argv, ext, null, c_object.src.owner); try argv.appendSlice(c_object.src.extra_flags); try argv.appendSlice(c_object.src.cache_exempt_flags); @@ -4262,7 +4282,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P null else try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); - try comp.addCCArgs(arena, &argv, ext, out_dep_path); + try comp.addCCArgs(arena, &argv, ext, out_dep_path, c_object.src.owner); try argv.appendSlice(c_object.src.extra_flags); try argv.appendSlice(c_object.src.cache_exempt_flags); @@ -4610,7 +4630,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // mode. While these defines are not normally present when calling rc.exe directly, // them being defined matches the behavior of how MSVC calls rc.exe which is the more // relevant behavior in this case. - try comp.addCCArgs(arena, &argv, .rc, out_dep_path); + try comp.addCCArgs(arena, &argv, .rc, out_dep_path, rc_src.owner); if (comp.verbose_cc) { dump_argv(argv.items); @@ -4788,11 +4808,12 @@ pub fn addTranslateCCArgs( argv: *std.ArrayList([]const u8), ext: FileExt, out_dep_path: ?[]const u8, + owner_mod: *Package.Module, ) !void { - try argv.appendSlice(&[_][]const u8{ "-x", "c" }); - try comp.addCCArgs(arena, argv, ext, out_dep_path); + try argv.appendSlice(&.{ "-x", "c" }); + try comp.addCCArgs(arena, argv, ext, out_dep_path, owner_mod); // This gives us access to preprocessing entities, presumably at the cost of performance. - try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" }); + try argv.appendSlice(&.{ "-Xclang", "-detailed-preprocessing-record" }); } /// Add common C compiler args between translate-c and C object compilation. @@ -4825,11 +4846,11 @@ pub fn addCCArgs( try argv.append("-fno-caret-diagnostics"); } - if (comp.bin_file.function_sections) { + if (comp.function_sections) { try argv.append("-ffunction-sections"); } - if (comp.bin_file.data_sections) { + if (comp.data_sections) { try argv.append("-fdata-sections"); } @@ -5088,7 +5109,7 @@ pub fn addCCArgs( try argv.append("-fPIC"); } - if (comp.unwind_tables) { + if (mod.unwind_tables) { try argv.append("-funwind-tables"); } else { try argv.append("-fno-unwind-tables"); @@ -5174,7 +5195,7 @@ pub fn addCCArgs( } try argv.ensureUnusedCapacity(2); - switch (comp.bin_file.debug_format) { + switch (comp.config.debug_format) { .strip => {}, .code_view => { // -g is required here because -gcodeview doesn't trigger debug info @@ -5210,7 +5231,7 @@ pub fn addCCArgs( try argv.append("-ffreestanding"); } - try argv.appendSlice(comp.clang_argv); + try argv.appendSlice(mod.cc_argv); } fn failCObj( @@ -6094,6 +6115,7 @@ fn buildOutputFromZig( .have_zcu = true, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), .link_libc = comp.config.link_libc, .any_unwind_tables = unwind_tables, }); @@ -6198,6 +6220,7 @@ pub fn build_crt_file( .have_zcu = false, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), .link_libc = false, .lto = switch (output_mode) { .Lib => comp.config.lto, diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index aba21e4bfe..0afb633c86 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -33,9 +33,16 @@ shared_memory: bool, is_test: bool, test_evented_io: bool, entry: ?[]const u8, +debug_format: DebugFormat, pub const CFrontend = enum { clang, aro }; +pub const DebugFormat = union(enum) { + strip, + dwarf: std.dwarf.Format, + code_view, +}; + pub const Options = struct { output_mode: std.builtin.OutputMode, resolved_target: Module.ResolvedTarget, @@ -43,6 +50,7 @@ pub const Options = struct { have_zcu: bool, emit_bin: bool, root_optimize_mode: ?std.builtin.OptimizeMode = null, + root_strip: ?bool = null, link_mode: ?std.builtin.LinkMode = null, ensure_libc_on_non_freestanding: bool = false, ensure_libcpp_on_non_freestanding: bool = false, @@ -51,6 +59,7 @@ pub const Options = struct { any_unwind_tables: bool = false, any_dyn_libs: bool = false, any_c_source_files: bool = false, + any_non_stripped: bool = false, emit_llvm_ir: bool = false, emit_llvm_bc: bool = false, link_libc: ?bool = null, @@ -74,6 +83,7 @@ pub const Options = struct { export_memory: ?bool = null, shared_memory: ?bool = null, test_evented_io: bool = false, + debug_format: ?Config.DebugFormat = null, }; pub fn resolve(options: Options) !Config { @@ -365,6 +375,26 @@ pub fn resolve(options: Options) !Config { break :b false; }; + const root_strip = b: { + if (options.root_strip) |x| break :b x; + if (root_optimize_mode == .ReleaseSmall) break :b true; + if (!target_util.hasDebugInfo(target)) break :b true; + break :b false; + }; + + const debug_format: DebugFormat = b: { + if (root_strip and !options.any_non_stripped) break :b .strip; + break :b switch (target.ofmt) { + .elf, .macho, .wasm => .{ .dwarf = .@"32" }, + .coff => .code_view, + .c => switch (target.os.tag) { + .windows, .uefi => .code_view, + else => .{ .dwarf = .@"32" }, + }, + .spirv, .nvptx, .dxcontainer, .hex, .raw, .plan9 => .strip, + }; + }; + return .{ .output_mode = options.output_mode, .have_zcu = options.have_zcu, @@ -388,6 +418,7 @@ pub fn resolve(options: Options) !Config { .use_lld = use_lld, .entry = entry, .wasi_exec_model = wasi_exec_model, + .debug_format = debug_format, }; } diff --git a/src/Module.zig b/src/Module.zig index e32bad7295..121f639f6b 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -152,8 +152,6 @@ stage1_flags: packed struct { reserved: u2 = 0, } = .{}, -job_queued_update_builtin_zig: bool = true, - compile_log_text: ArrayListUnmanaged(u8) = .{}, emit_h: ?*GlobalEmitH, @@ -2490,7 +2488,6 @@ pub fn deinit(mod: *Module) void { mod.compile_log_text.deinit(gpa); - mod.zig_cache_artifact_directory.handle.close(); mod.local_zir_cache.handle.close(); mod.global_zir_cache.handle.close(); @@ -3075,72 +3072,6 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { } } -pub fn populateBuiltinFile(mod: *Module) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const comp = mod.comp; - const builtin_mod, const file = blk: { - comp.mutex.lock(); - defer comp.mutex.unlock(); - - const builtin_mod = mod.main_mod.deps.get("builtin").?; - const result = try mod.importPkg(builtin_mod); - break :blk .{ builtin_mod, result.file }; - }; - const gpa = mod.gpa; - file.source = try comp.generateBuiltinZigSource(gpa); - file.source_loaded = true; - - if (builtin_mod.root.statFile(builtin_mod.root_src_path)) |stat| { - if (stat.size != file.source.len) { - log.warn( - "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++ - "Overwriting with correct file contents now", - .{ builtin_mod.root, builtin_mod.root_src_path, file.source.len, stat.size }, - ); - - try writeBuiltinFile(file, builtin_mod); - } else { - file.stat = .{ - .size = stat.size, - .inode = stat.inode, - .mtime = stat.mtime, - }; - } - } else |err| switch (err) { - error.BadPathName => unreachable, // it's always "builtin.zig" - error.NameTooLong => unreachable, // it's always "builtin.zig" - error.PipeBusy => unreachable, // it's not a pipe - error.WouldBlock => unreachable, // not asking for non-blocking I/O - - error.FileNotFound => try writeBuiltinFile(file, builtin_mod), - - else => |e| return e, - } - - file.tree = try Ast.parse(gpa, file.source, .zig); - file.tree_loaded = true; - assert(file.tree.errors.len == 0); // builtin.zig must parse - - file.zir = try AstGen.generate(gpa, file.tree); - file.zir_loaded = true; - file.status = .success_zir; -} - -fn writeBuiltinFile(file: *File, builtin_mod: *Package.Module) !void { - var af = try builtin_mod.root.atomicFile(builtin_mod.root_src_path, .{}); - defer af.deinit(); - try af.file.writeAll(file.source); - try af.finish(); - - file.stat = .{ - .size = file.source.len, - .inode = 0, // dummy value - .mtime = 0, // dummy value - }; -} - pub fn mapOldZirToNew( gpa: Allocator, old_zir: Zir, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 0916742876..051303ca26 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -33,11 +33,16 @@ cc_argv: []const []const u8, /// (SPIR-V) whether to generate a structured control flow graph or not structured_cfg: bool, -/// The contents of `@import("builtin")` for this module. -generated_builtin_source: []const u8, +/// If the module is an `@import("builtin")` module, this is the `File` that +/// is preallocated for it. Otherwise this field is null. +builtin_file: ?*File, pub const Deps = std.StringArrayHashMapUnmanaged(*Module); +pub fn isBuiltin(m: Module) bool { + return m.file != null; +} + pub const Tree = struct { /// Each `Package` exposes a `Module` with build.zig as its root source file. build_module_table: std.AutoArrayHashMapUnmanaged(MultiHashHexDigest, *Module), @@ -329,6 +334,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .wasi_exec_model = options.global.wasi_exec_model, }, arena); + const new_file = try arena.create(File); + const digest = Cache.HashHelper.oneShot(generated_builtin_source); const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ digest); const new = try arena.create(Module); @@ -359,12 +366,25 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .stack_protector = stack_protector, .code_model = code_model, .red_zone = red_zone, - .generated_builtin_source = generated_builtin_source, .sanitize_c = sanitize_c, .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = &.{}, .structured_cfg = structured_cfg, + .builtin_file = new_file, + }; + new_file.* = .{ + .sub_file_path = "builtin.zig", + .source = generated_builtin_source, + .source_loaded = true, + .tree_loaded = false, + .zir_loaded = false, + .stat = undefined, + .tree = undefined, + .zir = undefined, + .status = .never_loaded, + .mod = new, + .root_decl = .none, }; break :b new; }; @@ -391,12 +411,12 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .stack_protector = stack_protector, .code_model = code_model, .red_zone = red_zone, - .generated_builtin_source = builtin_mod.generated_builtin_source, .sanitize_c = sanitize_c, .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = options.cc_argv, .structured_cfg = structured_cfg, + .builtin_file = null, }; try mod.deps.ensureUnusedCapacity(arena, 1); @@ -437,8 +457,8 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P .sanitize_thread = undefined, .unwind_tables = undefined, .cc_argv = undefined, - .generated_builtin_source = undefined, .structured_cfg = undefined, + .builtin_file = null, }; return mod; } @@ -457,3 +477,4 @@ const Cache = std.Build.Cache; const Builtin = @import("../Builtin.zig"); const assert = std.debug.assert; const Compilation = @import("../Compilation.zig"); +const File = @import("../Module.zig").File; diff --git a/src/Sema.zig b/src/Sema.zig index 910b1cca47..2d46faf435 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -784,6 +784,11 @@ pub const Block = struct { } } + pub fn ownerModule(block: Block) *Package.Module { + const zcu = block.sema.mod; + return zcu.namespacePtr(block.namespace).file_scope.mod; + } + pub fn startAnonDecl(block: *Block) !WipAnonDecl { return WipAnonDecl{ .block = block, @@ -5733,7 +5738,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr // Ignore the result, all the relevant operations have written to c_import_buf already. _ = try sema.analyzeBodyBreak(&child_block, body); - var c_import_res = comp.cImport(c_import_buf.items) catch |err| + var c_import_res = comp.cImport(c_import_buf.items, parent_block.ownerModule()) catch |err| return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); defer c_import_res.deinit(gpa); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ee9e3de086..709b2bf6a9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -854,9 +854,8 @@ pub const Object = struct { /// want to iterate over it while adding entries to it. pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); - pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object { + pub fn create(arena: Allocator, comp: *Compilation) !*Object { if (build_options.only_c) unreachable; - const comp = options.comp; const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; const llvm_target_triple = try targetTriple(arena, target); @@ -878,14 +877,7 @@ pub const Object = struct { var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined; if (builder.useLibLlvm()) { debug_info: { - const debug_format = options.debug_format orelse b: { - if (strip) break :b .strip; - break :b switch (target.ofmt) { - .coff => .code_view, - else => .{ .dwarf = .@"32" }, - }; - }; - switch (debug_format) { + switch (comp.config.debug_format) { .strip => break :debug_info, .code_view => builder.llvm.module.?.addModuleCodeViewFlag(), .dwarf => |f| builder.llvm.module.?.addModuleDebugInfoFlag(f == .@"64"), @@ -961,8 +953,8 @@ pub const Object = struct { opt_level, reloc_mode, code_model, - options.function_sections orelse false, - options.data_sections orelse false, + comp.function_sections, + comp.data_sections, float_abi, if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, ); diff --git a/src/libunwind.zig b/src/libunwind.zig index 9215e24f7c..bc1c0d0343 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -28,6 +28,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .have_zcu = false, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), .link_libc = true, // Disable LTO to avoid https://github.com/llvm/llvm-project/issues/56825 .lto = false, @@ -131,7 +132,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .libc_installation = comp.libc_installation, .emit_bin = emit_bin, .link_mode = link_mode, - .function_sections = comp.bin_file.function_sections, + .function_sections = comp.function_sections, .c_source_files = &c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, diff --git a/src/link.zig b/src/link.zig index 2a61e46969..91def2a134 100644 --- a/src/link.zig +++ b/src/link.zig @@ -68,9 +68,6 @@ pub const File = struct { force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), allow_shlib_undefined: bool, stack_size: u64, - debug_format: DebugFormat, - function_sections: bool, - data_sections: bool, /// Prevents other processes from clobbering files in the output directory /// of this linking operation. @@ -78,16 +75,7 @@ pub const File = struct { child_pid: ?std.ChildProcess.Id = null, - pub const DebugFormat = union(enum) { - strip, - dwarf: std.dwarf.Format, - code_view, - }; - pub const OpenOptions = struct { - comp: *Compilation, - emit: Compilation.Emit, - symbol_count_hint: u64 = 32, program_code_size_hint: u64 = 256 * 1024, @@ -95,8 +83,6 @@ pub const File = struct { entry_addr: ?u64, stack_size: ?u64, image_base: ?u64, - function_sections: bool, - data_sections: bool, eh_frame_hdr: bool, emit_relocs: bool, rdynamic: bool, @@ -150,8 +136,6 @@ pub const File = struct { compatibility_version: ?std.SemanticVersion, - debug_format: ?DebugFormat, - // TODO: remove this. libraries are resolved by the frontend. lib_dirs: []const []const u8, rpath_list: []const []const u8, @@ -190,10 +174,29 @@ pub const File = struct { /// rewriting it. A malicious file is detected as incremental link failure /// and does not cause Illegal Behavior. This operation is not atomic. /// `arena` is used for allocations with the same lifetime as the created File. - pub fn open(arena: Allocator, options: OpenOptions) !*File { - switch (Tag.fromObjectFormat(options.comp.root_mod.resolved_target.result.ofmt)) { + pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: OpenOptions, + ) !*File { + switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { + inline else => |tag| { + const ptr = try tag.Type().open(arena, comp, emit, options); + return &ptr.base; + }, + } + } + + pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: OpenOptions, + ) !*File { + switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { inline else => |tag| { - const ptr = try tag.Type().open(arena, options); + const ptr = try tag.Type().createEmpty(arena, comp, emit, options); return &ptr.base; }, } diff --git a/src/link/C.zig b/src/link/C.zig index 043ca0ce6f..ce44cc4c06 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -92,21 +92,24 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String { }; } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { - const target = options.comp.root_mod.resolved_target.result; +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*C { + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .c); - const optimize_mode = options.comp.root_mod.optimize_mode; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; - const output_mode = options.comp.config.output_mode; - const link_mode = options.comp.config.link_mode; + const optimize_mode = comp.root_mod.optimize_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; // These are caught by `Compilation.Config.resolve`. assert(!use_lld); assert(!use_llvm); - const emit = options.emit; - const file = try emit.directory.handle.createFile(emit.sub_path, .{ // Truncation is done on `flush`. .truncate = false, @@ -119,7 +122,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { c_file.* = .{ .base = .{ .tag = .c, - .comp = options.comp, + .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), .stack_size = options.stack_size orelse 16777216, @@ -129,9 +132,6 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, }; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index db99ba189c..eba24f0d17 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -234,44 +234,49 @@ const ideal_factor = 3; const minimum_text_block_size = 64; pub const min_text_capacity = padToIdeal(minimum_text_block_size); -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Coff { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .coff); - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; if (use_lld and use_llvm) { // LLVM emits the object file; LLD links it into the final product. return self; } - const sub_path = if (!use_lld) options.emit.sub_path else p: { + const sub_path = if (!use_lld) emit.sub_path else p: { // Open a temporary object file, not the final output file because we // want to link with LLD. const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + emit.sub_path, target.ofmt.fileExt(target.cpu.arch), }); self.base.intermediary_basename = o_file_path; break :p o_file_path; }; - self.base.file = try options.emit.directory.handle.createFile(sub_path, .{ + self.base.file = try emit.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.File.determineMode( use_lld, - options.comp.config.output_mode, - options.comp.config.link_mode, + comp.config.output_mode, + comp.config.link_mode, ), }); assert(self.llvm_object == null); - const gpa = self.base.comp.gpa; + const gpa = comp.gpa; try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); @@ -362,8 +367,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff { return self; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Coff { const target = comp.root_mod.resolved_target.result; const optimize_mode = comp.root_mod.optimize_mode; const output_mode = comp.config.output_mode; @@ -380,7 +389,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { .base = .{ .tag = .coff, .comp = comp, - .emit = options.emit, + .emit = emit, .stack_size = options.stack_size orelse 16777216, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -389,9 +398,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .code_view, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .ptr_width = ptr_width, .page_size = page_size, @@ -423,7 +429,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { const use_llvm = comp.config.use_llvm; if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, options); + self.llvm_object = try LlvmObject.create(arena, comp); } return self; } diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index 1719d5fa67..ad9e18fa22 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -171,7 +171,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append("-ERRORLIMIT:0"); try argv.append("-NOLOGO"); - if (self.base.debug_format != .strip) { + if (comp.config.debug_format != .strip) { try argv.append("-DEBUG"); const out_ext = std.fs.path.extension(full_out_path); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b54bde325f..5f96e195ab 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -228,18 +228,23 @@ pub const HashStyle = enum { sysv, gnu, both }; pub const CompressDebugSections = enum { none, zlib, zstd }; pub const SortSection = enum { name, alignment }; -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Elf { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .elf); - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; - const opt_zcu = options.comp.module; - const output_mode = options.comp.config.output_mode; - const link_mode = options.comp.config.link_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + const opt_zcu = comp.module; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); if (use_lld and use_llvm) { @@ -250,23 +255,23 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { const is_obj = output_mode == .Obj; const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .Static); - const sub_path = if (!use_lld) options.emit.sub_path else p: { + const sub_path = if (!use_lld) emit.sub_path else p: { // Open a temporary object file, not the final output file because we // want to link with LLD. const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + emit.sub_path, target.ofmt.fileExt(target.cpu.arch), }); self.base.intermediary_basename = o_file_path; break :p o_file_path; }; - self.base.file = try options.emit.directory.handle.createFile(sub_path, .{ + self.base.file = try emit.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.File.determineMode(use_lld, output_mode, link_mode), }); - const gpa = options.comp.gpa; + const gpa = comp.gpa; // Index 0 is always a null symbol. try self.symbols.append(gpa, .{}); @@ -343,8 +348,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { return self; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Elf { const use_llvm = comp.config.use_llvm; const optimize_mode = comp.root_mod.optimize_mode; const target = comp.root_mod.resolved_target.result; @@ -373,7 +382,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .base = .{ .tag = .elf, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os, @@ -382,9 +391,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .ptr_width = ptr_width, .page_size = page_size, @@ -423,7 +429,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .version_script = options.version_script, }; if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, options); + self.llvm_object = try LlvmObject.create(arena, comp); } return self; @@ -1753,7 +1759,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("-pie"); } - if (self.base.debug_format == .strip) { + if (comp.config.debug_format == .strip) { try argv.append("-s"); } @@ -2640,7 +2646,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--export-dynamic"); } - if (self.base.debug_format == .strip) { + if (comp.config.debug_format == .strip) { try argv.append("-s"); } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 5fa31711e6..0bf1e837e3 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -293,13 +293,14 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem } fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { + const comp = elf_file.base.comp; const shdr = self.shdrs.items[index]; const name = self.getString(shdr.sh_name); const ignore = blk: { if (mem.startsWith(u8, name, ".note")) break :blk true; if (mem.startsWith(u8, name, ".comment")) break :blk true; if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; - if (elf_file.base.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and + if (comp.config.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and mem.startsWith(u8, name, ".debug")) break :blk true; break :blk false; }; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 05ff55dd18..75bc53bb48 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -76,7 +76,8 @@ pub const symbol_mask: u32 = 0x7fffffff; pub const SHN_ATOM: u16 = 0x100; pub fn init(self: *ZigObject, elf_file: *Elf) !void { - const gpa = elf_file.base.comp.gpa; + const comp = elf_file.base.comp; + const gpa = comp.gpa; try self.atoms.append(gpa, 0); // null input section try self.relocs.append(gpa, .{}); // null relocs section @@ -96,8 +97,13 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { esym.st_shndx = elf.SHN_ABS; symbol_ptr.esym_index = esym_index; - if (elf_file.base.debug_format != .strip) { - self.dwarf = Dwarf.init(&elf_file.base, .dwarf32); + switch (comp.config.debug_format) { + .strip => {}, + .dwarf => |v| { + assert(v == .@"32"); + self.dwarf = Dwarf.init(&elf_file.base, .dwarf32); + }, + .code_view => unreachable, } } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 87faec6537..25d59f3de3 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -182,18 +182,21 @@ pub const SdkLayout = enum { vendored, }; -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*MachO { if (build_options.only_c) unreachable; - const comp = options.comp; const target = comp.root_mod.resolved_target.result; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; assert(target.ofmt == .macho); const gpa = comp.gpa; - const emit = options.emit; const mode: Mode = mode: { - if (use_llvm or comp.module == null or comp.cache_mode == .whole) + if (use_llvm or comp.module == null or comp.cache_use == .whole) break :mode .zld; break :mode .incremental; }; @@ -201,7 +204,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { if (comp.module == null) { // No point in opening a file, we would not write anything to it. // Initialize with empty. - return createEmpty(arena, options); + return createEmpty(arena, comp, emit, options); } // Open a temporary object file, not the final output file because we // want to link with LLD. @@ -210,7 +213,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { }); } else emit.sub_path; - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); if (mode == .zld) { @@ -232,7 +235,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { }); self.base.file = file; - if (self.base.debug_format != .strip and comp.module != null) { + if (comp.config.debug_format != .strip and comp.module != null) { // Create dSYM bundle. log.debug("creating {s}.dSYM bundle", .{sub_path}); @@ -279,8 +282,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { return self; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*MachO { const optimize_mode = comp.root_mod.optimize_mode; const use_llvm = comp.config.use_llvm; @@ -289,7 +296,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { .base = .{ .tag = .macho, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -298,11 +305,8 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, - .mode = if (use_llvm or comp.module == null or comp.cache_mode == .whole) + .mode = if (use_llvm or comp.module == null or comp.cache_use == .whole) .zld else .incremental, @@ -317,7 +321,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { }; if (use_llvm and comp.module != null) { - self.llvm_object = try LlvmObject.create(arena, options); + self.llvm_object = try LlvmObject.create(arena, comp); } log.debug("selected linker mode '{s}'", .{@tagName(self.mode)}); @@ -4313,7 +4317,8 @@ fn addLocalToSymtab(self: *MachO, sym_loc: SymbolWithLoc, locals: *std.ArrayList } fn writeSymtab(self: *MachO) !SymtabCtx { - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; var locals = std.ArrayList(macho.nlist_64).init(gpa); defer locals.deinit(); @@ -4368,7 +4373,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx { // We generate stabs last in order to ensure that the strtab always has debug info // strings trailing - if (self.base.debug_format != .strip) { + if (comp.config.debug_format != .strip) { for (self.objects.items) |object| { assert(self.d_sym == null); // TODO try self.generateSymbolStabs(object, &locals); diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index 846e496ec1..57a8352898 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -25,12 +25,17 @@ const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, llvm_object: *LlvmObject, -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*NvPtx { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; assert(use_llvm); // Caught by Compilation.Config.resolve. assert(!use_lld); // Caught by Compilation.Config.resolve. @@ -42,13 +47,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { else => return error.PtxArchNotSupported, } - const llvm_object = try LlvmObject.create(arena, options); + const llvm_object = try LlvmObject.create(arena, comp); const nvptx = try arena.create(NvPtx); nvptx.* = .{ .base = .{ .tag = .nvptx, - .comp = options.comp, - .emit = options.emit, + .comp = comp, + .emit = emit, .gc_sections = options.gc_sections orelse false, .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -57,9 +62,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .llvm_object = llvm_object, }; @@ -67,10 +69,15 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { return nvptx; } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { - const target = options.comp.root_mod.resolved_target.result; +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*NvPtx { + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .nvptx); - return createEmpty(arena, options); + return createEmpty(arena, comp, emit, options); } pub fn deinit(self: *NvPtx) void { diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index b3c08fb66b..c970e72e51 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -294,8 +294,12 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { }; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Plan9 { const target = comp.root_mod.resolved_target.result; const gpa = comp.gpa; const optimize_mode = comp.root_mod.optimize_mode; @@ -313,7 +317,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { .base = .{ .tag = .plan9, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -322,9 +326,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .sixtyfour_bit = sixtyfour_bit, .bases = undefined, @@ -1308,26 +1309,31 @@ pub fn deinit(self: *Plan9) void { } } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Plan9 { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; assert(!use_llvm); // Caught by Compilation.Config.resolve. assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.ofmt == .plan9); - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); - const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ + const file = try emit.directory.handle.createFile(emit.sub_path, .{ .read = true, .mode = link.File.determineMode( use_lld, - options.comp.config.output_mode, - options.comp.config.link_mode, + comp.config.output_mode, + comp.config.link_mode, ), }); errdefer file.close(); @@ -1335,7 +1341,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { self.bases = defaultBaseAddrs(target.cpu.arch); - const gpa = options.comp.gpa; + const gpa = comp.gpa; try self.syms.appendSlice(gpa, &.{ // we include the global offset table to make it easier for debugging diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index bb278a8e4a..853d97b014 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -49,16 +49,21 @@ object: codegen.Object, pub const base_tag: link.File.Tag = .spirv; -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { - const gpa = options.comp.gpa; - const target = options.comp.root_mod.resolved_target.result; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*SpirV { + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; const self = try arena.create(SpirV); self.* = .{ .base = .{ .tag = .spirv, - .comp = options.comp, - .emit = options.emit, + .comp = comp, + .emit = emit, .gc_sections = options.gc_sections orelse false, .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -67,9 +72,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .function_sections = options.function_sections, - .data_sections = options.data_sections, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, }, .object = codegen.Object.init(gpa), }; @@ -90,22 +92,27 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { return self; } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*SpirV { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; assert(!use_llvm); // Caught by Compilation.Config.resolve. assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.ofmt == .spirv); // Caught by Compilation.Config.resolve. - const spirv = try createEmpty(arena, options); + const spirv = try createEmpty(arena, comp, emit, options); errdefer spirv.base.destroy(); // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ + const file = try emit.directory.handle.createFile(emit.sub_path, .{ .truncate = true, .read = true, }); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 74d83e6c3c..8f63e7c6fd 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -373,9 +373,13 @@ pub const StringTable = struct { } }; -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Wasm { if (build_options.only_c) unreachable; - const comp = options.comp; const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .wasm); @@ -385,7 +389,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { const output_mode = comp.config.output_mode; const shared_memory = comp.config.shared_memory; - const wasm = try createEmpty(arena, options); + const wasm = try createEmpty(arena, comp, emit, options); errdefer wasm.base.destroy(); if (use_lld and use_llvm) { @@ -393,18 +397,18 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { return wasm; } - const sub_path = if (!use_lld) options.emit.sub_path else p: { + const sub_path = if (!use_lld) emit.sub_path else p: { // Open a temporary object file, not the final output file because we // want to link with LLD. const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + emit.sub_path, target.ofmt.fileExt(target.cpu.arch), }); wasm.base.intermediary_basename = o_file_path; break :p o_file_path; }; // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.directory.handle.createFile(sub_path, .{ + const file = try emit.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = if (fs.has_executable_bit) @@ -530,8 +534,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { return wasm; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Wasm { const use_llvm = comp.config.use_llvm; const output_mode = comp.config.output_mode; @@ -540,7 +548,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { .base = .{ .tag = .wasm, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (output_mode != .Obj), .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -549,9 +557,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .name = undefined, .import_table = options.import_table, @@ -566,7 +571,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { }; if (use_llvm) { - wasm.llvm_object = try LlvmObject.create(arena, options); + wasm.llvm_object = try LlvmObject.create(arena, comp); } return wasm; } @@ -4205,11 +4210,11 @@ fn writeToFile( if (data_section_index) |data_index| { try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table); } - } else if (wasm.base.debug_format != .strip) { + } else if (comp.config.debug_format != .strip) { try wasm.emitNameSection(&binary_bytes, arena); } - if (wasm.base.debug_format != .strip) { + if (comp.config.debug_format != .strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. switch (wasm.base.build_id) { @@ -4748,7 +4753,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append("--no-gc-sections"); } - if (wasm.base.debug_format == .strip) { + if (comp.config.debug_format == .strip) { try argv.append("-s"); } @@ -5276,7 +5281,9 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s fn markReferences(wasm: *Wasm) !void { const tracy = trace(@src()); defer tracy.end(); + const do_garbage_collect = wasm.base.gc_sections; + const comp = wasm.base.comp; for (wasm.resolved_symbols.keys()) |sym_loc| { const sym = sym_loc.getSymbol(wasm); @@ -5287,7 +5294,7 @@ fn markReferences(wasm: *Wasm) !void { // Debug sections may require to be parsed and marked when it contains // relocations to alive symbols. - if (sym.tag == .section and wasm.base.debug_format != .strip) { + if (sym.tag == .section and comp.config.debug_format != .strip) { const file = sym_loc.file orelse continue; // Incremental debug info is done independently const object = &wasm.objects.items[file]; const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm); diff --git a/src/main.zig b/src/main.zig index 9acad1a0ca..dbd9759015 100644 --- a/src/main.zig +++ b/src/main.zig @@ -892,7 +892,6 @@ fn buildOutputType( var contains_res_file: bool = false; var reference_trace: ?u32 = null; var pdb_out_path: ?[]const u8 = null; - var debug_format: ?link.File.DebugFormat = null; var error_limit: ?Module.ErrorInt = null; // These are before resolving sysroot. var lib_dir_args: std.ArrayListUnmanaged([]const u8) = .{}; @@ -1054,6 +1053,8 @@ fn buildOutputType( create_module.opts.any_sanitize_thread = true; if (mod_opts.unwind_tables == true) create_module.opts.any_unwind_tables = true; + if (mod_opts.strip == false) + create_module.opts.any_non_stripped = true; const root_src = try introspect.resolvePath(arena, root_src_orig); try create_module.modules.put(arena, mod_name, .{ @@ -1480,9 +1481,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-strip")) { mod_opts.strip = false; } else if (mem.eql(u8, arg, "-gdwarf32")) { - debug_format = .{ .dwarf = .@"32" }; + create_module.opts.debug_format = .{ .dwarf = .@"32" }; } else if (mem.eql(u8, arg, "-gdwarf64")) { - debug_format = .{ .dwarf = .@"64" }; + create_module.opts.debug_format = .{ .dwarf = .@"64" }; } else if (mem.eql(u8, arg, "-fformatted-panics")) { formatted_panics = true; } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { @@ -1989,11 +1990,11 @@ fn buildOutputType( }, .gdwarf32 => { mod_opts.strip = false; - debug_format = .{ .dwarf = .@"32" }; + create_module.opts.debug_format = .{ .dwarf = .@"32" }; }, .gdwarf64 => { mod_opts.strip = false; - debug_format = .{ .dwarf = .@"64" }; + create_module.opts.debug_format = .{ .dwarf = .@"64" }; }, .sanitize => { if (mem.eql(u8, it.only_arg, "undefined")) { @@ -2532,6 +2533,8 @@ fn buildOutputType( create_module.opts.any_sanitize_thread = true; if (mod_opts.unwind_tables == true) create_module.opts.any_unwind_tables = true; + if (mod_opts.strip == false) + create_module.opts.any_non_stripped = true; const src_path = try introspect.resolvePath(arena, unresolved_src_path); try create_module.modules.put(arena, "main", .{ @@ -3359,7 +3362,6 @@ fn buildOutputType( .emit_docs = emit_docs_resolved.data, .emit_implib = emit_implib_resolved.data, .dll_export_fns = dll_export_fns, - .keep_source_files_loaded = false, .lib_dirs = lib_dirs.items, .rpath_list = rpath_list.items, .symbol_wrap_set = symbol_wrap_set, @@ -3443,7 +3445,6 @@ fn buildOutputType( .test_runner_path = test_runner_path, .disable_lld_caching = !output_to_cache, .subsystem = subsystem, - .debug_format = debug_format, .debug_compile_errors = debug_compile_errors, .enable_link_snapshots = enable_link_snapshots, .install_name = install_name, @@ -3484,7 +3485,9 @@ fn buildOutputType( defer if (!comp_destroyed) comp.destroy(); if (show_builtin) { - return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena)); + const builtin_mod = comp.root_mod.deps.get("builtin").?; + const source = builtin_mod.builtin_file.?.source; + return std.io.getStdOut().writeAll(source); } switch (listen) { .none => {}, @@ -3737,6 +3740,7 @@ fn createModule( const resolved_target = cli_mod.inherited.resolved_target.?; create_module.opts.resolved_target = resolved_target; create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode; + create_module.opts.root_strip = cli_mod.inherited.strip; const target = resolved_target.result; // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. @@ -4366,12 +4370,12 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati const translated_zig_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{comp.root_name}); - var man: Cache.Manifest = comp.obtainCObjectCacheManifest(); + var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod); man.want_shared_lock = false; defer man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - man.hash.add(comp.c_frontend); + man.hash.add(comp.config.c_frontend); Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| { fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) }); }; @@ -4380,14 +4384,14 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati const digest = if (try man.hit()) man.final() else digest: { if (fancy_output) |p| p.cache_hit = false; var argv = std.ArrayList([]const u8).init(arena); - try argv.append(@tagName(comp.c_frontend)); // argv[0] is program name, actual args start at [1] + try argv.append(@tagName(comp.config.c_frontend)); // argv[0] is program name, actual args start at [1] var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); defer zig_cache_tmp_dir.close(); const ext = Compilation.classifyFileExt(c_source_file.src_path); const out_dep_path: ?[]const u8 = blk: { - if (comp.c_frontend == .aro or comp.disable_c_depfile or !ext.clangSupportsDepFile()) + if (comp.config.c_frontend == .aro or comp.disable_c_depfile or !ext.clangSupportsDepFile()) break :blk null; const c_src_basename = fs.path.basename(c_source_file.src_path); @@ -4397,14 +4401,15 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati }; // TODO - if (comp.c_frontend != .aro) try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path); + if (comp.config.c_frontend != .aro) + try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path, comp.root_mod); try argv.append(c_source_file.src_path); if (comp.verbose_cc) { Compilation.dump_argv(argv.items); } - var tree = switch (comp.c_frontend) { + var tree = switch (comp.config.c_frontend) { .aro => tree: { const aro = @import("aro"); const translate_c = @import("aro_translate_c.zig"); -- cgit v1.2.3 From c49957dbe82d7f0db555160b50306335bfa03165 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Dec 2023 18:47:58 -0700 Subject: fix a round of compile errors caused by this branch --- src/Compilation.zig | 153 +++++++++++++++++++++++++++---------------- src/Module.zig | 127 +++++++++++++++++++---------------- src/arch/aarch64/CodeGen.zig | 6 +- src/arch/aarch64/Emit.zig | 29 ++++---- src/arch/arm/CodeGen.zig | 8 ++- src/arch/arm/Emit.zig | 30 +++++---- src/arch/riscv64/CodeGen.zig | 6 +- src/arch/riscv64/Emit.zig | 4 +- src/arch/sparc64/CodeGen.zig | 5 +- src/arch/sparc64/Emit.zig | 29 ++++---- src/arch/wasm/CodeGen.zig | 10 +-- src/arch/wasm/Emit.zig | 24 +++++-- src/arch/x86_64/CodeGen.zig | 42 ++++++------ src/codegen.zig | 33 ++++++---- src/codegen/llvm.zig | 4 +- src/libunwind.zig | 2 +- src/link.zig | 63 ++++++++---------- src/link/C.zig | 12 +++- src/link/Coff.zig | 5 +- src/link/Coff/Atom.zig | 9 ++- src/link/Dwarf.zig | 2 +- src/link/Elf.zig | 52 +++++++-------- src/link/Elf/Atom.zig | 14 ++-- src/link/MachO.zig | 42 +++++------- src/link/MachO/Atom.zig | 12 ++-- src/link/Plan9.zig | 1 - 26 files changed, 411 insertions(+), 313 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 35ee243617..693e46c07c 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -884,12 +884,32 @@ const CacheUse = union(CacheMode) { docs_sub_path: ?[]u8, lf_open_opts: link.File.OpenOptions, tmp_artifact_directory: ?Cache.Directory, + /// Prevents other processes from clobbering files in the output directory. + lock: ?Cache.Lock, + + fn releaseLock(whole: *Whole) void { + if (whole.lock) |*lock| { + lock.release(); + whole.lock = null; + } + } }; const Incremental = struct { /// Where build artifacts and incremental compilation metadata serialization go. artifact_directory: Compilation.Directory, }; + + fn deinit(cu: CacheUse) void { + switch (cu) { + .incremental => |incremental| { + incremental.artifact_directory.handle.close(); + }, + .whole => |whole| { + whole.releaseLock(); + }, + } + } }; pub const LinkObject = struct { @@ -916,7 +936,7 @@ pub const InitOptions = struct { /// Normally, `main_mod` and `root_mod` are the same. The exception is `zig /// test`, in which `root_mod` is the test runner, and `main_mod` is the /// user's source file which has the tests. - main_mod: ?*Package.Module, + main_mod: ?*Package.Module = null, /// This is provided so that the API user has a chance to tweak the /// per-module settings of the standard library. std_mod: *Package.Module, @@ -1615,6 +1635,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .implib_sub_path = try prepareWholeEmitSubPath(arena, options.emit_implib), .docs_sub_path = try prepareWholeEmitSubPath(arena, options.emit_docs), .tmp_artifact_directory = null, + .lock = null, }; comp.cache_use = .{ .whole = whole }; }, @@ -1822,13 +1843,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { pub fn destroy(self: *Compilation) void { if (self.bin_file) |lf| lf.destroy(); if (self.module) |zcu| zcu.deinit(); - switch (self.cache_use) { - .incremental => |incremental| { - incremental.artifact_directory.handle.close(); - }, - .whole => {}, - } - + self.cache_use.deinit(); self.work_queue.deinit(); self.anon_work_queue.deinit(); self.c_object_work_queue.deinit(); @@ -1922,11 +1937,17 @@ pub fn getTarget(self: Compilation) Target { return self.root_mod.resolved_target.result; } -pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.ChildProcess.Id) !void { - comp.bin_file.child_pid = pid; - try comp.makeBinFileWritable(); +/// Only legal to call when cache mode is incremental and a link file is present. +pub fn hotCodeSwap( + comp: *Compilation, + prog_node: *std.Progress.Node, + pid: std.ChildProcess.Id, +) !void { + const lf = comp.bin_file.?; + lf.child_pid = pid; + try lf.makeWritable(); try comp.update(prog_node); - try comp.makeBinFileExecutable(); + try lf.makeExecutable(); } fn cleanupAfterUpdate(comp: *Compilation) void { @@ -1941,7 +1962,7 @@ fn cleanupAfterUpdate(comp: *Compilation) void { lf.destroy(); comp.bin_file = null; } - if (whole.tmp_artifact_directory) |directory| { + if (whole.tmp_artifact_directory) |*directory| { directory.handle.close(); if (directory.path) |p| comp.gpa.free(p); whole.tmp_artifact_directory = null; @@ -1967,8 +1988,9 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // C source files. switch (comp.cache_use) { .whole => |whole| { - // We are about to obtain this lock, so here we give other processes a chance first. assert(comp.bin_file == null); + // We are about to obtain this lock, so here we give other processes a chance first. + whole.releaseLock(); man = comp.cache_parent.obtain(); whole.cache_manifest = &man; @@ -1989,8 +2011,8 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void comp.wholeCacheModeSetBinFilePath(whole, &digest); - assert(comp.bin_file.lock == null); - comp.bin_file.lock = man.toOwnedLock(); + assert(whole.lock == null); + whole.lock = man.toOwnedLock(); return; } log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); @@ -2158,7 +2180,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // Rename the temporary directory into place. // Close tmp dir and link.File to avoid open handle during rename. - if (whole.tmp_artifact_directory) |tmp_directory| { + if (whole.tmp_artifact_directory) |*tmp_directory| { tmp_directory.handle.close(); if (tmp_directory.path) |p| comp.gpa.free(p); whole.tmp_artifact_directory = null; @@ -2181,8 +2203,8 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void log.warn("failed to write cache manifest: {s}", .{@errorName(err)}); }; - assert(comp.bin_file.lock == null); - comp.bin_file.lock = man.toOwnedLock(); + assert(whole.lock == null); + whole.lock = man.toOwnedLock(); }, .incremental => {}, } @@ -2263,13 +2285,15 @@ fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !voi } fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { - // This is needed before reading the error flags. - comp.bin_file.flush(comp, prog_node) catch |err| switch (err) { - error.FlushFailure => {}, // error reported through link_error_flags - error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr - else => |e| return e, - }; - comp.link_error_flags = comp.bin_file.errorFlags(); + if (comp.bin_file) |lf| { + // This is needed before reading the error flags. + lf.flush(comp, prog_node) catch |err| switch (err) { + error.FlushFailure => {}, // error reported through link_error_flags + error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr + else => |e| return e, + }; + comp.link_error_flags = lf.error_flags; + } if (comp.module) |module| { try link.File.C.flushEmitH(module); @@ -2445,9 +2469,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes .wasm => { const wasm = lf.cast(link.File.Wasm).?; man.hash.add(wasm.rdynamic); - man.hash.add(wasm.initial_memory); - man.hash.add(wasm.max_memory); - man.hash.add(wasm.global_base); + man.hash.addOptional(wasm.initial_memory); + man.hash.addOptional(wasm.max_memory); + man.hash.addOptional(wasm.global_base); }, .macho => { const macho = lf.cast(link.File.MachO).?; @@ -2626,12 +2650,14 @@ fn reportMultiModuleErrors(mod: *Module) !void { /// binary is concerned. This will remove the write flag, or close the file, /// or whatever is needed so that it can be executed. /// After this, one must call` makeFileWritable` before calling `update`. -pub fn makeBinFileExecutable(self: *Compilation) !void { - return self.bin_file.makeExecutable(); +pub fn makeBinFileExecutable(comp: *Compilation) !void { + const lf = comp.bin_file orelse return; + return lf.makeExecutable(); } -pub fn makeBinFileWritable(self: *Compilation) !void { - return self.bin_file.makeWritable(); +pub fn makeBinFileWritable(comp: *Compilation) !void { + const lf = comp.bin_file orelse return; + return lf.makeWritable(); } const Header = extern struct { @@ -2764,8 +2790,9 @@ pub fn totalErrorCount(self: *Compilation) u32 { } total += @intFromBool(self.link_error_flags.missing_libc); - // Misc linker errors - total += self.bin_file.miscErrors().len; + if (self.bin_file) |lf| { + total += lf.misc_errors.items.len; + } // Compile log errors only count if there are no other errors. if (total == 0) { @@ -2914,7 +2941,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { })); } - for (self.bin_file.miscErrors()) |link_err| { + if (self.bin_file) |lf| for (lf.misc_errors.items) |link_err| { try bundle.addRootErrorMessage(.{ .msg = try bundle.addString(link_err.msg), .notes_len = @intCast(link_err.notes.len), @@ -2925,7 +2952,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { .msg = try bundle.addString(note.msg), })); } - } + }; if (self.module) |module| { if (bundle.root_list.items.len == 0 and module.compile_log_decls.count() != 0) { @@ -3246,12 +3273,12 @@ pub fn performAllTheWork( // TODO put all the modules in a flat array to make them easy to iterate. var seen: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{}; defer seen.deinit(comp.gpa); - try seen.put(comp.gpa, comp.root_mod); + try seen.put(comp.gpa, comp.root_mod, {}); var i: usize = 0; while (i < seen.count()) : (i += 1) { const mod = seen.keys()[i]; for (mod.deps.values()) |dep| - try seen.put(comp.gpa, dep); + try seen.put(comp.gpa, dep, {}); const file = mod.builtin_file orelse continue; @@ -3459,7 +3486,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v const gpa = comp.gpa; const module = comp.module.?; const decl = module.declPtr(decl_index); - comp.bin_file.updateDeclLineNumber(module, decl_index) catch |err| { + const lf = comp.bin_file.?; + lf.updateDeclLineNumber(module, decl_index) catch |err| { try module.failed_decls.ensureUnusedCapacity(gpa, 1); module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( gpa, @@ -3782,7 +3810,7 @@ pub fn obtainCObjectCacheManifest( // that apply both to @cImport and compiling C objects. No linking stuff here! // Also nothing that applies only to compiling .zig code. man.hash.add(owner_mod.sanitize_c); - man.hash.addListOfBytes(owner_mod.clang_argv); + man.hash.addListOfBytes(owner_mod.cc_argv); man.hash.add(comp.config.link_libcpp); // When libc_installation is null it means that Zig generated this dir list @@ -6099,7 +6127,8 @@ fn buildOutputFromZig( const tracy_trace = trace(@src()); defer tracy_trace.end(); - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); + const gpa = comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); @@ -6110,6 +6139,7 @@ fn buildOutputFromZig( const config = try Config.resolve(.{ .output_mode = output_mode, + .link_mode = .Static, .resolved_target = comp.root_mod.resolved_target, .is_test = false, .have_zcu = true, @@ -6120,7 +6150,8 @@ fn buildOutputFromZig( .any_unwind_tables = unwind_tables, }); - const root_mod = Package.Module.create(.{ + const root_mod = try Package.Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, .paths = .{ .root = .{ .root_dir = comp.zig_lib_directory }, .root_src_path = src_basename, @@ -6139,6 +6170,8 @@ fn buildOutputFromZig( }, .global = config, .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, }); const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; const target = comp.getTarget(); @@ -6148,23 +6181,21 @@ fn buildOutputFromZig( .output_mode = output_mode, }); - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = bin_basename, - }; - const sub_compilation = try Compilation.create(comp.gpa, .{ + const sub_compilation = try Compilation.create(gpa, .{ .global_cache_directory = comp.global_cache_directory, .local_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, .self_exe_path = comp.self_exe_path, - .resolved = config, + .config = config, .root_mod = root_mod, .cache_mode = .whole, .root_name = root_name, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .link_mode = .Static, + .emit_bin = .{ + .directory = null, // Put it in the cache directory. + .basename = bin_basename, + }, .function_sections = true, .data_sections = true, .no_builtin = true, @@ -6186,8 +6217,8 @@ fn buildOutputFromZig( try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); assert(out.* == null); - out.* = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(comp.gpa, &[_][]const u8{ + out.* = .{ + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(gpa, &.{ sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), @@ -6206,12 +6237,15 @@ pub fn build_crt_file( defer tracy_trace.end(); const gpa = comp.gpa; - const basename = try std.zig.binNameAlloc(gpa, .{ + var arena_allocator = std.heap.ArenaAllocator.init(gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + + const basename = try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = comp.root_mod.resolved_target.result, .output_mode = output_mode, }); - errdefer gpa.free(basename); const config = try Config.resolve(.{ .output_mode = output_mode, @@ -6227,7 +6261,8 @@ pub fn build_crt_file( .Obj, .Exe => false, }, }); - const root_mod = Package.Module.create(.{ + const root_mod = try Package.Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, .paths = .{ .root = .{ .root_dir = comp.zig_lib_directory }, .root_src_path = "", @@ -6249,6 +6284,8 @@ pub fn build_crt_file( }, .global = config, .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, }); const sub_compilation = try Compilation.create(gpa, .{ @@ -6257,7 +6294,7 @@ pub fn build_crt_file( .zig_lib_directory = comp.zig_lib_directory, .self_exe_path = comp.self_exe_path, .cache_mode = .whole, - .resolved = config, + .config = config, .root_mod = root_mod, .root_name = root_name, .thread_pool = comp.thread_pool, @@ -6287,7 +6324,7 @@ pub fn build_crt_file( try comp.crt_files.ensureUnusedCapacity(gpa, 1); comp.crt_files.putAssumeCapacityNoClobber(basename, .{ - .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(gpa, &[_][]const u8{ + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(gpa, &.{ sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), diff --git a/src/Module.zig b/src/Module.zig index 121f639f6b..0645b6f04f 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -619,7 +619,7 @@ pub const Decl = struct { // Sanitize the name for nvptx which is more restrictive. // TODO This should be handled by the backend, not the frontend. Have a // look at how the C backend does it for inspiration. - const cpu_arch = mod.root_mod.resolved_target.cpu.arch; + const cpu_arch = mod.root_mod.resolved_target.result.cpu.arch; if (cpu_arch.isNvptx()) { for (ip.string_bytes.items[start..]) |*byte| switch (byte.*) { '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', @@ -3313,7 +3313,8 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaEr if (no_bin_file and !dump_llvm_ir) return; - comp.bin_file.updateFunc(mod, func_index, air, liveness) catch |err| switch (err) { + const lf = comp.bin_file.?; + lf.updateFunc(mod, func_index, air, liveness) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => { decl.analysis = .codegen_failure; @@ -3488,25 +3489,29 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { new_decl.owns_tv = true; new_decl.analysis = .complete; - if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { - const source = file.getSource(gpa) catch |err| { - try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); - return error.AnalysisFail; - }; + const comp = mod.comp; + switch (comp.cache_use) { + .whole => |whole| if (whole.cache_manifest) |man| { + const source = file.getSource(gpa) catch |err| { + try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); + return error.AnalysisFail; + }; - const resolved_path = std.fs.path.resolve(gpa, &.{ - file.mod.root.root_dir.path orelse ".", - file.mod.root.sub_path, - file.sub_file_path, - }) catch |err| { - try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); - return error.AnalysisFail; - }; - errdefer gpa.free(resolved_path); + const resolved_path = std.fs.path.resolve(gpa, &.{ + file.mod.root.root_dir.path orelse ".", + file.mod.root.sub_path, + file.sub_file_path, + }) catch |err| { + try reportRetryableFileError(mod, file, "unable to resolve path: {s}", .{@errorName(err)}); + return error.AnalysisFail; + }; + errdefer gpa.free(resolved_path); - mod.comp.whole_cache_manifest_mutex.lock(); - defer mod.comp.whole_cache_manifest_mutex.unlock(); - try whole_cache_manifest.addFilePostContents(resolved_path, source.bytes, source.stat); + whole.cache_manifest_mutex.lock(); + defer whole.cache_manifest_mutex.unlock(); + try man.addFilePostContents(resolved_path, source.bytes, source.stat); + }, + .incremental => {}, } } @@ -4045,12 +4050,16 @@ fn newEmbedFile( const actual_read = try file.readAll(ptr); if (actual_read != size) return error.UnexpectedEndOfFile; - if (mod.comp.whole_cache_manifest) |whole_cache_manifest| { - const copied_resolved_path = try gpa.dupe(u8, resolved_path); - errdefer gpa.free(copied_resolved_path); - mod.comp.whole_cache_manifest_mutex.lock(); - defer mod.comp.whole_cache_manifest_mutex.unlock(); - try whole_cache_manifest.addFilePostContents(copied_resolved_path, ptr, stat); + const comp = mod.comp; + switch (comp.cache_use) { + .whole => |whole| if (whole.cache_manifest) |man| { + const copied_resolved_path = try gpa.dupe(u8, resolved_path); + errdefer gpa.free(copied_resolved_path); + whole.cache_manifest_mutex.lock(); + defer whole.cache_manifest_mutex.unlock(); + try man.addFilePostContents(copied_resolved_path, ptr, stat); + }, + .incremental => {}, } const array_ty = try ip.get(gpa, .{ .array_type = .{ @@ -4393,7 +4402,9 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void } }, } - try mod.comp.bin_file.deleteDeclExport(decl_index, exp.opts.name); + if (mod.comp.bin_file) |lf| { + try lf.deleteDeclExport(decl_index, exp.opts.name); + } if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { failed_kv.value.destroy(mod.gpa); } @@ -5247,7 +5258,8 @@ fn processExportsInner( gop.value_ptr.* = new_export; } } - mod.comp.bin_file.updateExports(mod, exported, exports) catch |err| switch (err) { + const lf = mod.comp.bin_file orelse return; + lf.updateExports(mod, exported, exports) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => { const new_export = exports[0]; @@ -5403,36 +5415,39 @@ pub fn populateTestFunctions( pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { const comp = mod.comp; - const no_bin_file = (comp.bin_file == null and - comp.emit_asm == null and - comp.emit_llvm_ir == null and - comp.emit_llvm_bc == null); - - const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); - - if (no_bin_file and !dump_llvm_ir) return; - - const decl = mod.declPtr(decl_index); + if (comp.bin_file) |lf| { + const decl = mod.declPtr(decl_index); + lf.updateDecl(mod, decl_index) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => { + decl.analysis = .codegen_failure; + return; + }, + else => { + const gpa = mod.gpa; + try mod.failed_decls.ensureUnusedCapacity(gpa, 1); + mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( + gpa, + decl.srcLoc(mod), + "unable to codegen: {s}", + .{@errorName(err)}, + )); + decl.analysis = .codegen_failure_retryable; + return; + }, + }; + } else { + const dump_llvm_ir = builtin.mode == .Debug and + (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); - comp.bin_file.updateDecl(mod, decl_index) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.AnalysisFail => { - decl.analysis = .codegen_failure; - return; - }, - else => { - const gpa = mod.gpa; - try mod.failed_decls.ensureUnusedCapacity(gpa, 1); - mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( - gpa, - decl.srcLoc(mod), - "unable to codegen: {s}", - .{@errorName(err)}, - )); - decl.analysis = .codegen_failure_retryable; - return; - }, - }; + if (comp.emit_asm != null or + comp.emit_llvm_ir != null or + comp.emit_llvm_bc != null or + dump_llvm_ir) + { + @panic("TODO handle emit_asm, emit_llvm_ir, and emit_llvm_bc along with -fno-emit-bin"); + } + } } fn reportRetryableFileError( diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 2fb740474b..341e4bef00 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -344,7 +344,7 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); - const target = &namespace.file_scope.mod.target; + const target = &namespace.file_scope.mod.resolved_target.result; var branch_stack = std.ArrayList(Branch).init(gpa); defer { @@ -6343,14 +6343,14 @@ fn wantSafety(self: *Self) bool { fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + self.err_msg = try ErrorMsg.create(self.gpa, self.src_loc, format, args); return error.CodegenFail; } fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + self.err_msg = try ErrorMsg.create(self.gpa, self.src_loc, format, args); return error.CodegenFail; } diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index 9ba722f393..3f629fd46f 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -218,14 +218,16 @@ pub fn emitMir( } pub fn deinit(emit: *Emit) void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; var iter = emit.branch_forward_origins.valueIterator(); while (iter.next()) |origin_list| { - origin_list.deinit(emit.bin_file.allocator); + origin_list.deinit(gpa); } - emit.branch_types.deinit(emit.bin_file.allocator); - emit.branch_forward_origins.deinit(emit.bin_file.allocator); - emit.code_offset_mapping.deinit(emit.bin_file.allocator); + emit.branch_types.deinit(gpa); + emit.branch_forward_origins.deinit(gpa); + emit.code_offset_mapping.deinit(gpa); emit.* = undefined; } @@ -314,8 +316,9 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { } fn lowerBranches(emit: *Emit) !void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; const mir_tags = emit.mir.instructions.items(.tag); - const allocator = emit.bin_file.allocator; // First pass: Note down all branches and their target // instructions, i.e. populate branch_types, @@ -329,7 +332,7 @@ fn lowerBranches(emit: *Emit) !void { const target_inst = emit.branchTarget(inst); // Remember this branch instruction - try emit.branch_types.put(allocator, inst, BranchType.default(tag)); + try emit.branch_types.put(gpa, inst, BranchType.default(tag)); // Forward branches require some extra stuff: We only // know their offset once we arrive at the target @@ -339,14 +342,14 @@ fn lowerBranches(emit: *Emit) !void { // etc. if (target_inst > inst) { // Remember the branch instruction index - try emit.code_offset_mapping.put(allocator, inst, 0); + try emit.code_offset_mapping.put(gpa, inst, 0); if (emit.branch_forward_origins.getPtr(target_inst)) |origin_list| { - try origin_list.append(allocator, inst); + try origin_list.append(gpa, inst); } else { var origin_list: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}; - try origin_list.append(allocator, inst); - try emit.branch_forward_origins.put(allocator, target_inst, origin_list); + try origin_list.append(gpa, inst); + try emit.branch_forward_origins.put(gpa, target_inst, origin_list); } } @@ -356,7 +359,7 @@ fn lowerBranches(emit: *Emit) !void { // putNoClobber may not be used as the put operation // may clobber the entry when multiple branches branch // to the same target instruction - try emit.code_offset_mapping.put(allocator, target_inst, 0); + try emit.code_offset_mapping.put(gpa, target_inst, 0); } } @@ -429,7 +432,9 @@ fn writeInstruction(emit: *Emit, instruction: Instruction) !void { fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(emit.err_msg == null); - emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + emit.err_msg = try ErrorMsg.create(gpa, emit.src_loc, format, args); return error.EmitFail; } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 0df653ff35..c9d6a3aef4 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -351,7 +351,7 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); - const target = &namespace.file_scope.mod.target; + const target = &namespace.file_scope.mod.resolved_target.result; var branch_stack = std.ArrayList(Branch).init(gpa); defer { @@ -6292,14 +6292,16 @@ fn wantSafety(self: *Self) bool { fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + const gpa = self.gpa; + self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args); return error.CodegenFail; } fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + const gpa = self.gpa; + self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args); return error.CodegenFail; } diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index 45c3392918..2ab3b60ee6 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -152,14 +152,17 @@ pub fn emitMir( } pub fn deinit(emit: *Emit) void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + var iter = emit.branch_forward_origins.valueIterator(); while (iter.next()) |origin_list| { - origin_list.deinit(emit.bin_file.allocator); + origin_list.deinit(gpa); } - emit.branch_types.deinit(emit.bin_file.allocator); - emit.branch_forward_origins.deinit(emit.bin_file.allocator); - emit.code_offset_mapping.deinit(emit.bin_file.allocator); + emit.branch_types.deinit(gpa); + emit.branch_forward_origins.deinit(gpa); + emit.code_offset_mapping.deinit(gpa); emit.* = undefined; } @@ -231,8 +234,9 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { } fn lowerBranches(emit: *Emit) !void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; const mir_tags = emit.mir.instructions.items(.tag); - const allocator = emit.bin_file.allocator; // First pass: Note down all branches and their target // instructions, i.e. populate branch_types, @@ -246,7 +250,7 @@ fn lowerBranches(emit: *Emit) !void { const target_inst = emit.branchTarget(inst); // Remember this branch instruction - try emit.branch_types.put(allocator, inst, BranchType.default(tag)); + try emit.branch_types.put(gpa, inst, BranchType.default(tag)); // Forward branches require some extra stuff: We only // know their offset once we arrive at the target @@ -256,14 +260,14 @@ fn lowerBranches(emit: *Emit) !void { // etc. if (target_inst > inst) { // Remember the branch instruction index - try emit.code_offset_mapping.put(allocator, inst, 0); + try emit.code_offset_mapping.put(gpa, inst, 0); if (emit.branch_forward_origins.getPtr(target_inst)) |origin_list| { - try origin_list.append(allocator, inst); + try origin_list.append(gpa, inst); } else { var origin_list: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}; - try origin_list.append(allocator, inst); - try emit.branch_forward_origins.put(allocator, target_inst, origin_list); + try origin_list.append(gpa, inst); + try emit.branch_forward_origins.put(gpa, target_inst, origin_list); } } @@ -273,7 +277,7 @@ fn lowerBranches(emit: *Emit) !void { // putNoClobber may not be used as the put operation // may clobber the entry when multiple branches branch // to the same target instruction - try emit.code_offset_mapping.put(allocator, target_inst, 0); + try emit.code_offset_mapping.put(gpa, target_inst, 0); } } @@ -346,7 +350,9 @@ fn writeInstruction(emit: *Emit, instruction: Instruction) !void { fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(emit.err_msg == null); - emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + emit.err_msg = try ErrorMsg.create(gpa, emit.src_loc, format, args); return error.EmitFail; } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 30c6e38c8a..80daa8fd3a 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -232,7 +232,7 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); - const target = &namespace.file_scope.mod.target; + const target = &namespace.file_scope.mod.resolved_target.result; var branch_stack = std.ArrayList(Branch).init(gpa); defer { @@ -2719,14 +2719,14 @@ fn wantSafety(self: *Self) bool { fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + self.err_msg = try ErrorMsg.create(self.gpa, self.src_loc, format, args); return error.CodegenFail; } fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + self.err_msg = try ErrorMsg.create(self.gpa, self.src_loc, format, args); return error.CodegenFail; } diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index 9d82cc38cc..f382f6f9eb 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -80,7 +80,9 @@ fn writeInstruction(emit: *Emit, instruction: Instruction) !void { fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(emit.err_msg == null); - emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + emit.err_msg = try ErrorMsg.create(gpa, emit.src_loc, format, args); return error.EmitFail; } diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index bd0208c3c2..e58206ac16 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -275,7 +275,7 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); - const target = &namespace.file_scope.mod.target; + const target = &namespace.file_scope.mod.resolved_target.result; var branch_stack = std.ArrayList(Branch).init(gpa); defer { @@ -3546,7 +3546,8 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + const gpa = self.gpa; + self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args); return error.CodegenFail; } diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig index 4701035bc9..b2f2e6f79d 100644 --- a/src/arch/sparc64/Emit.zig +++ b/src/arch/sparc64/Emit.zig @@ -152,14 +152,16 @@ pub fn emitMir( } pub fn deinit(emit: *Emit) void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; var iter = emit.branch_forward_origins.valueIterator(); while (iter.next()) |origin_list| { - origin_list.deinit(emit.bin_file.allocator); + origin_list.deinit(gpa); } - emit.branch_types.deinit(emit.bin_file.allocator); - emit.branch_forward_origins.deinit(emit.bin_file.allocator); - emit.code_offset_mapping.deinit(emit.bin_file.allocator); + emit.branch_types.deinit(gpa); + emit.branch_forward_origins.deinit(gpa); + emit.code_offset_mapping.deinit(gpa); emit.* = undefined; } @@ -511,7 +513,9 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(emit.err_msg == null); - emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args); + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + emit.err_msg = try ErrorMsg.create(gpa, emit.src_loc, format, args); return error.EmitFail; } @@ -537,8 +541,9 @@ fn isBranch(tag: Mir.Inst.Tag) bool { } fn lowerBranches(emit: *Emit) !void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; const mir_tags = emit.mir.instructions.items(.tag); - const allocator = emit.bin_file.allocator; // First pass: Note down all branches and their target // instructions, i.e. populate branch_types, @@ -552,7 +557,7 @@ fn lowerBranches(emit: *Emit) !void { const target_inst = emit.branchTarget(inst); // Remember this branch instruction - try emit.branch_types.put(allocator, inst, BranchType.default(tag)); + try emit.branch_types.put(gpa, inst, BranchType.default(tag)); // Forward branches require some extra stuff: We only // know their offset once we arrive at the target @@ -562,14 +567,14 @@ fn lowerBranches(emit: *Emit) !void { // etc. if (target_inst > inst) { // Remember the branch instruction index - try emit.code_offset_mapping.put(allocator, inst, 0); + try emit.code_offset_mapping.put(gpa, inst, 0); if (emit.branch_forward_origins.getPtr(target_inst)) |origin_list| { - try origin_list.append(allocator, inst); + try origin_list.append(gpa, inst); } else { var origin_list: std.ArrayListUnmanaged(Mir.Inst.Index) = .{}; - try origin_list.append(allocator, inst); - try emit.branch_forward_origins.put(allocator, target_inst, origin_list); + try origin_list.append(gpa, inst); + try emit.branch_forward_origins.put(gpa, target_inst, origin_list); } } @@ -579,7 +584,7 @@ fn lowerBranches(emit: *Emit) !void { // putNoClobber may not be used as the put operation // may clobber the entry when multiple branches branch // to the same target instruction - try emit.code_offset_mapping.put(allocator, target_inst, 0); + try emit.code_offset_mapping.put(gpa, target_inst, 0); } } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 2319330333..da33ae521d 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1210,13 +1210,15 @@ pub fn generate( debug_output: codegen.DebugInfoOutput, ) codegen.CodeGenError!codegen.Result { _ = src_loc; - const mod = bin_file.comp.module.?; + const comp = bin_file.comp; + const gpa = comp.gpa; + const mod = comp.module.?; const func = mod.funcInfo(func_index); const decl = mod.declPtr(func.owner_decl); const namespace = mod.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; var code_gen: CodeGen = .{ - .gpa = bin_file.allocator, + .gpa = gpa, .air = air, .liveness = liveness, .code = code, @@ -7731,7 +7733,7 @@ fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { // Only when the atomic feature is enabled, and we're not building // for a single-threaded build, can we emit the `fence` instruction. // In all other cases, we emit no instructions for a fence. - const func_namespace = zcu.namespacePtr(zcu.declPtr(func.decl).namespace); + const func_namespace = zcu.namespacePtr(func.decl.src_namespace); const single_threaded = func_namespace.file_scope.mod.single_threaded; if (func.useAtomicFeature() and !single_threaded) { try func.addAtomicTag(.atomic_fence); diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 990eb359e8..7e67a98285 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -254,8 +254,10 @@ fn offset(self: Emit) u32 { fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { @setCold(true); std.debug.assert(emit.error_msg == null); - const mod = emit.bin_file.base.comp.module.?; - emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(mod), format, args); + const comp = emit.bin_file.base.comp; + const zcu = comp.module.?; + const gpa = comp.gpa; + emit.error_msg = try Module.ErrorMsg.create(gpa, zcu.declPtr(emit.decl_index).srcLoc(zcu), format, args); return error.EmitFail; } @@ -299,6 +301,8 @@ fn emitLabel(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void { } fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void { + const comp = emit.bin_file.base.comp; + const gpa = comp.gpa; const label = emit.mir.instructions.items(.data)[inst].label; try emit.code.append(@intFromEnum(tag)); var buf: [5]u8 = undefined; @@ -308,7 +312,7 @@ fn emitGlobal(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void { const atom_index = emit.bin_file.decls.get(emit.decl_index).?; const atom = emit.bin_file.getAtomPtr(atom_index); - try atom.relocs.append(emit.bin_file.base.allocator, .{ + try atom.relocs.append(gpa, .{ .index = label, .offset = global_offset, .relocation_type = .R_WASM_GLOBAL_INDEX_LEB, @@ -356,6 +360,8 @@ fn encodeMemArg(mem_arg: Mir.MemArg, writer: anytype) !void { } fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void { + const comp = emit.bin_file.base.comp; + const gpa = comp.gpa; const label = emit.mir.instructions.items(.data)[inst].label; try emit.code.append(std.wasm.opcode(.call)); const call_offset = emit.offset(); @@ -366,7 +372,7 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void { if (label != 0) { const atom_index = emit.bin_file.decls.get(emit.decl_index).?; const atom = emit.bin_file.getAtomPtr(atom_index); - try atom.relocs.append(emit.bin_file.base.allocator, .{ + try atom.relocs.append(gpa, .{ .offset = call_offset, .index = label, .relocation_type = .R_WASM_FUNCTION_INDEX_LEB, @@ -384,6 +390,8 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void { } fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void { + const comp = emit.bin_file.base.comp; + const gpa = comp.gpa; const symbol_index = emit.mir.instructions.items(.data)[inst].label; try emit.code.append(std.wasm.opcode(.i32_const)); const index_offset = emit.offset(); @@ -394,7 +402,7 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void { if (symbol_index != 0) { const atom_index = emit.bin_file.decls.get(emit.decl_index).?; const atom = emit.bin_file.getAtomPtr(atom_index); - try atom.relocs.append(emit.bin_file.base.allocator, .{ + try atom.relocs.append(gpa, .{ .offset = index_offset, .index = symbol_index, .relocation_type = .R_WASM_TABLE_INDEX_SLEB, @@ -406,7 +414,9 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void { const extra_index = emit.mir.instructions.items(.data)[inst].payload; const mem = emit.mir.extraData(Mir.Memory, extra_index).data; const mem_offset = emit.offset() + 1; - const target = emit.bin_file.comp.root_mod.resolved_target.result; + const comp = emit.bin_file.base.comp; + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; const is_wasm32 = target.cpu.arch == .wasm32; if (is_wasm32) { try emit.code.append(std.wasm.opcode(.i32_const)); @@ -423,7 +433,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void { if (mem.pointer != 0) { const atom_index = emit.bin_file.decls.get(emit.decl_index).?; const atom = emit.bin_file.getAtomPtr(atom_index); - try atom.relocs.append(emit.bin_file.base.allocator, .{ + try atom.relocs.append(gpa, .{ .offset = mem_offset, .index = mem.pointer, .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b3c5df02d9..5056bc32fd 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -795,15 +795,16 @@ pub fn generate( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, ) CodeGenError!Result { - const mod = bin_file.comp.module.?; + const comp = bin_file.comp; + const gpa = comp.gpa; + const mod = comp.module.?; const func = mod.funcInfo(func_index); const fn_owner_decl = mod.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; const namespace = mod.namespacePtr(fn_owner_decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; - const gpa = bin_file.allocator; var function = Self{ .gpa = gpa, .air = air, @@ -860,7 +861,7 @@ pub fn generate( error.CodegenFail => return Result{ .fail = function.err_msg.? }, error.OutOfRegisters => return Result{ .fail = try ErrorMsg.create( - bin_file.allocator, + gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}, @@ -904,22 +905,22 @@ pub fn generate( function.gen() catch |err| switch (err) { error.CodegenFail => return Result{ .fail = function.err_msg.? }, error.OutOfRegisters => return Result{ - .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, }; var mir = Mir{ .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator), + .extra = try function.mir_extra.toOwnedSlice(gpa), .frame_locs = function.frame_locs.toOwnedSlice(), }; - defer mir.deinit(bin_file.allocator); + defer mir.deinit(gpa); var emit = Emit{ .lower = .{ .bin_file = bin_file, - .allocator = bin_file.allocator, + .allocator = gpa, .mir = mir, .cc = cc, .src_loc = src_loc, @@ -940,7 +941,7 @@ pub fn generate( }; return Result{ .fail = try ErrorMsg.create( - bin_file.allocator, + gpa, src_loc, "{s} This is a bug in the Zig compiler.", .{msg}, @@ -964,12 +965,13 @@ pub fn generateLazy( code: *std.ArrayList(u8), debug_output: DebugInfoOutput, ) CodeGenError!Result { - const gpa = bin_file.allocator; - const zcu = bin_file.comp.module.?; + const comp = bin_file.comp; + const gpa = comp.gpa; + const zcu = comp.module.?; const decl_index = lazy_sym.ty.getOwnerDecl(zcu); const decl = zcu.declPtr(decl_index); const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; var function = Self{ .gpa = gpa, .air = undefined, @@ -996,22 +998,22 @@ pub fn generateLazy( function.genLazy(lazy_sym) catch |err| switch (err) { error.CodegenFail => return Result{ .fail = function.err_msg.? }, error.OutOfRegisters => return Result{ - .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), + .fail = try ErrorMsg.create(gpa, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), }, else => |e| return e, }; var mir = Mir{ .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator), + .extra = try function.mir_extra.toOwnedSlice(gpa), .frame_locs = function.frame_locs.toOwnedSlice(), }; - defer mir.deinit(bin_file.allocator); + defer mir.deinit(gpa); var emit = Emit{ .lower = .{ .bin_file = bin_file, - .allocator = bin_file.allocator, + .allocator = gpa, .mir = mir, .cc = abi.resolveCallingConvention(.Unspecified, function.target.*), .src_loc = src_loc, @@ -1032,7 +1034,7 @@ pub fn generateLazy( }; return Result{ .fail = try ErrorMsg.create( - bin_file.allocator, + gpa, src_loc, "{s} This is a bug in the Zig compiler.", .{msg}, @@ -16416,14 +16418,16 @@ fn resolveCallingConventionValues( fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + const gpa = self.gpa; + self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args); return error.CodegenFail; } fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError { @setCold(true); assert(self.err_msg == null); - self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args); + const gpa = self.gpa; + self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args); return error.CodegenFail; } diff --git a/src/codegen.zig b/src/codegen.zig index e579cb50f1..65af8236de 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -57,7 +57,7 @@ pub fn generateFunction( const func = zcu.funcInfo(func_index); const decl = zcu.declPtr(func.owner_decl); const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; switch (target.cpu.arch) { .arm, .armeb, @@ -87,7 +87,7 @@ pub fn generateLazyFunction( const decl_index = lazy_sym.ty.getOwnerDecl(zcu); const decl = zcu.declPtr(decl_index); const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; switch (target.cpu.arch) { .x86_64 => return @import("arch/x86_64/CodeGen.zig").generateLazy(lf, src_loc, lazy_sym, code, debug_output), else => unreachable, @@ -117,12 +117,14 @@ pub fn generateLazySymbol( const tracy = trace(@src()); defer tracy.end(); - const zcu = bin_file.comp.module.?; + const comp = bin_file.comp; + const zcu = comp.module.?; const decl_index = lazy_sym.ty.getOwnerDecl(zcu); const decl = zcu.declPtr(decl_index); const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; const endian = target.cpu.arch.endian(); + const gpa = comp.gpa; log.debug("generateLazySymbol: kind = {s}, ty = {}", .{ @tagName(lazy_sym.kind), @@ -160,7 +162,7 @@ pub fn generateLazySymbol( } return Result.ok; } else return .{ .fail = try ErrorMsg.create( - bin_file.allocator, + gpa, src_loc, "TODO implement generateLazySymbol for {s} {}", .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(zcu) }, @@ -827,7 +829,7 @@ fn lowerDeclRef( const zcu = lf.comp.module.?; const decl = zcu.declPtr(decl_index); const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; const ptr_width = target.ptrBitWidth(); const is_fn_body = decl.ty.zigTypeTag(zcu) == .Fn; @@ -921,7 +923,7 @@ fn genDeclRef( const ptr_decl = zcu.declPtr(ptr_decl_index); const namespace = zcu.namespacePtr(ptr_decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; const ptr_bits = target.ptrBitWidth(); const ptr_bytes: u64 = @divExact(ptr_bits, 8); @@ -944,6 +946,9 @@ fn genDeclRef( return GenResult.mcv(.{ .immediate = imm }); } + const comp = lf.comp; + const gpa = comp.gpa; + // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? if (tv.ty.castPtrToFn(zcu)) |fn_ty| { if (zcu.typeToFunc(fn_ty).?.is_generic) { @@ -958,8 +963,8 @@ fn genDeclRef( try zcu.markDeclAlive(decl); - const decl_namespace = zcu.namespacePtr(decl.namespace_index); - const single_threaded = decl_namespace.file_scope.zcu.single_threaded; + const decl_namespace = zcu.namespacePtr(decl.src_namespace); + const single_threaded = decl_namespace.file_scope.mod.single_threaded; const is_threadlocal = tv.val.isPtrToThreadLocal(zcu) and !single_threaded; const is_extern = decl.isExtern(zcu); @@ -985,8 +990,8 @@ fn genDeclRef( if (is_extern) { // TODO make this part of getGlobalSymbol const name = zcu.intern_pool.stringToSlice(decl.name); - const sym_name = try std.fmt.allocPrint(lf.allocator, "_{s}", .{name}); - defer lf.allocator.free(sym_name); + const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); + defer gpa.free(sym_name); const global_index = try macho_file.addUndefined(sym_name, .{ .add_got = true }); return GenResult.mcv(.{ .load_got = link.File.MachO.global_symbol_bit | global_index }); } @@ -1005,7 +1010,7 @@ fn genDeclRef( else null; const global_index = try coff_file.getGlobalSymbol(name, lib_name); - try coff_file.need_got_table.put(lf.allocator, global_index, {}); // needs GOT + try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index }); } const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); @@ -1016,7 +1021,7 @@ fn genDeclRef( const atom = p9.getAtom(atom_index); return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(p9) }); } else { - return GenResult.fail(lf.allocator, src_loc, "TODO genDeclRef for target {}", .{target}); + return GenResult.fail(gpa, src_loc, "TODO genDeclRef for target {}", .{target}); } } @@ -1073,7 +1078,7 @@ pub fn genTypedValue( const owner_decl = zcu.declPtr(owner_decl_index); const namespace = zcu.namespacePtr(owner_decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; const ptr_bits = target.ptrBitWidth(); if (!typed_value.ty.isSlice(zcu)) switch (zcu.intern_pool.indexToKey(typed_value.val.toIntern())) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 709b2bf6a9..6545f84f9d 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1785,7 +1785,7 @@ pub const Object = struct { if (wantDllExports(mod)) global_index.setDllStorageClass(.default, &self.builder); global_index.setUnnamedAddr(.unnamed_addr, &self.builder); if (decl.val.getVariable(mod)) |decl_var| { - const decl_namespace = mod.namespacePtr(decl.namespace_index); + const decl_namespace = mod.namespacePtr(decl.src_namespace); const single_threaded = decl_namespace.file_scope.mod.single_threaded; global_index.ptrConst(&self.builder).kind.variable.setThreadLocal( if (decl_var.is_threadlocal and !single_threaded) @@ -3173,7 +3173,7 @@ pub const Object = struct { variable_index.setLinkage(.external, &o.builder); variable_index.setUnnamedAddr(.default, &o.builder); if (decl.val.getVariable(mod)) |decl_var| { - const decl_namespace = mod.namespacePtr(decl.namespace_index); + const decl_namespace = mod.namespacePtr(decl.src_namespace); const single_threaded = decl_namespace.file_scope.mod.single_threaded; variable_index.setThreadLocal( if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default, diff --git a/src/libunwind.zig b/src/libunwind.zig index bc1c0d0343..baf24d8508 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -123,7 +123,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, - .resolved = config, + .config = config, .root_mod = root_mod, .cache_mode = .whole, .root_name = root_name, diff --git a/src/link.zig b/src/link.zig index 91def2a134..ce12e922d7 100644 --- a/src/link.zig +++ b/src/link.zig @@ -69,10 +69,12 @@ pub const File = struct { allow_shlib_undefined: bool, stack_size: u64, + error_flags: ErrorFlags = .{}, + misc_errors: std.ArrayListUnmanaged(ErrorMsg) = .{}, + /// Prevents other processes from clobbering files in the output directory /// of this linking operation. lock: ?Cache.Lock = null, - child_pid: ?std.ChildProcess.Id = null, pub const OpenOptions = struct { @@ -210,6 +212,8 @@ pub const File = struct { } pub fn makeWritable(base: *File) !void { + const comp = base.comp; + const gpa = comp.gpa; switch (base.tag) { .coff, .elf, .macho, .plan9, .wasm => { if (build_options.only_c) unreachable; @@ -225,9 +229,10 @@ pub const File = struct { // it will return ETXTBSY. So instead, we copy the file, atomically rename it // over top of the exe path, and then proceed normally. This changes the inode, // avoiding the error. - const tmp_sub_path = try std.fmt.allocPrint(base.allocator, "{s}-{x}", .{ + const tmp_sub_path = try std.fmt.allocPrint(gpa, "{s}-{x}", .{ emit.sub_path, std.crypto.random.int(u32), }); + defer gpa.free(tmp_sub_path); try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{}); try emit.directory.handle.rename(tmp_sub_path, emit.sub_path); switch (builtin.os.tag) { @@ -242,9 +247,9 @@ pub const File = struct { } } } - const use_lld = build_options.have_llvm and base.comp.config.use_lld; - const output_mode = base.comp.config.output_mode; - const link_mode = base.comp.config.link_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; base.file = try emit.directory.handle.createFile(emit.sub_path, .{ .truncate = false, .read = true, @@ -256,9 +261,10 @@ pub const File = struct { } pub fn makeExecutable(base: *File) !void { - const output_mode = base.comp.config.output_mode; - const link_mode = base.comp.config.link_mode; - const use_lld = build_options.have_llvm and base.comp.config.use_lld; + const comp = base.comp; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; switch (output_mode) { .Obj => return, @@ -464,8 +470,13 @@ pub const File = struct { } pub fn destroy(base: *File) void { + const gpa = base.comp.gpa; base.releaseLock(); if (base.file) |f| f.close(); + { + for (base.misc_errors.items) |*item| item.deinit(gpa); + base.misc_errors.deinit(gpa); + } switch (base.tag) { .coff => { if (build_options.only_c) unreachable; @@ -602,9 +613,9 @@ pub const File = struct { return; } - const use_lld = build_options.have_llvm and base.comp.config.use_lld; - const output_mode = base.comp.config.output_mode; - const link_mode = base.comp.config.link_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; if (use_lld and output_mode == .Lib and link_mode == .Static) { return base.linkAsArchive(comp, prog_node); } @@ -657,25 +668,6 @@ pub const File = struct { } } - pub fn errorFlags(base: *File) ErrorFlags { - switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).error_flags, - .elf => return @fieldParentPtr(Elf, "base", base).error_flags, - .macho => return @fieldParentPtr(MachO, "base", base).error_flags, - .plan9 => return @fieldParentPtr(Plan9, "base", base).error_flags, - .c => return .{ .no_entry_point_found = false }, - .wasm, .spirv, .nvptx => return ErrorFlags{}, - } - } - - pub fn miscErrors(base: *File) []const ErrorMsg { - switch (base.tag) { - .elf => return @fieldParentPtr(Elf, "base", base).misc_errors.items, - .macho => return @fieldParentPtr(MachO, "base", base).misc_errors.items, - else => return &.{}, - } - } - pub const UpdateExportsError = error{ OutOfMemory, AnalysisFail, @@ -781,14 +773,15 @@ pub const File = struct { const tracy = trace(@src()); defer tracy.end(); - var arena_allocator = std.heap.ArenaAllocator.init(base.allocator); + const gpa = comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); const directory = base.emit.directory; // Just an alias to make it shorter to type. const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); const full_out_path_z = try arena.dupeZ(u8, full_out_path); - const opt_zcu = base.comp.module; + const opt_zcu = comp.module; // If there is no Zig code to compile, then we should skip flushing the output file // because it will not be part of the linker line anyway. @@ -801,7 +794,7 @@ pub const File = struct { log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"}); - const compiler_rt_path: ?[]const u8 = if (base.comp.include_compiler_rt) + const compiler_rt_path: ?[]const u8 = if (comp.include_compiler_rt) comp.compiler_rt_obj.?.full_object_path else null; @@ -815,7 +808,7 @@ pub const File = struct { var man: Cache.Manifest = undefined; defer if (!base.disable_lld_caching) man.deinit(); - const objects = base.comp.objects; + const objects = comp.objects; var digest: [Cache.hex_digest_len]u8 = undefined; @@ -869,7 +862,7 @@ pub const File = struct { const win32_resource_table_len = if (build_options.only_core_functionality) 0 else comp.win32_resource_table.count(); const num_object_files = objects.len + comp.c_object_table.count() + win32_resource_table_len + 2; - var object_files = try std.ArrayList([*:0]const u8).initCapacity(base.allocator, num_object_files); + var object_files = try std.ArrayList([*:0]const u8).initCapacity(gpa, num_object_files); defer object_files.deinit(); for (objects) |obj| { diff --git a/src/link/C.zig b/src/link/C.zig index ce44cc4c06..3592052cf8 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -84,7 +84,8 @@ pub fn getString(this: C, s: String) []const u8 { } pub fn addString(this: *C, s: []const u8) Allocator.Error!String { - const gpa = this.base.allocator; + const comp = this.base.comp; + const gpa = comp.gpa; try this.string_bytes.appendSlice(gpa, s); return .{ .start = @intCast(this.string_bytes.items.len - s.len), @@ -97,6 +98,15 @@ pub fn open( comp: *Compilation, emit: Compilation.Emit, options: link.File.OpenOptions, +) !*C { + return createEmpty(arena, comp, emit, options); +} + +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, ) !*C { const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .c); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index eba24f0d17..762591442b 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -8,7 +8,6 @@ llvm_object: ?*LlvmObject = null, base: link.File, image_base: u64, -error_flags: link.File.ErrorFlags = .{}, dll_export_fns: bool, subsystem: ?std.Target.SubSystem, tsaware: bool, @@ -1825,10 +1824,10 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (self.entry_addr == null and self.base.comp.config.output_mode == .Exe) { log.debug("flushing. no_entry_point_found = true\n", .{}); - self.error_flags.no_entry_point_found = true; + self.base.error_flags.no_entry_point_found = true; } else { log.debug("flushing. no_entry_point_found = false\n", .{}); - self.error_flags.no_entry_point_found = false; + self.base.error_flags.no_entry_point_found = false; try self.writeHeader(); } diff --git a/src/link/Coff/Atom.zig b/src/link/Coff/Atom.zig index 9e55575755..4aa97fa6ac 100644 --- a/src/link/Coff/Atom.zig +++ b/src/link/Coff/Atom.zig @@ -94,7 +94,8 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool { } pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !void { - const gpa = coff_file.base.allocator; + const comp = coff_file.base.comp; + const gpa = comp.gpa; log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index }); const gop = try coff_file.relocs.getOrPut(gpa, atom_index); if (!gop.found_existing) { @@ -104,7 +105,8 @@ pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !vo } pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void { - const gpa = coff_file.base.allocator; + const comp = coff_file.base.comp; + const gpa = comp.gpa; log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, coff_file.getAtom(atom_index).getSymbolIndex().?, @@ -117,7 +119,8 @@ pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void } pub fn freeRelocations(coff_file: *Coff, atom_index: Index) void { - const gpa = coff_file.base.allocator; + const comp = coff_file.base.comp; + const gpa = comp.gpa; var removed_relocs = coff_file.relocs.fetchOrderedRemove(atom_index); if (removed_relocs) |*relocs| relocs.value.deinit(gpa); var removed_base_relocs = coff_file.base_relocs.fetchOrderedRemove(atom_index); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 525ca90bc3..faaf5100a4 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1205,7 +1205,7 @@ pub fn commitDeclState( const decl = zcu.declPtr(decl_index); const ip = &zcu.intern_pool; const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.target; + const target = namespace.file_scope.mod.resolved_target.result; const target_endian = target.cpu.arch.endian(); var dbg_line_buffer = &decl_state.dbg_line; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 5f96e195ab..3e237fe494 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -196,9 +196,6 @@ resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, has_text_reloc: bool = false, num_ifunc_dynrelocs: usize = 0, -error_flags: link.File.ErrorFlags = link.File.ErrorFlags{}, -misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, - /// List of atoms that are owned directly by the linker. atoms: std.ArrayListUnmanaged(Atom) = .{}, @@ -477,7 +474,6 @@ pub fn deinit(self: *Elf) void { } self.last_atom_and_free_list_table.deinit(gpa); - self.misc_errors.deinit(gpa); self.comdat_groups.deinit(gpa); self.comdat_groups_owners.deinit(gpa); self.comdat_groups_table.deinit(gpa); @@ -1168,7 +1164,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } // libc dep - self.error_flags.missing_libc = false; + self.base.error_flags.missing_libc = false; if (self.base.comp.config.link_libc) { if (self.base.comp.libc_installation) |lc| { const flags = target_util.libcFullLinkFlags(target); @@ -1219,7 +1215,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node }); try system_libs.append(.{ .path = path }); } else { - self.error_flags.missing_libc = true; + self.base.error_flags.missing_libc = true; } } @@ -1257,7 +1253,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node }; } - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; // Init all objects for (self.objects.items) |index| { @@ -1267,7 +1263,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try self.file(index).?.shared_object.init(self); } - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; // Dedup shared objects { @@ -1389,14 +1385,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node if (self.entry_index == null and self.base.isExe()) { log.debug("flushing. no_entry_point_found = true", .{}); - self.error_flags.no_entry_point_found = true; + self.base.error_flags.no_entry_point_found = true; } else { log.debug("flushing. no_entry_point_found = false", .{}); - self.error_flags.no_entry_point_found = false; + self.base.error_flags.no_entry_point_found = false; try self.writeElfHeader(); } - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; } pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { @@ -1428,7 +1424,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const }; } - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; // First, we flush relocatable object file generated with our backends. if (self.zigObjectPtr()) |zig_object| { @@ -1540,7 +1536,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const try self.base.file.?.setEndPos(total_size); try self.base.file.?.pwriteAll(buffer.items, 0); - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; } pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { @@ -1571,14 +1567,14 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) }; } - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; // Init all objects for (self.objects.items) |index| { try self.file(index).?.object.init(self); } - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; // Now, we are ready to resolve the symbols across all input files. // We will first resolve the files in the ZigObject, next in the parsed @@ -1612,7 +1608,7 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) try self.writeShdrTable(); try self.writeElfHeader(); - if (self.misc_errors.items.len > 0) return error.FlushFailure; + if (self.base.misc_errors.items.len > 0) return error.FlushFailure; } /// --verbose-link output @@ -2891,7 +2887,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } // libc dep - self.error_flags.missing_libc = false; + self.base.error_flags.missing_libc = false; if (comp.config.link_libc) { if (self.base.comp.libc_installation != null) { const needs_grouping = link_mode == .Static; @@ -2912,7 +2908,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v .Dynamic => "libc.so", })); } else { - self.error_flags.missing_libc = true; + self.base.error_flags.missing_libc = true; } } } @@ -3135,7 +3131,7 @@ fn writePhdrTable(self: *Elf) !void { } fn writeElfHeader(self: *Elf) !void { - if (self.misc_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable + if (self.base.misc_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; @@ -6067,8 +6063,9 @@ const ErrorWithNotes = struct { comptime format: []const u8, args: anytype, ) error{OutOfMemory}!void { - const gpa = elf_file.base.allocator; - const err_msg = &elf_file.misc_errors.items[err.index]; + const comp = elf_file.base.comp; + const gpa = comp.gpa; + const err_msg = &elf_file.base.misc_errors.items[err.index]; err_msg.msg = try std.fmt.allocPrint(gpa, format, args); } @@ -6078,8 +6075,9 @@ const ErrorWithNotes = struct { comptime format: []const u8, args: anytype, ) error{OutOfMemory}!void { - const gpa = elf_file.base.allocator; - const err_msg = &elf_file.misc_errors.items[err.index]; + const comp = elf_file.base.comp; + const gpa = comp.gpa; + const err_msg = &elf_file.base.misc_errors.items[err.index]; assert(err.note_slot < err_msg.notes.len); err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) }; err.note_slot += 1; @@ -6088,14 +6086,14 @@ const ErrorWithNotes = struct { pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); return self.addErrorWithNotesAssumeCapacity(note_count); } fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { const gpa = self.base.comp.gpa; - const index = self.misc_errors.items.len; - const err = self.misc_errors.addOneAssumeCapacity(); + const index = self.base.misc_errors.items.len; + const err = self.base.misc_errors.addOneAssumeCapacity(); err.* = .{ .msg = undefined, .notes = try gpa.alloc(link.File.ErrorMsg, note_count) }; return .{ .index = index }; } @@ -6130,7 +6128,7 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void { const gpa = self.base.comp.gpa; const max_notes = 4; - try self.misc_errors.ensureUnusedCapacity(gpa, undefs.count()); + try self.base.misc_errors.ensureUnusedCapacity(gpa, undefs.count()); var it = undefs.iterator(); while (it.next()) |entry| { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index dc330fa54b..9f57dab283 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -227,7 +227,8 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void { pub fn free(self: *Atom, elf_file: *Elf) void { log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) }); - const gpa = elf_file.base.allocator; + const comp = elf_file.base.comp; + const gpa = comp.gpa; const shndx = self.outputShndx().?; const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?; const free_list = &meta.free_list; @@ -352,7 +353,8 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void { } pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void { - const gpa = elf_file.base.allocator; + const comp = elf_file.base.comp; + const gpa = comp.gpa; const file_ptr = self.file(elf_file).?; assert(file_ptr == .zig_object); const zig_object = file_ptr.zig_object; @@ -747,6 +749,8 @@ fn reportUndefined( rel: elf.Elf64_Rela, undefs: anytype, ) !void { + const comp = elf_file.base.comp; + const gpa = comp.gpa; const rel_esym = switch (self.file(elf_file).?) { .zig_object => |x| x.elfSym(rel.r_sym()).*, .object => |x| x.symtab.items[rel.r_sym()], @@ -761,7 +765,7 @@ fn reportUndefined( { const gop = try undefs.getOrPut(sym_index); if (!gop.found_existing) { - gop.value_ptr.* = std.ArrayList(Atom.Index).init(elf_file.base.allocator); + gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa); } try gop.value_ptr.append(self.atom_index); } @@ -957,6 +961,8 @@ fn resolveDynAbsReloc( elf_file: *Elf, writer: anytype, ) !void { + const comp = elf_file.base.comp; + const gpa = comp.gpa; const P = self.value + rel.r_offset; const A = rel.r_addend; const S = @as(i64, @intCast(target.address(.{}, elf_file))); @@ -967,7 +973,7 @@ fn resolveDynAbsReloc( .shared_object => unreachable, inline else => |x| x.num_dynrelocs, }; - try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, num_dynrelocs); + try elf_file.rela_dyn.ensureUnusedCapacity(gpa, num_dynrelocs); switch (action) { .@"error", diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 25d59f3de3..104c83b357 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -67,9 +67,6 @@ tlv_ptr_table: TableSection(SymbolWithLoc) = .{}, thunk_table: std.AutoHashMapUnmanaged(Atom.Index, thunks.Thunk.Index) = .{}, thunks: std.ArrayListUnmanaged(thunks.Thunk) = .{}, -error_flags: File.ErrorFlags = File.ErrorFlags{}, -misc_errors: std.ArrayListUnmanaged(File.ErrorMsg) = .{}, - segment_table_dirty: bool = false, got_table_count_dirty: bool = false, got_table_contents_dirty: bool = false, @@ -337,8 +334,8 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) li if (build_options.have_llvm) { return self.base.linkAsArchive(comp, prog_node); } else { - try self.misc_errors.ensureUnusedCapacity(gpa, 1); - self.misc_errors.appendAssumeCapacity(.{ + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); + self.base.misc_errors.appendAssumeCapacity(.{ .msg = try gpa.dupe(u8, "TODO: non-LLVM archiver for MachO object files"), }); return error.FlushFailure; @@ -492,7 +489,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No try self.resolveSymbols(); if (self.getEntryPoint() == null) { - self.error_flags.no_entry_point_found = true; + self.base.error_flags.no_entry_point_found = true; } if (self.unresolved.count() > 0) { try self.reportUndefined(); @@ -2097,11 +2094,6 @@ pub fn deinit(self: *MachO) void { bindings.deinit(gpa); } self.bindings.deinit(gpa); - - for (self.misc_errors.items) |*err| { - err.deinit(gpa); - } - self.misc_errors.deinit(gpa); } fn freeAtom(self: *MachO, atom_index: Atom.Index) void { @@ -5341,13 +5333,13 @@ fn reportMissingLibraryError( args: anytype, ) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); const notes = try gpa.alloc(File.ErrorMsg, checked_paths.len); errdefer gpa.free(notes); for (checked_paths, notes) |path, *note| { note.* = .{ .msg = try std.fmt.allocPrint(gpa, "tried {s}", .{path}) }; } - self.misc_errors.appendAssumeCapacity(.{ + self.base.misc_errors.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, format, args), .notes = notes, }); @@ -5361,14 +5353,14 @@ fn reportDependencyError( args: anytype, ) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, 2); defer notes.deinit(); if (path) |p| { notes.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, "while parsing {s}", .{p}) }); } notes.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, "a dependency of {s}", .{parent}) }); - self.misc_errors.appendAssumeCapacity(.{ + self.base.misc_errors.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, format, args), .notes = try notes.toOwnedSlice(), }); @@ -5381,11 +5373,11 @@ pub fn reportParseError( args: anytype, ) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); var notes = try gpa.alloc(File.ErrorMsg, 1); errdefer gpa.free(notes); notes[0] = .{ .msg = try std.fmt.allocPrint(gpa, "while parsing {s}", .{path}) }; - self.misc_errors.appendAssumeCapacity(.{ + self.base.misc_errors.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, format, args), .notes = notes, }); @@ -5398,11 +5390,11 @@ pub fn reportUnresolvedBoundarySymbol( args: anytype, ) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); var notes = try gpa.alloc(File.ErrorMsg, 1); errdefer gpa.free(notes); notes[0] = .{ .msg = try std.fmt.allocPrint(gpa, "while resolving {s}", .{sym_name}) }; - self.misc_errors.appendAssumeCapacity(.{ + self.base.misc_errors.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, format, args), .notes = notes, }); @@ -5411,7 +5403,7 @@ pub fn reportUnresolvedBoundarySymbol( pub fn reportUndefined(self: *MachO) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; const count = self.unresolved.count(); - try self.misc_errors.ensureUnusedCapacity(gpa, count); + try self.base.misc_errors.ensureUnusedCapacity(gpa, count); for (self.unresolved.keys()) |global_index| { const global = self.globals.items[global_index]; @@ -5432,7 +5424,7 @@ pub fn reportUndefined(self: *MachO) error{OutOfMemory}!void { }; err_msg.notes = try notes.toOwnedSlice(); - self.misc_errors.appendAssumeCapacity(err_msg); + self.base.misc_errors.appendAssumeCapacity(err_msg); } } @@ -5442,7 +5434,7 @@ fn reportSymbolCollision( other: SymbolWithLoc, ) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, 2); defer notes.deinit(); @@ -5465,12 +5457,12 @@ fn reportSymbolCollision( }) }; err_msg.notes = try notes.toOwnedSlice(); - self.misc_errors.appendAssumeCapacity(err_msg); + self.base.misc_errors.appendAssumeCapacity(err_msg); } fn reportUnhandledSymbolType(self: *MachO, sym_with_loc: SymbolWithLoc) error{OutOfMemory}!void { const gpa = self.base.comp.gpa; - try self.misc_errors.ensureUnusedCapacity(gpa, 1); + try self.base.misc_errors.ensureUnusedCapacity(gpa, 1); const notes = try gpa.alloc(File.ErrorMsg, 1); errdefer gpa.free(notes); @@ -5488,7 +5480,7 @@ fn reportUnhandledSymbolType(self: *MachO, sym_with_loc: SymbolWithLoc) error{Ou else unreachable; - self.misc_errors.appendAssumeCapacity(.{ + self.base.misc_errors.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, "unhandled symbol type: '{s}' has type {s}", .{ self.getSymbolName(sym_with_loc), sym_type, diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 0263995359..d76a6de841 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -253,7 +253,8 @@ pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) ! } pub fn addRelocations(macho_file: *MachO, atom_index: Index, relocs: []const Relocation) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const gop = try macho_file.relocs.getOrPut(gpa, atom_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; @@ -269,7 +270,8 @@ pub fn addRelocations(macho_file: *MachO, atom_index: Index, relocs: []const Rel } pub fn addRebase(macho_file: *MachO, atom_index: Index, offset: u32) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const atom = macho_file.getAtom(atom_index); log.debug(" (adding rebase at offset 0x{x} in %{?d})", .{ offset, atom.getSymbolIndex() }); const gop = try macho_file.rebases.getOrPut(gpa, atom_index); @@ -280,7 +282,8 @@ pub fn addRebase(macho_file: *MachO, atom_index: Index, offset: u32) !void { } pub fn addBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const atom = macho_file.getAtom(atom_index); log.debug(" (adding binding to symbol {s} at offset 0x{x} in %{?d})", .{ macho_file.getSymbolName(binding.target), @@ -307,7 +310,8 @@ pub fn resolveRelocations( } pub fn freeRelocations(macho_file: *MachO, atom_index: Index) void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; var removed_relocs = macho_file.relocs.fetchOrderedRemove(atom_index); if (removed_relocs) |*relocs| relocs.value.deinit(gpa); var removed_rebases = macho_file.rebases.fetchOrderedRemove(atom_index); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index c970e72e51..3fe6aee009 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -28,7 +28,6 @@ pub const base_tag = .plan9; base: link.File, sixtyfour_bit: bool, -error_flags: File.ErrorFlags = File.ErrorFlags{}, bases: Bases, /// A symbol's value is just casted down when compiling -- cgit v1.2.3 From 2596f5d92593a5f7dad21d9a54f2d08f33639432 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Dec 2023 19:49:53 -0700 Subject: update bin_file.options references in Sema mainly pertaining to error return tracing --- src/Compilation/Config.zig | 22 ++++++++++++++++ src/Package/Module.zig | 10 ++------ src/Sema.zig | 64 +++++++++++++++++++++++----------------------- src/codegen/llvm.zig | 10 ++++---- src/main.zig | 5 ++++ 5 files changed, 66 insertions(+), 45 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 0afb633c86..efe314095c 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -9,6 +9,10 @@ link_libunwind: bool, any_unwind_tables: bool, any_c_source_files: bool, any_non_single_threaded: bool, +/// This is true if any Module has error_tracing set to true. Function types +/// and function calling convention depend on this global value, however, other +/// kinds of error tracing are omitted depending on the per-Module setting. +any_error_tracing: bool, pie: bool, /// If this is true then linker code is responsible for making an LLVM IR /// Module, outputting it to an object file, and then linking that together @@ -34,6 +38,8 @@ is_test: bool, test_evented_io: bool, entry: ?[]const u8, debug_format: DebugFormat, +root_strip: bool, +root_error_tracing: bool, pub const CFrontend = enum { clang, aro }; @@ -51,6 +57,7 @@ pub const Options = struct { emit_bin: bool, root_optimize_mode: ?std.builtin.OptimizeMode = null, root_strip: ?bool = null, + root_error_tracing: ?bool = null, link_mode: ?std.builtin.LinkMode = null, ensure_libc_on_non_freestanding: bool = false, ensure_libcpp_on_non_freestanding: bool = false, @@ -60,6 +67,7 @@ pub const Options = struct { any_dyn_libs: bool = false, any_c_source_files: bool = false, any_non_stripped: bool = false, + any_error_tracing: bool = false, emit_llvm_ir: bool = false, emit_llvm_bc: bool = false, link_libc: ?bool = null, @@ -395,6 +403,17 @@ pub fn resolve(options: Options) !Config { }; }; + const root_error_tracing = b: { + if (options.root_error_tracing) |x| break :b x; + if (root_strip) break :b false; + break :b switch (root_optimize_mode) { + .Debug => true, + .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, + }; + }; + + const any_error_tracing = root_error_tracing or options.any_error_tracing; + return .{ .output_mode = options.output_mode, .have_zcu = options.have_zcu, @@ -407,6 +426,8 @@ pub fn resolve(options: Options) !Config { .any_unwind_tables = any_unwind_tables, .any_c_source_files = options.any_c_source_files, .any_non_single_threaded = options.any_non_single_threaded, + .any_error_tracing = any_error_tracing, + .root_error_tracing = root_error_tracing, .pie = pie, .lto = lto, .import_memory = import_memory, @@ -419,6 +440,7 @@ pub fn resolve(options: Options) !Config { .entry = entry, .wasi_exec_model = wasi_exec_model, .debug_format = debug_format, + .root_strip = root_strip, }; } diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 051303ca26..5e786a6fa2 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -114,9 +114,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { const strip = b: { if (options.inherited.strip) |x| break :b x; if (options.parent) |p| break :b p.strip; - if (optimize_mode == .ReleaseSmall) break :b true; - if (!target_util.hasDebugInfo(target)) break :b true; - break :b false; + break :b options.global.root_strip; }; const valgrind = b: { @@ -156,11 +154,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { const error_tracing = b: { if (options.inherited.error_tracing) |x| break :b x; if (options.parent) |p| break :b p.error_tracing; - if (strip) break :b false; - break :b switch (optimize_mode) { - .Debug => true, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, - }; + break :b options.global.root_error_tracing; }; const pic = b: { diff --git a/src/Sema.zig b/src/Sema.zig index 2d46faf435..6d14deb095 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1329,13 +1329,13 @@ fn analyzeBodyInner( }, .dbg_block_begin => { dbg_block_begins += 1; - try sema.zirDbgBlockBegin(block); + try zirDbgBlockBegin(block); i += 1; continue; }, .dbg_block_end => { dbg_block_begins -= 1; - try sema.zirDbgBlockEnd(block); + try zirDbgBlockEnd(block); i += 1; continue; }, @@ -1830,17 +1830,17 @@ fn analyzeBodyInner( }; // balance out dbg_block_begins in case of early noreturn - const noreturn_inst = block.instructions.popOrNull(); - while (dbg_block_begins > 0) { - dbg_block_begins -= 1; - if (block.is_comptime or mod.comp.bin_file.options.strip) continue; - - _ = try block.addInst(.{ - .tag = .dbg_block_end, - .data = undefined, - }); + if (!block.is_comptime and !block.ownerModule().strip) { + const noreturn_inst = block.instructions.popOrNull(); + while (dbg_block_begins > 0) { + dbg_block_begins -= 1; + _ = try block.addInst(.{ + .tag = .dbg_block_end, + .data = undefined, + }); + } + if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); } - if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); // We may have overwritten the capture scope due to a `repeat` instruction where // the body had a capture; restore it now. @@ -6272,7 +6272,7 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi // ZIR code that possibly will need to generate runtime code. So error messages // and other source locations must not rely on sema.src being set from dbg_stmt // instructions. - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; + if (block.is_comptime or block.ownerModule().strip) return; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; @@ -6297,8 +6297,8 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi }); } -fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; +fn zirDbgBlockBegin(block: *Block) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; _ = try block.addInst(.{ .tag = .dbg_block_begin, @@ -6306,8 +6306,8 @@ fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { }); } -fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; +fn zirDbgBlockEnd(block: *Block) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; _ = try block.addInst(.{ .tag = .dbg_block_end, @@ -6321,7 +6321,7 @@ fn zirDbgVar( inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, ) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; + if (block.is_comptime or block.ownerModule().strip) return; const str_op = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_op; const operand = try sema.resolveInst(str_op.operand); @@ -6519,7 +6519,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref const src = sema.src; if (!mod.backendSupportsFeature(.error_return_trace)) return .none; - if (!mod.comp.bin_file.options.error_return_tracing) return .none; + if (!block.ownerModule().error_tracing) return .none; if (block.is_comptime) return .none; @@ -6703,7 +6703,7 @@ fn zirCall( input_is_error = false; } - if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and + if (mod.backendSupportsFeature(.error_return_trace) and block.ownerModule().error_tracing and !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) { const return_ty = sema.typeOf(call_inst); @@ -7456,7 +7456,7 @@ fn analyzeCall( new_fn_info.return_type = sema.fn_ret_ty.toIntern(); const new_func_resolved_ty = try mod.funcType(new_fn_info); if (!is_comptime_call and !block.is_typeof) { - try sema.emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); + try emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); const zir_tags = sema.code.instructions.items(.tag); for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) { @@ -7494,7 +7494,7 @@ fn analyzeCall( if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) { - try sema.emitDbgInline( + try emitDbgInline( block, module_fn_index, prev_fn_index, @@ -8067,15 +8067,13 @@ fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) } fn emitDbgInline( - sema: *Sema, block: *Block, old_func: InternPool.Index, new_func: InternPool.Index, new_func_ty: Type, tag: Air.Inst.Tag, ) CompileError!void { - const mod = sema.mod; - if (mod.comp.bin_file.options.strip) return; + if (block.ownerModule().strip) return; // Recursive inline call; no dbg_inline needed. if (old_func == new_func) return; @@ -9109,7 +9107,7 @@ fn handleExternLibName( ); break :blk; } - if (!target.isWasm() and !comp.bin_file.options.pic) { + if (!target.isWasm() and !block.ownerModule().pic) { return sema.fail( block, src_loc, @@ -18738,16 +18736,16 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { const mod = sema.mod; if (!mod.backendSupportsFeature(.error_return_trace)) return false; - return fn_ret_ty.isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + return fn_ret_ty.isError(mod) and mod.comp.config.any_error_tracing; } fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index; + // TODO: replace all of these checks with logic in module creation if (!mod.backendSupportsFeature(.error_return_trace)) return; - if (!mod.comp.bin_file.options.error_return_tracing) return; + if (!block.ownerModule().error_tracing) return; // This is only relevant at runtime. if (block.is_comptime or block.is_typeof) return; @@ -18774,7 +18772,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) if (!mod.backendSupportsFeature(.error_return_trace)) return; if (!ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn) return; - if (!mod.comp.bin_file.options.error_return_tracing) return; + if (!start_block.ownerModule().error_tracing) return; const tracy = trace(@src()); defer tracy.end(); @@ -20045,7 +20043,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { if (sema.owner_func_index != .none and ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn and - mod.comp.bin_file.options.error_return_tracing and + mod.ownerModule().error_tracing and mod.backendSupportsFeature(.error_return_trace)) { return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); @@ -34504,7 +34502,9 @@ pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void { try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.return_type)); - if (mod.comp.bin_file.options.error_return_tracing and Type.fromInterned(fn_ty_info.return_type).isError(mod)) { + if (mod.comp.config.any_error_tracing and + Type.fromInterned(fn_ty_info.return_type).isError(mod)) + { // Ensure the type exists so that backends can assume that. _ = try sema.getBuiltinType("StackTrace"); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6545f84f9d..75fb373d9b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1398,7 +1398,7 @@ pub const Object = struct { }; const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + mod.comp.config.any_error_tracing; const err_ret_trace: Builder.Value = if (err_return_tracing) param: { const param = wip.arg(llvm_arg_i); @@ -2820,7 +2820,7 @@ pub const Object = struct { } if (Type.fromInterned(fn_info.return_type).isError(mod) and - o.module.comp.bin_file.options.error_return_tracing) + o.module.comp.config.any_error_tracing) { const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); @@ -2988,7 +2988,7 @@ pub const Object = struct { } const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + mod.comp.config.any_error_tracing; if (err_return_tracing) { try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); @@ -3677,7 +3677,7 @@ pub const Object = struct { } if (Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing) + mod.comp.config.any_error_tracing) { const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try llvm_params.append(o.gpa, try o.lowerType(ptr_ty)); @@ -5142,7 +5142,7 @@ pub const FuncGen = struct { }; const err_return_tracing = return_type.isError(mod) and - o.module.comp.bin_file.options.error_return_tracing; + o.module.comp.config.any_error_tracing; if (err_return_tracing) { assert(self.err_ret_trace != .none); try llvm_args.append(self.err_ret_trace); diff --git a/src/main.zig b/src/main.zig index dbd9759015..b73023e5b3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1055,6 +1055,8 @@ fn buildOutputType( create_module.opts.any_unwind_tables = true; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; + if (mod_opts.error_tracing == true) + create_module.opts.any_error_tracing = true; const root_src = try introspect.resolvePath(arena, root_src_orig); try create_module.modules.put(arena, mod_name, .{ @@ -2535,6 +2537,8 @@ fn buildOutputType( create_module.opts.any_unwind_tables = true; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; + if (mod_opts.error_tracing == true) + create_module.opts.any_error_tracing = true; const src_path = try introspect.resolvePath(arena, unresolved_src_path); try create_module.modules.put(arena, "main", .{ @@ -3741,6 +3745,7 @@ fn createModule( create_module.opts.resolved_target = resolved_target; create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode; create_module.opts.root_strip = cli_mod.inherited.strip; + create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing; const target = resolved_target.result; // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. -- cgit v1.2.3 From b54ad9317591873159594e673953088a21d66e7b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Dec 2023 19:12:06 -0700 Subject: update codegen.llvm references to bin_file.options --- src/codegen/llvm.zig | 494 ++++++++++++++++++++++----------------------- src/link.zig | 46 +++++ src/link/Coff.zig | 17 +- src/link/Elf.zig | 47 +++-- src/link/Elf/Symbol.zig | 6 +- src/link/Elf/ZigObject.zig | 6 +- src/link/MachO.zig | 21 +- src/link/Wasm.zig | 21 +- 8 files changed, 354 insertions(+), 304 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 75fb373d9b..42180c6529 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -822,7 +822,7 @@ pub const Object = struct { type_map: TypeMap, di_type_map: DITypeMap, /// The LLVM global table which holds the names corresponding to Zig errors. - /// Note that the values are not added until flushModule, when all errors in + /// Note that the values are not added until `emit`, when all errors in /// the compilation are known. error_name_table: Builder.Variable.Index, /// This map is usually very close to empty. It tracks only the cases when a @@ -850,7 +850,7 @@ pub const Object = struct { pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type); - /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we + /// This is an ArrayHashMap as opposed to a HashMap because in `emit` we /// want to iterate over it while adding entries to it. pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); @@ -1026,17 +1026,6 @@ pub const Object = struct { self.* = undefined; } - fn locPath( - arena: Allocator, - opt_loc: ?Compilation.EmitLoc, - cache_directory: Compilation.Directory, - ) !?[*:0]u8 { - const loc = opt_loc orelse return null; - const directory = loc.directory orelse cache_directory; - const slice = try directory.joinZ(arena, &[_][]const u8{loc.basename}); - return slice.ptr; - } - fn genErrorNameTable(o: *Object) Allocator.Error!void { // If o.error_name_table is null, then it was not referenced by any instructions. if (o.error_name_table == .none) return; @@ -1175,12 +1164,22 @@ pub const Object = struct { } } - pub fn flushModule(self: *Object, comp: *Compilation, prog_node: *std.Progress.Node) !void { - var sub_prog_node = prog_node.start("LLVM Emit Object", 0); - sub_prog_node.activate(); - sub_prog_node.context.refresh(); - defer sub_prog_node.end(); + pub const EmitOptions = struct { + pre_ir_path: ?[]const u8, + pre_bc_path: ?[]const u8, + bin_path: ?[*:0]const u8, + emit_asm: ?[*:0]const u8, + post_ir_path: ?[*:0]const u8, + post_bc_path: ?[*:0]const u8, + + is_debug: bool, + is_small: bool, + time_report: bool, + sanitize_thread: bool, + lto: bool, + }; + pub fn emit(self: *Object, options: EmitOptions) !void { try self.resolveExportExternCollisions(); try self.genErrorNameTable(); try self.genCmpLtErrorsLenFunction(); @@ -1206,7 +1205,7 @@ pub const Object = struct { dib.finalize(); } - if (comp.verbose_llvm_ir) |path| { + if (options.pre_ir_path) |path| { if (std.mem.eql(u8, path, "-")) { self.builder.dump(); } else { @@ -1214,91 +1213,72 @@ pub const Object = struct { } } - if (comp.verbose_llvm_bc) |path| _ = try self.builder.writeBitcodeToFile(path); - - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - const mod = comp.module.?; - const cache_dir = mod.zig_cache_artifact_directory; + if (options.pre_bc_path) |path| _ = try self.builder.writeBitcodeToFile(path); if (std.debug.runtime_safety and !try self.builder.verify()) { - if (try locPath(arena, comp.emit_llvm_ir, cache_dir)) |emit_llvm_ir_path| - _ = self.builder.printToFileZ(emit_llvm_ir_path); @panic("LLVM module verification failed"); } - var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| - try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?)) - else - null; - - const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir); - var emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir); - const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir); - - const emit_asm_msg = emit_asm_path orelse "(none)"; - const emit_bin_msg = emit_bin_path orelse "(none)"; - const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)"; - const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)"; + const emit_asm_msg = options.asm_path orelse "(none)"; + const emit_bin_msg = options.bin_path orelse "(none)"; + const post_llvm_ir_msg = options.post_ir_path orelse "(none)"; + const post_llvm_bc_msg = options.post_bc_path orelse "(none)"; log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{ - emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg, + emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, }); - if (emit_asm_path == null and emit_bin_path == null and - emit_llvm_ir_path == null and emit_llvm_bc_path == null) return; + if (options.asm_path == null and options.bin_path == null and + options.post_ir_path == null and options.post_bc_path == null) return; - if (!self.builder.useLibLlvm()) { - log.err("emitting without libllvm not implemented", .{}); - return error.FailedToEmit; - } + if (!self.builder.useLibLlvm()) unreachable; // caught in Compilation.Config.resolve // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. // So we call the entire pipeline multiple times if this is requested. var error_message: [*:0]const u8 = undefined; - if (emit_asm_path != null and emit_bin_path != null) { + var emit_bin_path = options.bin_path; + var post_ir_path = options.post_ir_path; + if (options.asm_path != null and options.bin_path != null) { if (self.target_machine.emitToFile( self.builder.llvm.module.?, &error_message, - comp.bin_file.options.optimize_mode == .Debug, - comp.bin_file.options.optimize_mode == .ReleaseSmall, - comp.time_report, - comp.bin_file.options.tsan, - comp.bin_file.options.lto, + options.is_debug, + options.is_small, + options.time_report, + options.sanitize_thread, + options.lto, null, emit_bin_path, - emit_llvm_ir_path, + post_ir_path, null, )) { defer llvm.disposeMessage(error_message); log.err("LLVM failed to emit bin={s} ir={s}: {s}", .{ - emit_bin_msg, emit_llvm_ir_msg, error_message, + emit_bin_msg, post_llvm_ir_msg, error_message, }); return error.FailedToEmit; } emit_bin_path = null; - emit_llvm_ir_path = null; + post_ir_path = null; } if (self.target_machine.emitToFile( self.builder.llvm.module.?, &error_message, - comp.bin_file.options.optimize_mode == .Debug, - comp.bin_file.options.optimize_mode == .ReleaseSmall, - comp.time_report, - comp.bin_file.options.tsan, - comp.bin_file.options.lto, - emit_asm_path, + options.is_debug, + options.is_small, + options.time_report, + options.sanitize_thread, + options.lto, + options.asm_path, emit_bin_path, - emit_llvm_ir_path, - emit_llvm_bc_path, + post_ir_path, + options.post_bc_path, )) { defer llvm.disposeMessage(error_message); log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{ - emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg, + emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, error_message, }); return error.FailedToEmit; @@ -1307,17 +1287,19 @@ pub const Object = struct { pub fn updateFunc( o: *Object, - mod: *Module, + zcu: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness, ) !void { - const func = mod.funcInfo(func_index); + const func = zcu.funcInfo(func_index); const decl_index = func.owner_decl; - const decl = mod.declPtr(decl_index); - const fn_info = mod.typeToFunc(decl.ty).?; - const target = mod.getTarget(); - const ip = &mod.intern_pool; + const decl = zcu.declPtr(decl_index); + const namespace = zcu.namespacePtr(decl.src_namespace); + const owner_mod = namespace.file_scope.mod; + const fn_info = zcu.typeToFunc(decl.ty).?; + const target = zcu.getTarget(); + const ip = &zcu.intern_pool; var dg: DeclGen = .{ .object = o, @@ -1352,7 +1334,7 @@ pub const Object = struct { } // TODO: disable this if safety is off for the function scope - const ssp_buf_size = mod.comp.bin_file.options.stack_protector; + const ssp_buf_size = owner_mod.stack_protector; if (ssp_buf_size != 0) { try attributes.addFnAttr(.sspstrong, &o.builder); try attributes.addFnAttr(.{ .string = .{ @@ -1362,7 +1344,7 @@ pub const Object = struct { } // TODO: disable this if safety is off for the function scope - if (mod.comp.bin_file.options.stack_check) { + if (owner_mod.stack_check) { try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("probe-stack"), .value = try o.builder.string("__zig_probe_stack"), @@ -1385,20 +1367,22 @@ pub const Object = struct { var llvm_arg_i: u32 = 0; // This gets the LLVM values from the function and stores them in `dg.args`. - const sret = firstParamSRet(fn_info, mod); + const sret = firstParamSRet(fn_info, zcu); const ret_ptr: Builder.Value = if (sret) param: { const param = wip.arg(llvm_arg_i); llvm_arg_i += 1; break :param param; } else .none; - if (ccAbiPromoteInt(fn_info.cc, mod, Type.fromInterned(fn_info.return_type))) |s| switch (s) { + if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { .signed => try attributes.addRetAttr(.signext, &o.builder), .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), }; - const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.config.any_error_tracing; + const comp = zcu.comp; + + const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and + comp.config.any_error_tracing; const err_ret_trace: Builder.Value = if (err_return_tracing) param: { const param = wip.arg(llvm_arg_i); @@ -1426,8 +1410,8 @@ pub const Object = struct { const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); const param = wip.arg(llvm_arg_i); - if (isByRef(param_ty, mod)) { - const alignment = param_ty.abiAlignment(mod).toLlvm(); + if (isByRef(param_ty, zcu)) { + const alignment = param_ty.abiAlignment(zcu).toLlvm(); const param_llvm_ty = param.typeOfWip(&wip); const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); _ = try wip.store(.normal, param, arg_ptr, alignment); @@ -1443,12 +1427,12 @@ pub const Object = struct { const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); const param_llvm_ty = try o.lowerType(param_ty); const param = wip.arg(llvm_arg_i); - const alignment = param_ty.abiAlignment(mod).toLlvm(); + const alignment = param_ty.abiAlignment(zcu).toLlvm(); try o.addByRefParamAttrs(&attributes, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); llvm_arg_i += 1; - if (isByRef(param_ty, mod)) { + if (isByRef(param_ty, zcu)) { args.appendAssumeCapacity(param); } else { args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); @@ -1458,12 +1442,12 @@ pub const Object = struct { const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); const param_llvm_ty = try o.lowerType(param_ty); const param = wip.arg(llvm_arg_i); - const alignment = param_ty.abiAlignment(mod).toLlvm(); + const alignment = param_ty.abiAlignment(zcu).toLlvm(); try attributes.addParamAttr(llvm_arg_i, .noundef, &o.builder); llvm_arg_i += 1; - if (isByRef(param_ty, mod)) { + if (isByRef(param_ty, zcu)) { args.appendAssumeCapacity(param); } else { args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); @@ -1476,11 +1460,11 @@ pub const Object = struct { llvm_arg_i += 1; const param_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(mod).toLlvm(); + const alignment = param_ty.abiAlignment(zcu).toLlvm(); const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); _ = try wip.store(.normal, param, arg_ptr, alignment); - args.appendAssumeCapacity(if (isByRef(param_ty, mod)) + args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) arg_ptr else try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); @@ -1488,14 +1472,14 @@ pub const Object = struct { .slice => { assert(!it.byval_attr); const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const ptr_info = param_ty.ptrInfo(mod); + const ptr_info = param_ty.ptrInfo(zcu); if (math.cast(u5, it.zig_index - 1)) |i| { if (@as(u1, @truncate(fn_info.noalias_bits >> i)) != 0) { try attributes.addParamAttr(llvm_arg_i, .@"noalias", &o.builder); } } - if (param_ty.zigTypeTag(mod) != .Optional) { + if (param_ty.zigTypeTag(zcu) != .Optional) { try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); } if (ptr_info.flags.is_const) { @@ -1504,7 +1488,7 @@ pub const Object = struct { const elem_align = (if (ptr_info.flags.alignment != .none) @as(InternPool.Alignment, ptr_info.flags.alignment) else - Type.fromInterned(ptr_info.child).abiAlignment(mod).max(.@"1")).toLlvm(); + Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm(); try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); const ptr_param = wip.arg(llvm_arg_i); llvm_arg_i += 1; @@ -1521,7 +1505,7 @@ pub const Object = struct { const field_types = it.types_buffer[0..it.types_len]; const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); const param_llvm_ty = try o.lowerType(param_ty); - const param_alignment = param_ty.abiAlignment(mod).toLlvm(); + const param_alignment = param_ty.abiAlignment(zcu).toLlvm(); const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target); const llvm_ty = try o.builder.structType(.normal, field_types); for (0..field_types.len) |field_i| { @@ -1533,7 +1517,7 @@ pub const Object = struct { _ = try wip.store(.normal, param, field_ptr, alignment); } - const is_by_ref = isByRef(param_ty, mod); + const is_by_ref = isByRef(param_ty, zcu); args.appendAssumeCapacity(if (is_by_ref) arg_ptr else @@ -1551,11 +1535,11 @@ pub const Object = struct { const param = wip.arg(llvm_arg_i); llvm_arg_i += 1; - const alignment = param_ty.abiAlignment(mod).toLlvm(); + const alignment = param_ty.abiAlignment(zcu).toLlvm(); const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); _ = try wip.store(.normal, param, arg_ptr, alignment); - args.appendAssumeCapacity(if (isByRef(param_ty, mod)) + args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) arg_ptr else try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); @@ -1566,11 +1550,11 @@ pub const Object = struct { const param = wip.arg(llvm_arg_i); llvm_arg_i += 1; - const alignment = param_ty.abiAlignment(mod).toLlvm(); + const alignment = param_ty.abiAlignment(zcu).toLlvm(); const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target); _ = try wip.store(.normal, param, arg_ptr, alignment); - args.appendAssumeCapacity(if (isByRef(param_ty, mod)) + args.appendAssumeCapacity(if (isByRef(param_ty, zcu)) arg_ptr else try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); @@ -1584,14 +1568,12 @@ pub const Object = struct { var di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn = null; var di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn = null; - const namespace = mod.namespacePtr(decl.src_namespace); - if (o.di_builder) |dib| { di_file = try o.getDIFile(gpa, namespace.file_scope); const line_number = decl.src_line + 1; - const is_internal_linkage = decl.val.getExternFunc(mod) == null and - !mod.decl_exports.contains(decl_index); + const is_internal_linkage = decl.val.getExternFunc(zcu) == null and + !zcu.decl_exports.contains(decl_index); const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type) llvm.DIFlags.NoReturn else @@ -1608,7 +1590,7 @@ pub const Object = struct { true, // is definition line_number + func.lbrace_line, // scope line llvm.DIFlags.StaticMember | noret_bit, - mod.comp.bin_file.options.optimize_mode != .Debug, + owner_mod.optimize_mode != .Debug, null, // decl_subprogram ); try o.di_map.put(gpa, decl, subprogram.toNode()); @@ -1618,8 +1600,6 @@ pub const Object = struct { di_scope = subprogram.toScope(); } - const single_threaded = namespace.file_scope.mod.single_threaded; - var fg: FuncGen = .{ .gpa = gpa, .air = air, @@ -1631,7 +1611,7 @@ pub const Object = struct { .arg_index = 0, .func_inst_table = .{}, .blocks = .{}, - .sync_scope = if (single_threaded) .singlethread else .system, + .sync_scope = if (owner_mod.single_threaded) .singlethread else .system, .di_scope = di_scope, .di_file = di_file, .base_line = dg.decl.src_line, @@ -1645,7 +1625,7 @@ pub const Object = struct { fg.genBody(air.getMainBody()) catch |err| switch (err) { error.CodegenFail => { decl.analysis = .codegen_failure; - try mod.failed_decls.put(mod.gpa, decl_index, dg.err_msg.?); + try zcu.failed_decls.put(zcu.gpa, decl_index, dg.err_msg.?); dg.err_msg = null; return; }, @@ -1654,7 +1634,7 @@ pub const Object = struct { try fg.wip.finish(); - try o.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index)); + try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index)); } pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void { @@ -2933,22 +2913,24 @@ pub const Object = struct { o: *Object, decl_index: InternPool.DeclIndex, ) Allocator.Error!Builder.Function.Index { - const mod = o.module; - const ip = &mod.intern_pool; + const zcu = o.module; + const ip = &zcu.intern_pool; const gpa = o.gpa; - const decl = mod.declPtr(decl_index); + const decl = zcu.declPtr(decl_index); + const namespace = zcu.namespacePtr(decl.src_namespace); + const owner_mod = namespace.file_scope.mod; const zig_fn_type = decl.ty; const gop = try o.decl_map.getOrPut(gpa, decl_index); if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function; assert(decl.has_tv); - const fn_info = mod.typeToFunc(zig_fn_type).?; - const target = mod.getTarget(); - const sret = firstParamSRet(fn_info, mod); + const fn_info = zcu.typeToFunc(zig_fn_type).?; + const target = owner_mod.resolved_target.result; + const sret = firstParamSRet(fn_info, zcu); const function_index = try o.builder.addFunction( try o.lowerType(zig_fn_type), - try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(mod))), + try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(zcu))), toLlvmAddressSpace(decl.@"addrspace", target), ); gop.value_ptr.* = function_index.ptrConst(&o.builder).global; @@ -2956,7 +2938,7 @@ pub const Object = struct { var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); - const is_extern = decl.isExtern(mod); + const is_extern = decl.isExtern(zcu); if (!is_extern) { function_index.setLinkage(.internal, &o.builder); function_index.setUnnamedAddr(.unnamed_addr, &o.builder); @@ -2966,7 +2948,7 @@ pub const Object = struct { .kind = try o.builder.string("wasm-import-name"), .value = try o.builder.string(ip.stringToSlice(decl.name)), } }, &o.builder); - if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { + if (ip.stringToSliceUnwrap(decl.getOwnedExternFunc(zcu).?.lib_name)) |lib_name| { if (!std.mem.eql(u8, lib_name, "c")) try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("wasm-import-module"), .value = try o.builder.string(lib_name), @@ -2987,8 +2969,8 @@ pub const Object = struct { llvm_arg_i += 1; } - const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.config.any_error_tracing; + const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and + zcu.comp.config.any_error_tracing; if (err_return_tracing) { try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); @@ -3009,7 +2991,7 @@ pub const Object = struct { function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); // Function attributes that are independent of analysis results of the function body. - try o.addCommonFnAttributes(&attributes); + try o.addCommonFnAttributes(&attributes, owner_mod); if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder); @@ -3022,14 +3004,14 @@ pub const Object = struct { .byval => { const param_index = it.zig_index - 1; const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); - if (!isByRef(param_ty, mod)) { + if (!isByRef(param_ty, zcu)) { try o.addByValParamAttrs(&attributes, param_ty, param_index, fn_info, it.llvm_index - 1); } }, .byref => { const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); const param_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(mod); + const alignment = param_ty.abiAlignment(zcu); try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); }, .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder), @@ -3055,13 +3037,14 @@ pub const Object = struct { fn addCommonFnAttributes( o: *Object, attributes: *Builder.FunctionAttributes.Wip, + owner_mod: *Package.Module, ) Allocator.Error!void { const comp = o.module.comp; - if (!comp.bin_file.options.red_zone) { + if (!owner_mod.red_zone) { try attributes.addFnAttr(.noredzone, &o.builder); } - if (comp.bin_file.options.omit_frame_pointer) { + if (owner_mod.omit_frame_pointer) { try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("frame-pointer"), .value = try o.builder.string("none"), @@ -3073,7 +3056,7 @@ pub const Object = struct { } }, &o.builder); } try attributes.addFnAttr(.nounwind, &o.builder); - if (comp.unwind_tables) { + if (owner_mod.unwind_tables) { try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); } if (comp.skip_linker_dependencies or comp.no_builtin) { @@ -3084,26 +3067,27 @@ pub const Object = struct { // overflow instead of performing memcpy. try attributes.addFnAttr(.nobuiltin, &o.builder); } - if (comp.bin_file.options.optimize_mode == .ReleaseSmall) { + if (owner_mod.optimize_mode == .ReleaseSmall) { try attributes.addFnAttr(.minsize, &o.builder); try attributes.addFnAttr(.optsize, &o.builder); } - if (comp.bin_file.options.tsan) { + if (owner_mod.sanitize_thread) { try attributes.addFnAttr(.sanitize_thread, &o.builder); } - if (comp.getTarget().cpu.model.llvm_name) |s| { + const target = owner_mod.resolved_target.result; + if (target.cpu.model.llvm_name) |s| { try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("target-cpu"), .value = try o.builder.string(s), } }, &o.builder); } - if (comp.bin_file.options.llvm_cpu_features) |s| { + if (owner_mod.resolved_target.llvm_cpu_features) |s| { try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("target-features"), .value = try o.builder.string(std.mem.span(s)), } }, &o.builder); } - if (comp.getTarget().cpu.arch.isBpf()) { + if (target.cpu.arch.isBpf()) { try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("no-builtins"), .value = .empty, @@ -4646,6 +4630,100 @@ pub const Object = struct { .field_index = @intCast(field_index), }); } + + fn getCmpLtErrorsLenFunction(o: *Object) !Builder.Function.Index { + const name = try o.builder.string(lt_errors_fn_name); + if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function; + + const zcu = o.module; + const target = zcu.root_mod.resolved_target.result; + const function_index = try o.builder.addFunction( + try o.builder.fnType(.i1, &.{try o.errorIntType()}, .normal), + name, + toLlvmAddressSpace(.generic, target), + ); + + var attributes: Builder.FunctionAttributes.Wip = .{}; + defer attributes.deinit(&o.builder); + try o.addCommonFnAttributes(&attributes, zcu.root_mod); + + function_index.setLinkage(.internal, &o.builder); + function_index.setCallConv(.fastcc, &o.builder); + function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); + return function_index; + } + + fn getEnumTagNameFunction(o: *Object, enum_ty: Type) !Builder.Function.Index { + const zcu = o.module; + const ip = &zcu.intern_pool; + const enum_type = ip.indexToKey(enum_ty.toIntern()).enum_type; + + // TODO: detect when the type changes and re-emit this function. + const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl); + if (gop.found_existing) return gop.value_ptr.ptrConst(&o.builder).kind.function; + errdefer assert(o.decl_map.remove(enum_type.decl)); + + const usize_ty = try o.lowerType(Type.usize); + const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0); + const fqn = try zcu.declPtr(enum_type.decl).getFullyQualifiedName(zcu); + const target = zcu.root_mod.resolved_target.result; + const function_index = try o.builder.addFunction( + try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), + try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(ip)}), + toLlvmAddressSpace(.generic, target), + ); + + var attributes: Builder.FunctionAttributes.Wip = .{}; + defer attributes.deinit(&o.builder); + try o.addCommonFnAttributes(&attributes, zcu.root_mod); + + function_index.setLinkage(.internal, &o.builder); + function_index.setCallConv(.fastcc, &o.builder); + function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); + gop.value_ptr.* = function_index.ptrConst(&o.builder).global; + + var wip = try Builder.WipFunction.init(&o.builder, function_index); + defer wip.deinit(); + wip.cursor = .{ .block = try wip.block(0, "Entry") }; + + const bad_value_block = try wip.block(1, "BadValue"); + const tag_int_value = wip.arg(0); + var wip_switch = + try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len)); + defer wip_switch.finish(&wip); + + for (0..enum_type.names.len) |field_index| { + const name = try o.builder.string(ip.stringToSlice(enum_type.names.get(ip)[field_index])); + const name_init = try o.builder.stringNullConst(name); + const name_variable_index = + try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); + try name_variable_index.setInitializer(name_init, &o.builder); + name_variable_index.setLinkage(.private, &o.builder); + name_variable_index.setMutability(.constant, &o.builder); + name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); + name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); + + const name_val = try o.builder.structValue(ret_ty, &.{ + name_variable_index.toConst(&o.builder), + try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len), + }); + + const return_block = try wip.block(1, "Name"); + const this_tag_int_value = try o.lowerValue( + (try zcu.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(), + ); + try wip_switch.addCase(this_tag_int_value, return_block, &wip); + + wip.cursor = .{ .block = return_block }; + _ = try wip.ret(name_val); + } + + wip.cursor = .{ .block = bad_value_block }; + _ = try wip.@"unreachable"(); + + try wip.finish(); + return function_index; + } }; pub const DeclGen = struct { @@ -4654,6 +4732,13 @@ pub const DeclGen = struct { decl_index: InternPool.DeclIndex, err_msg: ?*Module.ErrorMsg, + fn ownerModule(dg: DeclGen) *Package.Module { + const o = dg.object; + const zcu = o.module; + const namespace = zcu.namespacePtr(dg.decl.src_namespace); + return namespace.file_scope.mod; + } + fn todo(dg: *DeclGen, comptime format: []const u8, args: anytype) Error { @setCold(true); assert(dg.err_msg == null); @@ -5614,7 +5699,7 @@ pub const FuncGen = struct { const o = self.dg.object; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); - const llvm_fn = try self.getCmpLtErrorsLenFunction(); + const llvm_fn = try o.getCmpLtErrorsLenFunction(); return self.wip.call( .normal, .fastcc, @@ -6547,11 +6632,13 @@ pub const FuncGen = struct { const dib = o.di_builder orelse return .none; const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn; - const mod = o.module; - const func = mod.funcInfo(ty_fn.func); + const zcu = o.module; + const func = zcu.funcInfo(ty_fn.func); const decl_index = func.owner_decl; - const decl = mod.declPtr(decl_index); - const di_file = try o.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope); + const decl = zcu.declPtr(decl_index); + const namespace = zcu.namespacePtr(decl.src_namespace); + const owner_mod = namespace.file_scope.mod; + const di_file = try o.getDIFile(self.gpa, zcu.namespacePtr(decl.src_namespace).file_scope); self.di_file = di_file; const line_number = decl.src_line + 1; const cur_debug_location = self.wip.llvm.builder.getCurrentDebugLocation2(); @@ -6562,18 +6649,18 @@ pub const FuncGen = struct { .base_line = self.base_line, }); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.getFullyQualifiedName(zcu); - const is_internal_linkage = !mod.decl_exports.contains(decl_index); - const fn_ty = try mod.funcType(.{ + const is_internal_linkage = !zcu.decl_exports.contains(decl_index); + const fn_ty = try zcu.funcType(.{ .param_types = &.{}, .return_type = .void_type, }); const fn_di_ty = try o.lowerDebugType(fn_ty, .full); const subprogram = dib.createFunction( di_file.toScope(), - mod.intern_pool.stringToSlice(decl.name), - mod.intern_pool.stringToSlice(fqn), + zcu.intern_pool.stringToSlice(decl.name), + zcu.intern_pool.stringToSlice(fqn), di_file, line_number, fn_di_ty, @@ -6581,7 +6668,7 @@ pub const FuncGen = struct { true, // is definition line_number + func.lbrace_line, // scope line llvm.DIFlags.StaticMember, - mod.comp.bin_file.options.optimize_mode != .Debug, + owner_mod.optimize_mode != .Debug, null, // decl_subprogram ); @@ -6676,11 +6763,12 @@ pub const FuncGen = struct { null; const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at); const insert_block = self.wip.cursor.block.toLlvm(&self.wip); - const mod = o.module; - if (isByRef(operand_ty, mod)) { + const zcu = o.module; + const owner_mod = self.dg.ownerModule(); + if (isByRef(operand_ty, zcu)) { _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); - } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) { - const alignment = operand_ty.abiAlignment(mod).toLlvm(); + } else if (owner_mod.optimize_mode == .Debug) { + const alignment = operand_ty.abiAlignment(zcu).toLlvm(); const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment); _ = try self.wip.store(.normal, operand, alloca, alignment); _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); @@ -8729,9 +8817,10 @@ pub const FuncGen = struct { const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null); const insert_block = self.wip.cursor.block.toLlvm(&self.wip); + const owner_mod = self.dg.ownerModule(); if (isByRef(inst_ty, mod)) { _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block); - } else if (o.module.comp.bin_file.options.optimize_mode == .Debug) { + } else if (owner_mod.optimize_mode == .Debug) { const alignment = inst_ty.abiAlignment(mod).toLlvm(); const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment); _ = try self.wip.store(.normal, arg_val, alloca, alignment); @@ -8821,7 +8910,8 @@ pub const FuncGen = struct { len, if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal, ); - if (safety and mod.comp.bin_file.options.valgrind) { + const owner_mod = self.dg.ownerModule(); + if (safety and owner_mod.valgrind) { try self.valgrindMarkUndef(dest_ptr, len); } return .none; @@ -9137,7 +9227,8 @@ pub const FuncGen = struct { } else { _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind); } - if (safety and mod.comp.bin_file.options.valgrind) { + const owner_mod = self.dg.ownerModule(); + if (safety and owner_mod.valgrind) { try self.valgrindMarkUndef(dest_ptr, len); } return .none; @@ -9488,24 +9579,25 @@ pub const FuncGen = struct { fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index { const o = self.dg.object; - const mod = o.module; - const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type; + const zcu = o.module; + const enum_type = zcu.intern_pool.indexToKey(enum_ty.toIntern()).enum_type; // TODO: detect when the type changes and re-emit this function. const gop = try o.named_enum_map.getOrPut(o.gpa, enum_type.decl); if (gop.found_existing) return gop.value_ptr.*; errdefer assert(o.named_enum_map.remove(enum_type.decl)); - const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); + const fqn = try zcu.declPtr(enum_type.decl).getFullyQualifiedName(zcu); + const target = zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), - try o.builder.fmt("__zig_is_named_enum_value_{}", .{fqn.fmt(&mod.intern_pool)}), - toLlvmAddressSpace(.generic, mod.getTarget()), + try o.builder.fmt("__zig_is_named_enum_value_{}", .{fqn.fmt(&zcu.intern_pool)}), + toLlvmAddressSpace(.generic, target), ); var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); - try o.addCommonFnAttributes(&attributes); + try o.addCommonFnAttributes(&attributes, zcu.root_mod); function_index.setLinkage(.internal, &o.builder); function_index.setCallConv(.fastcc, &o.builder); @@ -9524,7 +9616,7 @@ pub const FuncGen = struct { for (0..enum_type.names.len) |field_index| { const this_tag_int_value = try o.lowerValue( - (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(), + (try zcu.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(), ); try wip_switch.addCase(this_tag_int_value, named_block, &wip); } @@ -9544,7 +9636,7 @@ pub const FuncGen = struct { const operand = try self.resolveInst(un_op); const enum_ty = self.typeOf(un_op); - const llvm_fn = try self.getEnumTagNameFunction(enum_ty); + const llvm_fn = try o.getEnumTagNameFunction(enum_ty); return self.wip.call( .normal, .fastcc, @@ -9556,100 +9648,6 @@ pub const FuncGen = struct { ); } - fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !Builder.Function.Index { - const o = self.dg.object; - const mod = o.module; - const ip = &mod.intern_pool; - const enum_type = ip.indexToKey(enum_ty.toIntern()).enum_type; - - // TODO: detect when the type changes and re-emit this function. - const gop = try o.decl_map.getOrPut(o.gpa, enum_type.decl); - if (gop.found_existing) return gop.value_ptr.ptrConst(&o.builder).kind.function; - errdefer assert(o.decl_map.remove(enum_type.decl)); - - const usize_ty = try o.lowerType(Type.usize); - const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0); - const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); - const function_index = try o.builder.addFunction( - try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), - try o.builder.fmt("__zig_tag_name_{}", .{fqn.fmt(ip)}), - toLlvmAddressSpace(.generic, mod.getTarget()), - ); - - var attributes: Builder.FunctionAttributes.Wip = .{}; - defer attributes.deinit(&o.builder); - try o.addCommonFnAttributes(&attributes); - - function_index.setLinkage(.internal, &o.builder); - function_index.setCallConv(.fastcc, &o.builder); - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); - gop.value_ptr.* = function_index.ptrConst(&o.builder).global; - - var wip = try Builder.WipFunction.init(&o.builder, function_index); - defer wip.deinit(); - wip.cursor = .{ .block = try wip.block(0, "Entry") }; - - const bad_value_block = try wip.block(1, "BadValue"); - const tag_int_value = wip.arg(0); - var wip_switch = - try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len)); - defer wip_switch.finish(&wip); - - for (0..enum_type.names.len) |field_index| { - const name = try o.builder.string(ip.stringToSlice(enum_type.names.get(ip)[field_index])); - const name_init = try o.builder.stringNullConst(name); - const name_variable_index = - try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default); - try name_variable_index.setInitializer(name_init, &o.builder); - name_variable_index.setLinkage(.private, &o.builder); - name_variable_index.setMutability(.constant, &o.builder); - name_variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); - name_variable_index.setAlignment(comptime Builder.Alignment.fromByteUnits(1), &o.builder); - - const name_val = try o.builder.structValue(ret_ty, &.{ - name_variable_index.toConst(&o.builder), - try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len), - }); - - const return_block = try wip.block(1, "Name"); - const this_tag_int_value = try o.lowerValue( - (try mod.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(), - ); - try wip_switch.addCase(this_tag_int_value, return_block, &wip); - - wip.cursor = .{ .block = return_block }; - _ = try wip.ret(name_val); - } - - wip.cursor = .{ .block = bad_value_block }; - _ = try wip.@"unreachable"(); - - try wip.finish(); - return function_index; - } - - fn getCmpLtErrorsLenFunction(self: *FuncGen) !Builder.Function.Index { - const o = self.dg.object; - - const name = try o.builder.string(lt_errors_fn_name); - if (o.builder.getGlobal(name)) |llvm_fn| return llvm_fn.ptrConst(&o.builder).kind.function; - - const function_index = try o.builder.addFunction( - try o.builder.fnType(.i1, &.{try o.errorIntType()}, .normal), - name, - toLlvmAddressSpace(.generic, o.module.getTarget()), - ); - - var attributes: Builder.FunctionAttributes.Wip = .{}; - defer attributes.deinit(&o.builder); - try o.addCommonFnAttributes(&attributes); - - function_index.setLinkage(.internal, &o.builder); - function_index.setCallConv(.fastcc, &o.builder); - function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); - return function_index; - } - fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { const o = self.dg.object; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; diff --git a/src/link.zig b/src/link.zig index ce12e922d7..77169afa29 100644 --- a/src/link.zig +++ b/src/link.zig @@ -18,6 +18,7 @@ const Module = @import("Module.zig"); const InternPool = @import("InternPool.zig"); const Type = @import("type.zig").Type; const TypedValue = @import("TypedValue.zig"); +const LlvmObject = @import("codegen/llvm.zig").Object; /// When adding a new field, remember to update `hashAddSystemLibs`. /// These are *always* dynamically linked. Static libraries will be @@ -1046,6 +1047,51 @@ pub const File = struct { return output_mode == .Lib and !self.isStatic(); } + pub fn resolveEmitLoc( + base: File, + arena: Allocator, + opt_loc: ?Compilation.EmitLoc, + ) Allocator.Error!?[*:0]u8 { + const loc = opt_loc orelse return null; + const slice = if (loc.directory) |directory| + try directory.joinZ(arena, &.{loc.basename}) + else + try base.emit.basenamePath(arena, loc.basename); + return slice.ptr; + } + + pub fn emitLlvmObject( + base: File, + arena: Allocator, + llvm_object: *LlvmObject, + prog_node: *std.Progress.Node, + ) !void { + const comp = base.comp; + + var sub_prog_node = prog_node.start("LLVM Emit Object", 0); + sub_prog_node.activate(); + sub_prog_node.context.refresh(); + defer sub_prog_node.end(); + + try llvm_object.emit(comp, .{ + .pre_ir_path = comp.verbose_llvm_ir, + .pre_bc_path = comp.verbose_llvm_bc, + .bin_path = try base.resolveEmitLoc(arena, .{ + .directory = null, + .basename = base.intermediary_basename.?, + }), + .asm_path = try base.resolveEmitLoc(arena, comp.emit_asm), + .post_llvm_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir), + .post_llvm_bc_path = try base.resolveEmitLoc(arena, comp.emit_llvm_bc), + + .is_debug = comp.root_mod.optimize_mode == .Debug, + .is_small = comp.root_mod.optimize_mode == .ReleaseSmall, + .time_report = comp.time_report, + .sanitize_thread = comp.config.any_sanitize_thread, + .lto = comp.config.lto, + }); + } + pub const C = @import("link/C.zig"); pub const Coff = @import("link/Coff.zig"); pub const Plan9 = @import("link/Plan9.zig"); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 762591442b..52ca7e554c 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -3,7 +3,7 @@ //! LLD for traditional linking (linking relocatable object files). //! LLD is also the default linker for LLVM. -/// If this is not null, an object file is created by LLVM and linked with LLD afterwards. +/// If this is not null, an object file is created by LLVM and emitted to intermediary_basename. llvm_object: ?*LlvmObject = null, base: link.File, @@ -1711,17 +1711,22 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const tracy = trace(@src()); defer tracy.end(); + const gpa = comp.gpa; + if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp, prog_node); + var arena_allocator = std.heap.ArenaAllocator.init(gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + + try self.base.emitLlvmObject(arena, llvm_object, prog_node); + return; } var sub_prog_node = prog_node.start("COFF Flush", 0); sub_prog_node.activate(); defer sub_prog_node.end(); - const gpa = self.base.comp.gpa; - - const module = self.base.comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; + const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; if (self.lazy_syms.getPtr(.none)) |metadata| { // Most lazy symbols can be updated on first use, but @@ -1822,7 +1827,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try self.writeDataDirectoriesHeaders(); try self.writeSectionHeaders(); - if (self.entry_addr == null and self.base.comp.config.output_mode == .Exe) { + if (self.entry_addr == null and comp.config.output_mode == .Exe) { log.debug("flushing. no_entry_point_found = true\n", .{}); self.base.error_flags.no_entry_point_found = true; } else { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 3e237fe494..fe89a6321f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -27,7 +27,7 @@ version_script: ?[]const u8, ptr_width: PtrWidth, -/// If this is not null, an object file is created by LLVM and linked with LLD afterwards. +/// If this is not null, an object file is created by LLVM and emitted to intermediary_basename. llvm_object: ?*LlvmObject = null, /// A list of all input files. @@ -1031,24 +1031,23 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node const tracy = trace(@src()); defer tracy.end(); - if (self.llvm_object) |llvm_object| { - try llvm_object.flushModule(comp, prog_node); + const gpa = comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); - const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; + if (self.llvm_object) |llvm_object| { + try self.base.emitLlvmObject(arena, llvm_object, prog_node); + const use_lld = build_options.have_llvm and comp.config.use_lld; if (use_lld) return; } - const gpa = self.base.comp.gpa; var sub_prog_node = prog_node.start("ELF Flush", 0); sub_prog_node.activate(); defer sub_prog_node.end(); - var arena_allocator = std.heap.ArenaAllocator.init(gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - const target = self.base.comp.root_mod.resolved_target.result; - const link_mode = self.base.comp.config.link_mode; + const target = comp.root_mod.resolved_target.result; + const link_mode = comp.config.link_mode; const directory = self.base.emit.directory; // Just an alias to make it shorter to type. const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: { @@ -1060,7 +1059,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } else null; // --verbose-link - if (self.base.comp.verbose_link) try self.dumpArgv(comp); + if (comp.verbose_link) try self.dumpArgv(comp); const csu = try CsuObjects.init(arena, comp); const compiler_rt_path: ?[]const u8 = blk: { @@ -1082,8 +1081,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node if (csu.crti) |v| try positionals.append(.{ .path = v }); if (csu.crtbegin) |v| try positionals.append(.{ .path = v }); - try positionals.ensureUnusedCapacity(self.base.comp.objects.len); - positionals.appendSliceAssumeCapacity(self.base.comp.objects); + try positionals.ensureUnusedCapacity(comp.objects.len); + positionals.appendSliceAssumeCapacity(comp.objects); // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up @@ -1106,13 +1105,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node var test_path = std.ArrayList(u8).init(gpa); defer test_path.deinit(); for (self.lib_dirs) |lib_dir_path| { - for (self.base.comp.system_libs.keys()) |link_lib| { + for (comp.system_libs.keys()) |link_lib| { if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic))) continue; _ = try rpath_table.put(lib_dir_path, {}); } } - for (self.base.comp.objects) |obj| { + for (comp.objects) |obj| { if (Compilation.classifyFileExt(obj.path) == .shared_library) { const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; if (obj.loption) continue; @@ -1122,7 +1121,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node } // TSAN - if (self.base.comp.config.any_sanitize_thread) { + if (comp.config.any_sanitize_thread) { try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path }); } @@ -1146,27 +1145,27 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node var system_libs = std.ArrayList(SystemLib).init(arena); - try system_libs.ensureUnusedCapacity(self.base.comp.system_libs.values().len); - for (self.base.comp.system_libs.values()) |lib_info| { + try system_libs.ensureUnusedCapacity(comp.system_libs.values().len); + for (comp.system_libs.values()) |lib_info| { system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? }); } // libc++ dep - if (self.base.comp.config.link_libcpp) { + if (comp.config.link_libcpp) { try system_libs.ensureUnusedCapacity(2); system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }); system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path }); } // libunwind dep - if (self.base.comp.config.link_libunwind) { + if (comp.config.link_libunwind) { try system_libs.append(.{ .path = comp.libunwind_static_lib.?.full_object_path }); } // libc dep self.base.error_flags.missing_libc = false; - if (self.base.comp.config.link_libc) { - if (self.base.comp.libc_installation) |lc| { + if (comp.config.link_libc) { + if (comp.libc_installation) |lc| { const flags = target_util.libcFullLinkFlags(target); try system_libs.ensureUnusedCapacity(flags.len); @@ -1305,7 +1304,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Look for entry address in objects if not set by the incremental compiler. if (self.entry_index == null) { const entry: ?[]const u8 = entry: { - if (self.base.comp.config.entry) |entry| break :entry entry; + if (comp.config.entry) |entry| break :entry entry; if (!self.base.isDynLib()) break :entry "_start"; break :entry null; }; diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 3dd35dfe63..7c7d3fd17c 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -43,7 +43,7 @@ pub fn outputShndx(symbol: Symbol) ?u16 { } pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool { - if (elf_file.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL; + if (elf_file.base.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL; return !(symbol.flags.import or symbol.flags.@"export"); } @@ -186,7 +186,7 @@ const GetOrCreateZigGotEntryResult = struct { }; pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult { - assert(!elf_file.isRelocatable()); + assert(!elf_file.base.isRelocatable()); assert(symbol.flags.needs_zig_got); if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got }; const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file); @@ -237,7 +237,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { const st_shndx = blk: { if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?; if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; - if (elf_file.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON; + if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON; if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; break :blk symbol.outputShndx() orelse elf.SHN_UNDEF; }; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 75bc53bb48..b6be4013ce 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -926,7 +926,7 @@ fn updateDeclCode( sym.value = atom_ptr.value; esym.st_value = atom_ptr.value; - if (!elf_file.isRelocatable()) { + if (!elf_file.base.isRelocatable()) { log.debug(" (writing new offset table entry)", .{}); assert(sym.flags.has_zig_got); const extra = sym.extra(elf_file).?; @@ -944,7 +944,7 @@ fn updateDeclCode( sym.flags.needs_zig_got = true; esym.st_value = atom_ptr.value; - if (!elf_file.isRelocatable()) { + if (!elf_file.base.isRelocatable()) { const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file); try elf_file.zig_got.writeOne(elf_file, gop.index); } @@ -1262,7 +1262,7 @@ fn updateLazySymbol( local_sym.flags.needs_zig_got = true; local_esym.st_value = atom_ptr.value; - if (!elf_file.isRelocatable()) { + if (!elf_file.base.isRelocatable()) { const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file); try elf_file.zig_got.writeOne(elf_file, gop.index); } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 104c83b357..9af563b047 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1,6 +1,6 @@ base: File, -/// If this is not null, an object file is created by LLVM and linked with LLD afterwards. +/// If this is not null, an object file is created by LLVM and emitted to intermediary_basename. llvm_object: ?*LlvmObject = null, /// Debug symbols bundle (or dSym). @@ -352,22 +352,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No const tracy = trace(@src()); defer tracy.end(); - if (self.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp, prog_node); - } - - const gpa = self.base.comp.gpa; + const gpa = comp.gpa; var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); + if (self.llvm_object) |llvm_object| { + try self.base.emitLlvmObject(arena, llvm_object, prog_node); + return; + } + var sub_prog_node = prog_node.start("MachO Flush", 0); sub_prog_node.activate(); defer sub_prog_node.end(); - const output_mode = self.base.comp.config.output_mode; - const module = self.base.comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; - const target = self.base.comp.root_mod.resolved_target.result; + const output_mode = comp.config.output_mode; + const module = comp.module orelse return error.LinkingWithoutZigSourceUnimplemented; + const target = comp.root_mod.resolved_target.result; if (self.lazy_syms.getPtr(.none)) |metadata| { // Most lazy symbols can be updated on first use, but @@ -619,7 +620,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No .stacksize = self.base.stack_size, }); }, - .Lib => if (self.base.comp.config.link_mode == .Dynamic) { + .Lib => if (comp.config.link_mode == .Dynamic) { try load_commands.writeDylibIdLC(self, lc_writer); }, else => {}, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 8f63e7c6fd..6488231afa 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -3700,8 +3700,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod const tracy = trace(@src()); defer tracy.end(); + const gpa = comp.gpa; + // Used for all temporary memory allocated during flushin + var arena_instance = std.heap.ArenaAllocator.init(gpa); + defer arena_instance.deinit(); + const arena = arena_instance.allocator(); + if (wasm.llvm_object) |llvm_object| { - return try llvm_object.flushModule(comp, prog_node); + try wasm.base.emitLlvmObject(arena, llvm_object, prog_node); + return; } var sub_prog_node = prog_node.start("Wasm Flush", 0); @@ -3711,13 +3718,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod // ensure the error names table is populated when an error name is referenced try wasm.populateErrorNameTable(); - // Used for all temporary memory allocated during flushin - const gpa = wasm.base.comp.gpa; - var arena_instance = std.heap.ArenaAllocator.init(gpa); - defer arena_instance.deinit(); - const arena = arena_instance.allocator(); - - const objects = wasm.base.comp.objects; + const objects = comp.objects; // Positional arguments to the linker such as object files and static archives. var positionals = std.ArrayList([]const u8).init(arena); @@ -3755,7 +3756,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod try wasm.markReferences(); try wasm.setupErrorsLen(); try wasm.setupImports(); - if (wasm.base.comp.module) |mod| { + if (comp.module) |mod| { var decl_it = wasm.decls.iterator(); while (decl_it.next()) |entry| { const decl = mod.declPtr(entry.key_ptr.*); @@ -3810,7 +3811,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod } if (wasm.dwarf) |*dwarf| { - try dwarf.flushModule(wasm.base.comp.module.?); + try dwarf.flushModule(comp.module.?); } } -- cgit v1.2.3 From 638db680f4c6380bb193da520f29a7c587bfb719 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Dec 2023 19:25:34 -0700 Subject: move dll_export_fns and rdynamic to Compilation.Config --- src/Compilation.zig | 13 +++---------- src/Compilation/Config.zig | 17 +++++++++++++++++ src/codegen/llvm.zig | 17 ++++++++--------- src/link.zig | 2 -- src/link/Coff.zig | 2 -- src/link/Elf.zig | 10 ++++------ src/link/Wasm.zig | 13 ++++++------- src/main.zig | 16 ++++++---------- 8 files changed, 44 insertions(+), 46 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 7b7e85d0f7..c742e59af5 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -956,7 +956,6 @@ pub const InitOptions = struct { emit_docs: ?EmitLoc = null, /// `null` means to not emit an import lib. emit_implib: ?EmitLoc = null, - dll_export_fns: ?bool = false, /// Normally when using LLD to link, Zig uses a file named "lld.id" in the /// same directory as the output binary which contains the hash of the link /// operation, allowing Zig to skip linking when the hash would be unchanged. @@ -989,7 +988,6 @@ pub const InitOptions = struct { want_compiler_rt: ?bool = null, want_lto: ?bool = null, formatted_panics: ?bool = null, - rdynamic: bool = false, function_sections: bool = false, data_sections: bool = false, no_builtin: bool = false, @@ -1200,8 +1198,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { const link_libc = options.config.link_libc; - const dll_export_fns = options.dll_export_fns orelse (is_dyn_lib or options.rdynamic); - const libc_dirs = try detectLibCIncludeDirs( arena, options.zig_lib_directory.path.?, @@ -1524,10 +1520,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .gc_sections = options.linker_gc_sections, .eh_frame_hdr = link_eh_frame_hdr, .emit_relocs = options.link_emit_relocs, - .rdynamic = options.rdynamic, .soname = options.soname, .compatibility_version = options.compatibility_version, - .dll_export_fns = dll_export_fns, .each_lib_rpath = each_lib_rpath, .build_id = build_id, .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, @@ -1555,7 +1549,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { // Synchronize with other matching comments: ZigOnlyHashStuff hash.add(use_llvm); hash.add(options.config.use_lib_llvm); - hash.add(dll_export_fns); + hash.add(options.config.dll_export_fns); hash.add(options.config.is_test); hash.add(options.config.test_evented_io); hash.addOptionalBytes(options.test_filter); @@ -2430,6 +2424,8 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.config.import_memory); man.hash.add(comp.config.export_memory); man.hash.add(comp.config.shared_memory); + man.hash.add(comp.config.dll_export_fns); + man.hash.add(comp.config.rdynamic); if (comp.bin_file) |lf| { man.hash.add(lf.stack_size); @@ -2442,7 +2438,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes switch (lf.tag) { .elf => { const elf = lf.cast(link.File.Elf).?; - man.hash.add(elf.rdynamic); man.hash.add(elf.eh_frame_hdr); man.hash.add(elf.image_base); man.hash.add(elf.emit_relocs); @@ -2468,7 +2463,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes }, .wasm => { const wasm = lf.cast(link.File.Wasm).?; - man.hash.add(wasm.rdynamic); man.hash.addOptional(wasm.initial_memory); man.hash.addOptional(wasm.max_memory); man.hash.addOptional(wasm.global_base); @@ -2485,7 +2479,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes }, .coff => { const coff = lf.cast(link.File.Coff).?; - man.hash.add(coff.dll_export_fns); man.hash.add(coff.image_base); man.hash.addOptional(coff.subsystem); man.hash.add(coff.tsaware); diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 44ace55ae4..442b7a1b9a 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -41,6 +41,8 @@ entry: ?[]const u8, debug_format: DebugFormat, root_strip: bool, root_error_tracing: bool, +dll_export_fns: bool, +rdynamic: bool, pub const CFrontend = enum { clang, aro }; @@ -93,6 +95,8 @@ pub const Options = struct { shared_memory: ?bool = null, test_evented_io: bool = false, debug_format: ?Config.DebugFormat = null, + dll_export_fns: ?bool = null, + rdynamic: ?bool = null, }; pub fn resolve(options: Options) !Config { @@ -415,6 +419,17 @@ pub fn resolve(options: Options) !Config { const any_error_tracing = root_error_tracing or options.any_error_tracing; + const rdynamic = options.rdynamic orelse false; + + const dll_export_fns = b: { + if (options.dll_export_fns) |x| break :b x; + if (rdynamic) break :b true; + break :b switch (options.output_mode) { + .Obj, .Exe => false, + .Lib => link_mode == .Dynamic, + }; + }; + return .{ .output_mode = options.output_mode, .have_zcu = options.have_zcu, @@ -443,6 +458,8 @@ pub fn resolve(options: Options) !Config { .wasi_exec_model = wasi_exec_model, .debug_format = debug_format, .root_strip = root_strip, + .dll_export_fns = dll_export_fns, + .rdynamic = rdynamic, }; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 42180c6529..7e25a4b59b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1672,6 +1672,7 @@ pub const Object = struct { // because we call `updateExports` at the end of `updateFunc` and `updateDecl`. const global_index = self.decl_map.get(decl_index) orelse return; const decl = mod.declPtr(decl_index); + const comp = mod.comp; if (decl.isExtern(mod)) { const decl_name = decl_name: { const decl_name = mod.intern_pool.stringToSlice(decl.name); @@ -1696,7 +1697,8 @@ pub const Object = struct { try global_index.rename(decl_name, &self.builder); global_index.setLinkage(.external, &self.builder); global_index.setUnnamedAddr(.default, &self.builder); - if (wantDllExports(mod)) global_index.setDllStorageClass(.default, &self.builder); + if (comp.config.dll_export_fns) + global_index.setDllStorageClass(.default, &self.builder); if (self.di_map.get(decl)) |di_node| { const decl_name_slice = decl_name.slice(&self.builder).?; if (try decl.isFunction(mod)) { @@ -1762,7 +1764,8 @@ pub const Object = struct { ); try global_index.rename(fqn, &self.builder); global_index.setLinkage(.internal, &self.builder); - if (wantDllExports(mod)) global_index.setDllStorageClass(.default, &self.builder); + if (comp.config.dll_export_fns) + global_index.setDllStorageClass(.default, &self.builder); global_index.setUnnamedAddr(.unnamed_addr, &self.builder); if (decl.val.getVariable(mod)) |decl_var| { const decl_namespace = mod.namespacePtr(decl.src_namespace); @@ -1821,7 +1824,9 @@ pub const Object = struct { exports: []const *Module.Export, ) link.File.UpdateExportsError!void { global_index.setUnnamedAddr(.default, &o.builder); - if (wantDllExports(mod)) global_index.setDllStorageClass(.dllexport, &o.builder); + const comp = mod.comp; + if (comp.config.dll_export_fns) + global_index.setDllStorageClass(.dllexport, &o.builder); global_index.setLinkage(switch (exports[0].opts.linkage) { .Internal => unreachable, .Strong => .external, @@ -11758,9 +11763,3 @@ fn constraintAllowsRegister(constraint: []const u8) bool { } } else return false; } - -fn wantDllExports(zcu: *const Zcu) bool { - const lf = zcu.bin_file.?; - const coff = lf.cast(link.File.Coff) orelse return false; - return coff.dll_export_fns; -} diff --git a/src/link.zig b/src/link.zig index 77169afa29..14b180ed2a 100644 --- a/src/link.zig +++ b/src/link.zig @@ -88,7 +88,6 @@ pub const File = struct { image_base: ?u64, eh_frame_hdr: bool, emit_relocs: bool, - rdynamic: bool, z_nodelete: bool, z_notext: bool, z_defs: bool, @@ -110,7 +109,6 @@ pub const File = struct { max_memory: ?u64, export_symbol_names: []const []const u8, global_base: ?u64, - dll_export_fns: bool, each_lib_rpath: bool, build_id: std.zig.BuildId, disable_lld_caching: bool, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 52ca7e554c..c02aecf2db 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -8,7 +8,6 @@ llvm_object: ?*LlvmObject = null, base: link.File, image_base: u64, -dll_export_fns: bool, subsystem: ?std.Target.SubSystem, tsaware: bool, nxcompat: bool, @@ -416,7 +415,6 @@ pub fn createEmpty( .Obj => 0, }, - .dll_export_fns = options.dll_export_fns, .subsystem = options.subsystem, .tsaware = options.tsaware, .nxcompat = options.nxcompat, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index fe89a6321f..47b4712b57 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1,6 +1,5 @@ base: link.File, image_base: u64, -rdynamic: bool, eh_frame_hdr: bool, emit_relocs: bool, z_nodelete: bool, @@ -370,7 +369,7 @@ pub fn createEmpty( else => 0x1000, }; const is_dyn_lib = output_mode == .Lib and link_mode == .Dynamic; - const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or options.rdynamic) + const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or comp.config.rdynamic) elf.VER_NDX_GLOBAL else elf.VER_NDX_LOCAL; @@ -402,7 +401,6 @@ pub fn createEmpty( }; }, - .rdynamic = options.rdynamic, .eh_frame_hdr = options.eh_frame_hdr, .emit_relocs = options.emit_relocs, .z_nodelete = options.z_nodelete, @@ -1725,7 +1723,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("--eh-frame-hdr"); } - if (self.rdynamic) { + if (comp.config.rdynamic) { try argv.append("--export-dynamic"); } @@ -2434,7 +2432,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.addOptional(self.sort_section); man.hash.add(self.eh_frame_hdr); man.hash.add(self.emit_relocs); - man.hash.add(self.rdynamic); + man.hash.add(comp.config.rdynamic); man.hash.addListOfBytes(self.lib_dirs); man.hash.addListOfBytes(self.base.rpath_list); man.hash.add(self.each_lib_rpath); @@ -2637,7 +2635,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--emit-relocs"); } - if (self.rdynamic) { + if (comp.config.rdynamic) { try argv.append("--export-dynamic"); } diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 6488231afa..874cc2d9b3 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -39,7 +39,6 @@ pub const base_tag: link.File.Tag = .wasm; base: link.File, import_symbols: bool, export_symbol_names: []const []const u8, -rdynamic: bool, global_base: ?u64, initial_memory: ?u64, max_memory: ?u64, @@ -563,7 +562,6 @@ pub fn createEmpty( .export_table = options.export_table, .import_symbols = options.import_symbols, .export_symbol_names = options.export_symbol_names, - .rdynamic = options.rdynamic, .global_base = options.global_base, .initial_memory = options.initial_memory, .max_memory = options.max_memory, @@ -2973,8 +2971,9 @@ fn mergeTypes(wasm: *Wasm) !void { } fn setupExports(wasm: *Wasm) !void { - const gpa = wasm.base.comp.gpa; - if (wasm.base.comp.config.output_mode == .Obj) return; + const comp = wasm.base.comp; + const gpa = comp.gpa; + if (comp.config.output_mode == .Obj) return; log.debug("Building exports from symbols", .{}); const force_exp_names = wasm.export_symbol_names; @@ -2999,7 +2998,7 @@ fn setupExports(wasm: *Wasm) !void { for (wasm.resolved_symbols.keys()) |sym_loc| { const symbol = sym_loc.getSymbol(wasm); - if (!symbol.isExported(wasm.rdynamic)) continue; + if (!symbol.isExported(comp.config.rdynamic)) continue; const sym_name = sym_loc.getName(wasm); const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { @@ -4789,7 +4788,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append(arg); } - if (wasm.rdynamic) { + if (comp.config.rdynamic) { try argv.append("--export-dynamic"); } @@ -5288,7 +5287,7 @@ fn markReferences(wasm: *Wasm) !void { for (wasm.resolved_symbols.keys()) |sym_loc| { const sym = sym_loc.getSymbol(wasm); - if (sym.isExported(wasm.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { + if (sym.isExported(comp.config.rdynamic) or sym.isNoStrip() or !do_garbage_collect) { try wasm.mark(sym_loc); continue; } diff --git a/src/main.zig b/src/main.zig index b73023e5b3..ee6468d41f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -786,7 +786,6 @@ fn buildOutputType( arg_mode: ArgMode, ) !void { var provided_name: ?[]const u8 = null; - var dll_export_fns: ?bool = null; var root_src_file: ?[]const u8 = null; var version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 }; var have_version = false; @@ -824,7 +823,6 @@ fn buildOutputType( var soname: SOName = undefined; var want_native_include_dirs = false; var want_compiler_rt: ?bool = null; - var rdynamic: bool = false; var linker_script: ?[]const u8 = null; var version_script: ?[]const u8 = null; var disable_c_depfile = false; @@ -1411,7 +1409,7 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-error-tracing")) { mod_opts.error_tracing = false; } else if (mem.eql(u8, arg, "-rdynamic")) { - rdynamic = true; + create_module.opts.rdynamic = true; } else if (mem.eql(u8, arg, "-fsoname")) { soname = .yes_default_value; } else if (mem.startsWith(u8, arg, "-fsoname=")) { @@ -1472,9 +1470,9 @@ fn buildOutputType( lib_preferred_mode = .Static; lib_search_strategy = .no_fallback; } else if (mem.eql(u8, arg, "-fdll-export-fns")) { - dll_export_fns = true; + create_module.opts.dll_export_fns = true; } else if (mem.eql(u8, arg, "-fno-dll-export-fns")) { - dll_export_fns = false; + create_module.opts.dll_export_fns = false; } else if (mem.eql(u8, arg, "--show-builtin")) { show_builtin = true; emit_bin = .no; @@ -1882,7 +1880,7 @@ fn buildOutputType( create_module.opts.link_mode = .Dynamic; is_shared_lib = true; }, - .rdynamic => rdynamic = true, + .rdynamic => create_module.opts.rdynamic = true, .wl => { var split_it = mem.splitScalar(u8, it.only_arg, ','); while (split_it.next()) |linker_arg| { @@ -2136,7 +2134,7 @@ fn buildOutputType( mem.eql(u8, arg, "--export-dynamic") or mem.eql(u8, arg, "-export-dynamic")) { - rdynamic = true; + create_module.opts.rdynamic = true; } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { version_script = linker_args_it.nextOrFatal(); } else if (mem.eql(u8, arg, "-O")) { @@ -2295,7 +2293,7 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "--high-entropy-va")) { // This option does not do anything. } else if (mem.eql(u8, arg, "--export-all-symbols")) { - rdynamic = true; + create_module.opts.rdynamic = true; } else if (mem.eql(u8, arg, "--color-diagnostics") or mem.eql(u8, arg, "--color-diagnostics=always")) { @@ -3365,7 +3363,6 @@ fn buildOutputType( .emit_llvm_bc = emit_llvm_bc_resolved.data, .emit_docs = emit_docs_resolved.data, .emit_implib = emit_implib_resolved.data, - .dll_export_fns = dll_export_fns, .lib_dirs = lib_dirs.items, .rpath_list = rpath_list.items, .symbol_wrap_set = symbol_wrap_set, @@ -3381,7 +3378,6 @@ fn buildOutputType( .wasi_emulated_libs = create_module.wasi_emulated_libs.items, .want_compiler_rt = want_compiler_rt, .hash_style = hash_style, - .rdynamic = rdynamic, .linker_script = linker_script, .version_script = version_script, .disable_c_depfile = disable_c_depfile, -- cgit v1.2.3 From 2047a6b82d2e6cdbddde3e7f1c93df9e72216052 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Dec 2023 00:39:36 -0700 Subject: fix remaining compile errors except one --- src/Compilation.zig | 8 +- src/Module.zig | 11 +- src/Sema.zig | 2 +- src/arch/x86_64/CodeGen.zig | 46 +++--- src/codegen/llvm.zig | 2 +- src/link.zig | 298 ++++++++++++++++----------------------- src/link/C.zig | 1 + src/link/Coff.zig | 15 +- src/link/Coff/lld.zig | 45 +++--- src/link/Dwarf.zig | 6 +- src/link/Elf.zig | 12 +- src/link/Elf/Atom.zig | 6 +- src/link/Elf/Object.zig | 6 +- src/link/Elf/ZigObject.zig | 2 +- src/link/Elf/eh_frame.zig | 2 +- src/link/MachO.zig | 34 +++-- src/link/MachO/Object.zig | 16 ++- src/link/MachO/dead_strip.zig | 3 +- src/link/MachO/eh_frame.zig | 9 +- src/link/MachO/load_commands.zig | 33 +++-- src/link/MachO/thunks.zig | 6 +- src/link/MachO/zld.zig | 42 +++--- src/link/NvPtx.zig | 3 +- src/link/Plan9.zig | 11 +- src/link/SpirV.zig | 19 +-- src/link/Wasm.zig | 9 +- src/link/Wasm/Object.zig | 10 +- src/main.zig | 24 ++-- 28 files changed, 340 insertions(+), 341 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index a39d852563..14a39f1bb3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -229,7 +229,7 @@ pub const Emit = struct { /// Returns the full path to `basename` if it were in the same directory as the /// `Emit` sub_path. - pub fn basenamePath(emit: Emit, arena: Allocator, basename: [:0]const u8) ![:0]const u8 { + pub fn basenamePath(emit: Emit, arena: Allocator, basename: []const u8) ![:0]const u8 { const full_path = if (emit.directory.path) |p| try std.fs.path.join(arena, &[_][]const u8{ p, emit.sub_path }) else @@ -238,7 +238,7 @@ pub const Emit = struct { if (std.fs.path.dirname(full_path)) |dirname| { return try std.fs.path.joinZ(arena, &.{ dirname, basename }); } else { - return basename; + return try arena.dupeZ(u8, basename); } } }; @@ -1038,8 +1038,8 @@ pub const InitOptions = struct { linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null, linker_module_definition_file: ?[]const u8 = null, linker_sort_section: ?link.File.Elf.SortSection = null, - major_subsystem_version: ?u32 = null, - minor_subsystem_version: ?u32 = null, + major_subsystem_version: ?u16 = null, + minor_subsystem_version: ?u16 = null, clang_passthrough_mode: bool = false, verbose_cc: bool = false, verbose_link: bool = false, diff --git a/src/Module.zig b/src/Module.zig index 571301c8e6..6d5a2f78a6 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4309,14 +4309,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err decl.has_linksection_or_addrspace = has_linksection_or_addrspace; decl.zir_decl_index = @enumFromInt(decl_sub_index); if (decl.getOwnedFunction(mod) != null) { - switch (comp.bin_file.tag) { - .coff, .elf, .macho, .plan9 => { - // TODO Look into detecting when this would be unnecessary by storing enough state - // in `Decl` to notice that the line number did not change. - comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); - }, - .c, .wasm, .spirv, .nvptx => {}, - } + // TODO Look into detecting when this would be unnecessary by storing enough state + // in `Decl` to notice that the line number did not change. + comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index }); } } diff --git a/src/Sema.zig b/src/Sema.zig index 6d14deb095..26afd285c7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20043,7 +20043,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { if (sema.owner_func_index != .none and ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn and - mod.ownerModule().error_tracing and + block.ownerModule().error_tracing and mod.backendSupportsFeature(.error_return_trace)) { return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index dbb87fa566..55e241cbd4 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -800,19 +800,20 @@ pub fn generate( ) CodeGenError!Result { const comp = bin_file.comp; const gpa = comp.gpa; - const mod = comp.module.?; - const func = mod.funcInfo(func_index); - const fn_owner_decl = mod.declPtr(func.owner_decl); + const zcu = comp.module.?; + const func = zcu.funcInfo(func_index); + const fn_owner_decl = zcu.declPtr(func.owner_decl); assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; - const namespace = mod.namespacePtr(fn_owner_decl.src_namespace); - const target = namespace.file_scope.mod.resolved_target.result; + const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace); + const mod = namespace.file_scope.mod; var function = Self{ .gpa = gpa, .air = air, .liveness = liveness, - .target = target, + .target = &mod.resolved_target.result, + .mod = mod, .bin_file = bin_file, .debug_output = debug_output, .owner = .{ .func_index = func_index }, @@ -843,7 +844,7 @@ pub fn generate( wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)}); - const ip = &mod.intern_pool; + const ip = &zcu.intern_pool; try function.frame_allocs.resize(gpa, FrameIndex.named_count); function.frame_allocs.set( @@ -858,7 +859,7 @@ pub fn generate( FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }), ); - const fn_info = mod.typeToFunc(fn_type).?; + const fn_info = zcu.typeToFunc(fn_type).?; const cc = abi.resolveCallingConvention(fn_info.cc, function.target.*); var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) { error.CodegenFail => return Result{ .fail = function.err_msg.? }, @@ -877,14 +878,14 @@ pub fn generate( function.args = call_info.args; function.ret_mcv = call_info.return_value; function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{ - .size = Type.usize.abiSize(mod), - .alignment = Type.usize.abiAlignment(mod).min(call_info.stack_align), + .size = Type.usize.abiSize(zcu), + .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align), })); function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{ - .size = Type.usize.abiSize(mod), + .size = Type.usize.abiSize(zcu), .alignment = Alignment.min( call_info.stack_align, - Alignment.fromNonzeroByteUnits(target.stackAlignment()), + Alignment.fromNonzeroByteUnits(function.target.stackAlignment()), ), })); function.frame_allocs.set( @@ -927,6 +928,9 @@ pub fn generate( .mir = mir, .cc = cc, .src_loc = src_loc, + .output_mode = comp.config.output_mode, + .link_mode = comp.config.link_mode, + .pic = mod.pic, }, .debug_output = debug_output, .code = code, @@ -970,16 +974,14 @@ pub fn generateLazy( ) CodeGenError!Result { const comp = bin_file.comp; const gpa = comp.gpa; - const zcu = comp.module.?; - const decl_index = lazy_sym.ty.getOwnerDecl(zcu); - const decl = zcu.declPtr(decl_index); - const namespace = zcu.namespacePtr(decl.src_namespace); - const target = namespace.file_scope.mod.resolved_target.result; + // This function is for generating global code, so we use the root module. + const mod = comp.root_mod; var function = Self{ .gpa = gpa, .air = undefined, .liveness = undefined, - .target = target, + .target = &mod.resolved_target.result, + .mod = mod, .bin_file = bin_file, .debug_output = debug_output, .owner = .{ .lazy_sym = lazy_sym }, @@ -1020,6 +1022,9 @@ pub fn generateLazy( .mir = mir, .cc = abi.resolveCallingConvention(.Unspecified, function.target.*), .src_loc = src_loc, + .output_mode = comp.config.output_mode, + .link_mode = comp.config.link_mode, + .pic = mod.pic, }, .debug_output = debug_output, .code = code, @@ -1104,6 +1109,8 @@ fn formatWipMir( _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { + const comp = data.self.bin_file.comp; + const mod = comp.root_mod; var lower = Lower{ .bin_file = data.self.bin_file, .allocator = data.self.gpa, @@ -1114,6 +1121,9 @@ fn formatWipMir( }, .cc = .Unspecified, .src_loc = data.self.src_loc, + .output_mode = comp.config.output_mode, + .link_mode = comp.config.link_mode, + .pic = mod.pic, }; var first = true; for ((lower.lowerMir(data.inst) catch |err| switch (err) { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 7e25a4b59b..3a53bddcb8 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1168,7 +1168,7 @@ pub const Object = struct { pre_ir_path: ?[]const u8, pre_bc_path: ?[]const u8, bin_path: ?[*:0]const u8, - emit_asm: ?[*:0]const u8, + asm_path: ?[*:0]const u8, post_ir_path: ?[*:0]const u8, post_bc_path: ?[*:0]const u8, diff --git a/src/link.zig b/src/link.zig index 14b180ed2a..3e5caf9fc1 100644 --- a/src/link.zig +++ b/src/link.zig @@ -61,6 +61,7 @@ pub const File = struct { intermediary_basename: ?[]const u8 = null, disable_lld_caching: bool, gc_sections: bool, + print_gc_sections: bool, build_id: std.zig.BuildId, rpath_list: []const []const u8, /// List of symbols forced as undefined in the symbol table @@ -114,8 +115,8 @@ pub const File = struct { disable_lld_caching: bool, hash_style: Elf.HashStyle, sort_section: ?Elf.SortSection, - major_subsystem_version: ?u32, - minor_subsystem_version: ?u32, + major_subsystem_version: ?u16, + minor_subsystem_version: ?u16, gc_sections: ?bool, allow_shlib_undefined: ?bool, subsystem: ?std.Target.SubSystem, @@ -181,9 +182,15 @@ pub const File = struct { emit: Compilation.Emit, options: OpenOptions, ) !*File { - switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { - inline else => |tag| { - const ptr = try tag.Type().open(arena, comp, emit, options); + const tag = Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt); + switch (tag) { + .c => { + const ptr = try C.open(arena, comp, emit, options); + return &ptr.base; + }, + inline else => |t| { + if (build_options.only_c) unreachable; + const ptr = try t.Type().open(arena, comp, emit, options); return &ptr.base; }, } @@ -195,9 +202,15 @@ pub const File = struct { emit: Compilation.Emit, options: OpenOptions, ) !*File { - switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { - inline else => |tag| { - const ptr = try tag.Type().createEmpty(arena, comp, emit, options); + const tag = Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt); + switch (tag) { + .c => { + const ptr = try C.createEmpty(arena, comp, emit, options); + return &ptr.base; + }, + inline else => |t| { + if (build_options.only_c) unreachable; + const ptr = try t.Type().createEmpty(arena, comp, emit, options); return &ptr.base; }, } @@ -360,16 +373,12 @@ pub const File = struct { pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 { if (build_options.only_c) @compileError("unreachable"); switch (base.tag) { - // zig fmt: off - .coff => return @fieldParentPtr(Coff, "base", base).lowerUnnamedConst(tv, decl_index), - .elf => return @fieldParentPtr(Elf, "base", base).lowerUnnamedConst(tv, decl_index), - .macho => return @fieldParentPtr(MachO, "base", base).lowerUnnamedConst(tv, decl_index), - .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerUnnamedConst(tv, decl_index), .spirv => unreachable, - .c => unreachable, - .wasm => return @fieldParentPtr(Wasm, "base", base).lowerUnnamedConst(tv, decl_index), + .c => unreachable, .nvptx => unreachable, - // zig fmt: on + inline else => |t| { + return @fieldParentPtr(t.Type(), "base", base).lowerUnnamedConst(tv, decl_index); + }, } } @@ -382,16 +391,13 @@ pub const File = struct { if (build_options.only_c) @compileError("unreachable"); log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name }); switch (base.tag) { - // zig fmt: off - .coff => return @fieldParentPtr(Coff, "base", base).getGlobalSymbol(name, lib_name), - .elf => return @fieldParentPtr(Elf, "base", base).getGlobalSymbol(name, lib_name), - .macho => return @fieldParentPtr(MachO, "base", base).getGlobalSymbol(name, lib_name), .plan9 => unreachable, .spirv => unreachable, - .c => unreachable, - .wasm => return @fieldParentPtr(Wasm, "base", base).getGlobalSymbol(name, lib_name), + .c => unreachable, .nvptx => unreachable, - // zig fmt: on + inline else => |t| { + return @fieldParentPtr(t.Type(), "base", base).getGlobalSymbol(name, lib_name); + }, } } @@ -399,59 +405,48 @@ pub const File = struct { pub fn updateDecl(base: *File, module: *Module, decl_index: InternPool.DeclIndex) UpdateDeclError!void { const decl = module.declPtr(decl_index); assert(decl.has_tv); - if (build_options.only_c) { - assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).updateDecl(module, decl_index); - } switch (base.tag) { - // zig fmt: off - .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl_index), - .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl_index), - .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl_index), - .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl_index), - .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl_index), - .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl_index), - .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl_index), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateDecl(module, decl_index), - // zig fmt: on + .c => { + return @fieldParentPtr(C, "base", base).updateDecl(module, decl_index); + }, + inline else => |tag| { + if (build_options.only_c) unreachable; + return @fieldParentPtr(tag.Type(), "base", base).updateDecl(module, decl_index); + }, } } /// May be called before or after updateExports for any given Decl. - pub fn updateFunc(base: *File, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) UpdateDeclError!void { - if (build_options.only_c) { - assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness); - } + pub fn updateFunc( + base: *File, + module: *Module, + func_index: InternPool.Index, + air: Air, + liveness: Liveness, + ) UpdateDeclError!void { switch (base.tag) { - // zig fmt: off - .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func_index, air, liveness), - .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func_index, air, liveness), - .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func_index, air, liveness), - .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness), - .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func_index, air, liveness), - .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func_index, air, liveness), - .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func_index, air, liveness), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func_index, air, liveness), - // zig fmt: on + .c => { + return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness); + }, + inline else => |tag| { + if (build_options.only_c) unreachable; + return @fieldParentPtr(tag.Type(), "base", base).updateFunc(module, func_index, air, liveness); + }, } } pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: InternPool.DeclIndex) UpdateDeclError!void { const decl = module.declPtr(decl_index); assert(decl.has_tv); - if (build_options.only_c) { - assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index); - } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl_index), - .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl_index), - .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl_index), - .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index), - .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl_index), - .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl_index), .spirv, .nvptx => {}, + .c => { + return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index); + }, + inline else => |tag| { + if (build_options.only_c) unreachable; + return @fieldParentPtr(tag.Type(), "base", base).updateDeclLineNumber(module, decl_index); + }, } } @@ -477,44 +472,11 @@ pub const File = struct { base.misc_errors.deinit(gpa); } switch (base.tag) { - .coff => { - if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(Coff, "base", base); - parent.deinit(); - }, - .elf => { - if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(Elf, "base", base); - parent.deinit(); - }, - .macho => { - if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(MachO, "base", base); - parent.deinit(); - }, - .c => { - const parent = @fieldParentPtr(C, "base", base); - parent.deinit(); - }, - .wasm => { - if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(Wasm, "base", base); - parent.deinit(); - }, - .spirv => { - if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(SpirV, "base", base); - parent.deinit(); - }, - .plan9 => { - if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(Plan9, "base", base); - parent.deinit(); - }, - .nvptx => { + .c => @fieldParentPtr(C, "base", base).deinit(), + + inline else => |tag| { if (build_options.only_c) unreachable; - const parent = @fieldParentPtr(NvPtx, "base", base); - parent.deinit(); + @fieldParentPtr(tag.Type(), "base", base).deinit(); }, } } @@ -619,51 +581,36 @@ pub const File = struct { return base.linkAsArchive(comp, prog_node); } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).flush(comp, prog_node), - .elf => return @fieldParentPtr(Elf, "base", base).flush(comp, prog_node), - .macho => return @fieldParentPtr(MachO, "base", base).flush(comp, prog_node), - .c => return @fieldParentPtr(C, "base", base).flush(comp, prog_node), - .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp, prog_node), - .spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp, prog_node), - .plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp, prog_node), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).flush(comp, prog_node), + inline else => |tag| { + return @fieldParentPtr(tag.Type(), "base", base).flush(comp, prog_node); + }, } } /// Commit pending changes and write headers. Works based on `effectiveOutputMode` /// rather than final output mode. pub fn flushModule(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void { - if (build_options.only_c) { - assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node); - } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).flushModule(comp, prog_node), - .elf => return @fieldParentPtr(Elf, "base", base).flushModule(comp, prog_node), - .macho => return @fieldParentPtr(MachO, "base", base).flushModule(comp, prog_node), - .c => return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node), - .wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp, prog_node), - .spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp, prog_node), - .plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp, prog_node), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).flushModule(comp, prog_node), + .c => { + return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node); + }, + inline else => |tag| { + if (build_options.only_c) unreachable; + return @fieldParentPtr(tag.Type(), "base", base).flushModule(comp, prog_node); + }, } } /// Called when a Decl is deleted from the Module. pub fn freeDecl(base: *File, decl_index: InternPool.DeclIndex) void { - if (build_options.only_c) { - assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).freeDecl(decl_index); - } switch (base.tag) { - .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl_index), - .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl_index), - .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl_index), - .c => @fieldParentPtr(C, "base", base).freeDecl(decl_index), - .wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl_index), - .spirv => @fieldParentPtr(SpirV, "base", base).freeDecl(decl_index), - .plan9 => @fieldParentPtr(Plan9, "base", base).freeDecl(decl_index), - .nvptx => @fieldParentPtr(NvPtx, "base", base).freeDecl(decl_index), + .c => { + @fieldParentPtr(C, "base", base).freeDecl(decl_index); + }, + inline else => |tag| { + if (build_options.only_c) unreachable; + @fieldParentPtr(tag.Type(), "base", base).freeDecl(decl_index); + }, } } @@ -682,19 +629,14 @@ pub const File = struct { exported: Module.Exported, exports: []const *Module.Export, ) UpdateExportsError!void { - if (build_options.only_c) { - assert(base.tag == .c); - return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports); - } switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).updateExports(module, exported, exports), - .elf => return @fieldParentPtr(Elf, "base", base).updateExports(module, exported, exports), - .macho => return @fieldParentPtr(MachO, "base", base).updateExports(module, exported, exports), - .c => return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports), - .wasm => return @fieldParentPtr(Wasm, "base", base).updateExports(module, exported, exports), - .spirv => return @fieldParentPtr(SpirV, "base", base).updateExports(module, exported, exports), - .plan9 => return @fieldParentPtr(Plan9, "base", base).updateExports(module, exported, exports), - .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateExports(module, exported, exports), + .c => { + return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports); + }, + inline else => |tag| { + if (build_options.only_c) unreachable; + return @fieldParentPtr(tag.Type(), "base", base).updateExports(module, exported, exports); + }, } } @@ -711,60 +653,64 @@ pub const File = struct { /// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate /// the block/atom. pub fn getDeclVAddr(base: *File, decl_index: InternPool.DeclIndex, reloc_info: RelocInfo) !u64 { - if (build_options.only_c) unreachable; + if (build_options.only_c) @compileError("unreachable"); switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl_index, reloc_info), - .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl_index, reloc_info), - .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl_index, reloc_info), - .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl_index, reloc_info), .c => unreachable, - .wasm => return @fieldParentPtr(Wasm, "base", base).getDeclVAddr(decl_index, reloc_info), .spirv => unreachable, .nvptx => unreachable, + inline else => |tag| { + return @fieldParentPtr(tag.Type(), "base", base).getDeclVAddr(decl_index, reloc_info); + }, } } pub const LowerResult = @import("codegen.zig").Result; - pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !LowerResult { - if (build_options.only_c) unreachable; + pub fn lowerAnonDecl( + base: *File, + decl_val: InternPool.Index, + decl_align: InternPool.Alignment, + src_loc: Module.SrcLoc, + ) !LowerResult { + if (build_options.only_c) @compileError("unreachable"); switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), - .elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), - .macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), - .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerAnonDecl(decl_val, src_loc), .c => unreachable, - .wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), .spirv => unreachable, .nvptx => unreachable, + inline else => |tag| { + return @fieldParentPtr(tag.Type(), "base", base).lowerAnonDecl(decl_val, decl_align, src_loc); + }, } } pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 { - if (build_options.only_c) unreachable; + if (build_options.only_c) @compileError("unreachable"); switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).getAnonDeclVAddr(decl_val, reloc_info), - .elf => return @fieldParentPtr(Elf, "base", base).getAnonDeclVAddr(decl_val, reloc_info), - .macho => return @fieldParentPtr(MachO, "base", base).getAnonDeclVAddr(decl_val, reloc_info), - .plan9 => return @fieldParentPtr(Plan9, "base", base).getAnonDeclVAddr(decl_val, reloc_info), .c => unreachable, - .wasm => return @fieldParentPtr(Wasm, "base", base).getAnonDeclVAddr(decl_val, reloc_info), .spirv => unreachable, .nvptx => unreachable, + inline else => |tag| { + return @fieldParentPtr(tag.Type(), "base", base).getAnonDeclVAddr(decl_val, reloc_info); + }, } } - pub fn deleteDeclExport(base: *File, decl_index: InternPool.DeclIndex, name: InternPool.NullTerminatedString) !void { - if (build_options.only_c) unreachable; + pub fn deleteDeclExport( + base: *File, + decl_index: InternPool.DeclIndex, + name: InternPool.NullTerminatedString, + ) !void { + if (build_options.only_c) @compileError("unreachable"); switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).deleteDeclExport(decl_index, name), - .elf => return @fieldParentPtr(Elf, "base", base).deleteDeclExport(decl_index, name), - .macho => return @fieldParentPtr(MachO, "base", base).deleteDeclExport(decl_index, name), - .plan9 => {}, - .c => {}, - .wasm => return @fieldParentPtr(Wasm, "base", base).deleteDeclExport(decl_index), - .spirv => {}, - .nvptx => {}, + .plan9, + .c, + .spirv, + .nvptx, + => {}, + + inline else => |tag| { + return @fieldParentPtr(tag.Type(), "base", base).deleteDeclExport(decl_index, name); + }, } } @@ -1049,7 +995,7 @@ pub const File = struct { base: File, arena: Allocator, opt_loc: ?Compilation.EmitLoc, - ) Allocator.Error!?[*:0]u8 { + ) Allocator.Error!?[*:0]const u8 { const loc = opt_loc orelse return null; const slice = if (loc.directory) |directory| try directory.joinZ(arena, &.{loc.basename}) @@ -1071,7 +1017,7 @@ pub const File = struct { sub_prog_node.context.refresh(); defer sub_prog_node.end(); - try llvm_object.emit(comp, .{ + try llvm_object.emit(.{ .pre_ir_path = comp.verbose_llvm_ir, .pre_bc_path = comp.verbose_llvm_bc, .bin_path = try base.resolveEmitLoc(arena, .{ @@ -1079,8 +1025,8 @@ pub const File = struct { .basename = base.intermediary_basename.?, }), .asm_path = try base.resolveEmitLoc(arena, comp.emit_asm), - .post_llvm_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir), - .post_llvm_bc_path = try base.resolveEmitLoc(arena, comp.emit_llvm_bc), + .post_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir), + .post_bc_path = try base.resolveEmitLoc(arena, comp.emit_llvm_bc), .is_debug = comp.root_mod.optimize_mode == .Debug, .is_small = comp.root_mod.optimize_mode == .ReleaseSmall, diff --git a/src/link/C.zig b/src/link/C.zig index 3592052cf8..669587bda9 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -135,6 +135,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = file, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index c02aecf2db..98c649ca84 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -14,9 +14,10 @@ nxcompat: bool, dynamicbase: bool, /// TODO this and minor_subsystem_version should be combined into one property and left as /// default or populated together. They should not be separate fields. -major_subsystem_version: u32, -minor_subsystem_version: u32, +major_subsystem_version: u16, +minor_subsystem_version: u16, lib_dirs: []const []const u8, +entry_addr: ?u32, ptr_width: PtrWidth, page_size: u32, @@ -238,7 +239,6 @@ pub fn open( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*Coff { - if (build_options.only_c) unreachable; const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .coff); @@ -390,6 +390,7 @@ pub fn createEmpty( .emit = emit, .stack_size = options.stack_size orelse 16777216, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), + .print_gc_sections = options.print_gc_sections, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, .disable_lld_caching = options.disable_lld_caching, @@ -422,6 +423,8 @@ pub fn createEmpty( .major_subsystem_version = options.major_subsystem_version orelse 6, .minor_subsystem_version = options.minor_subsystem_version orelse 0, .lib_dirs = options.lib_dirs, + .entry_addr = math.cast(u32, options.entry_addr orelse 0) orelse + return error.EntryAddressTooBig, }; const use_llvm = comp.config.use_llvm; @@ -2329,8 +2332,8 @@ fn writeHeader(self: *Coff) !void { .minor_operating_system_version = 0, .major_image_version = 0, .minor_image_version = 0, - .major_subsystem_version = self.major_subsystem_version, - .minor_subsystem_version = self.minor_subsystem_version, + .major_subsystem_version = @intCast(self.major_subsystem_version), + .minor_subsystem_version = @intCast(self.minor_subsystem_version), .win32_version_value = 0, .size_of_image = size_of_image, .size_of_headers = size_of_headers, @@ -2342,7 +2345,7 @@ fn writeHeader(self: *Coff) !void { .size_of_heap_reserve = default_size_of_heap_reserve, .size_of_heap_commit = default_size_of_heap_commit, .loader_flags = 0, - .number_of_rva_and_sizes = @as(u32, @intCast(self.data_directories.len)), + .number_of_rva_and_sizes = @intCast(self.data_directories.len), }; writer.writeAll(mem.asBytes(&opt_header)) catch unreachable; }, diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index ad9e18fa22..a94644a41e 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -21,7 +21,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const tracy = trace(@src()); defer tracy.end(); - var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); + const gpa = comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); @@ -30,7 +31,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (self.base.comp.module != null) blk: { + const module_obj_path: ?[]const u8 = if (comp.module != null) blk: { try self.flushModule(comp, prog_node); if (fs.path.dirname(full_out_path)) |dirname| { @@ -45,12 +46,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod sub_prog_node.context.refresh(); defer sub_prog_node.end(); - const is_lib = self.base.comp.config.output_mode == .Lib; - const is_dyn_lib = self.base.comp.config.link_mode == .Dynamic and is_lib; - const is_exe_or_dyn_lib = is_dyn_lib or self.base.comp.config.output_mode == .Exe; + const is_lib = comp.config.output_mode == .Lib; + const is_dyn_lib = comp.config.link_mode == .Dynamic and is_lib; + const is_exe_or_dyn_lib = is_dyn_lib or comp.config.output_mode == .Exe; const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib; - const target = self.base.comp.root_mod.resolved_target.result; - const optimize_mode = self.base.comp.root_mod.optimize_mode; + const target = comp.root_mod.resolved_target.result; + const optimize_mode = comp.root_mod.optimize_mode; // See link/Elf.zig for comments on how this mechanism works. const id_symlink_basename = "lld.id"; @@ -85,8 +86,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod man.hash.addListOfBytes(self.lib_dirs); man.hash.add(comp.skip_linker_dependencies); if (comp.config.link_libc) { - man.hash.add(self.base.comp.libc_installation != null); - if (self.base.comp.libc_installation) |libc_installation| { + man.hash.add(comp.libc_installation != null); + if (comp.libc_installation) |libc_installation| { man.hash.addBytes(libc_installation.crt_dir.?); if (target.abi == .msvc) { man.hash.addBytes(libc_installation.msvc_lib_dir.?); @@ -94,7 +95,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } } - try link.hashAddSystemLibs(&man, self.base.comp.system_libs); + try link.hashAddSystemLibs(&man, comp.system_libs); man.hash.addListOfBytes(self.base.force_undefined_symbols.keys()); man.hash.addOptional(self.subsystem); man.hash.add(comp.config.is_test); @@ -136,7 +137,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod }; } - if (self.base.comp.config.output_mode == .Obj) { + if (comp.config.output_mode == .Obj) { // LLD's COFF driver does not support the equivalent of `-r` so we 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. @@ -161,7 +162,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } } else { // Create an LLD command line and invoke it. - var argv = std.ArrayList([]const u8).init(self.base.allocator); + var argv = std.ArrayList([]const u8).init(gpa); defer argv.deinit(); // We will invoke ourselves as a child process to gain access to LLD. // This is necessary because LLD does not behave properly as a library - @@ -192,7 +193,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), } } - if (self.base.comp.config.output_mode == .Exe) { + if (comp.config.output_mode == .Exe) { try argv.append(try allocPrint(arena, "-STACK:{d}", .{self.base.stack_size})); } try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{self.image_base})); @@ -242,7 +243,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } if (comp.config.link_libc) { - if (self.base.comp.libc_installation) |libc_installation| { + if (comp.libc_installation) |libc_installation| { try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?})); if (target.abi == .msvc) { @@ -287,7 +288,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (self.subsystem) |explicit| break :blk explicit; switch (target.os.tag) { .windows => { - if (self.base.comp.module) |module| { + if (comp.module) |module| { if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib) break :blk null; if (module.stage1_flags.have_c_main or comp.config.is_test or @@ -415,13 +416,13 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib")); for (mingw.always_link_libs) |name| { - if (!self.base.comp.system_libs.contains(name)) { + if (!comp.system_libs.contains(name)) { const lib_basename = try allocPrint(arena, "{s}.lib", .{name}); try argv.append(try comp.get_libc_crt_file(arena, lib_basename)); } } } else { - const lib_str = switch (self.base.comp.config.link_mode) { + const lib_str = switch (comp.config.link_mode) { .Dynamic => "", .Static => "lib", }; @@ -429,7 +430,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod .Debug => "d", else => "", }; - switch (self.base.comp.config.link_mode) { + switch (comp.config.link_mode) { .Static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})), .Dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})), } @@ -448,7 +449,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod } else { try argv.append("-NODEFAULTLIB"); if (!is_lib and comp.config.entry == null) { - if (self.base.comp.module) |module| { + if (comp.module) |module| { if (module.stage1_flags.have_winmain_crt_startup) { try argv.append("-ENTRY:WinMainCRTStartup"); } else { @@ -485,8 +486,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path); } - try argv.ensureUnusedCapacity(self.base.comp.system_libs.count()); - for (self.base.comp.system_libs.keys()) |key| { + try argv.ensureUnusedCapacity(comp.system_libs.count()); + for (comp.system_libs.keys()) |key| { const lib_basename = try allocPrint(arena, "{s}.lib", .{key}); if (comp.crt_files.get(lib_basename)) |crt_file| { argv.appendAssumeCapacity(crt_file.full_object_path); @@ -512,7 +513,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod return error.DllImportLibraryNotFound; } - if (self.base.comp.verbose_link) { + if (comp.verbose_link) { // Skip over our own name so that the LLD linker name is the first argv item. Compilation.dump_argv(argv.items[1..]); } diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index faaf5100a4..cabaed1add 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1745,6 +1745,7 @@ pub fn freeDecl(self: *Dwarf, decl_index: InternPool.DeclIndex) void { } pub fn writeDbgAbbrev(self: *Dwarf) !void { + const gpa = self.allocator; // These are LEB encoded but since the values are all less than 127 // we can simply append these bytes. // zig fmt: off @@ -1887,7 +1888,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void { .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code; - try debug_abbrev.resize(wasm_file.base.allocator, needed_size); + try debug_abbrev.resize(gpa, needed_size); debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf; }, else => unreachable, @@ -2236,6 +2237,7 @@ fn writeDbgInfoNopsToArrayList( pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { const comp = self.bin_file.comp; + const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; const target_endian = target.cpu.arch.endian(); const ptr_width_bytes = self.ptrWidthBytes(); @@ -2301,7 +2303,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void { .wasm => { const wasm_file = self.bin_file.cast(File.Wasm).?; const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code; - try debug_ranges.resize(wasm_file.base.allocator, needed_size); + try debug_ranges.resize(gpa, needed_size); @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items); }, else => unreachable, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 47b4712b57..67478a59e8 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -230,7 +230,6 @@ pub fn open( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*Elf { - if (build_options.only_c) unreachable; const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .elf); @@ -380,6 +379,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os, .file = null, @@ -1175,7 +1175,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node const lib_name = flag["-l".len..]; success: { - if (!self.isStatic()) { + if (!self.base.isStatic()) { if (try self.accessLibPath(&test_path, &checked_paths, lc.crt_dir.?, lib_name, .Dynamic)) break :success; } @@ -1664,7 +1664,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append(p); } } else { - if (!self.isStatic()) { + if (!self.base.isStatic()) { if (target.dynamic_linker.get()) |path| { try argv.append("-dynamic-linker"); try argv.append(path); @@ -1742,7 +1742,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("now"); } - if (self.isStatic()) { + if (self.base.isStatic()) { try argv.append("-static"); } else if (self.base.isDynLib()) { try argv.append("-shared"); @@ -2023,7 +2023,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { // TODO I think technically we should re-use the mechanism used by the frontend here. // Maybe we should hoist search-strategy all the way here? for (self.lib_dirs) |lib_dir| { - if (!self.isStatic()) { + if (!self.base.isStatic()) { if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Dynamic)) break :success; } @@ -3598,7 +3598,7 @@ fn initSyntheticSections(self: *Elf) !void { // In this case, if we do generate .interp section and segment, we will get // a segfault in the dynamic linker trying to load a binary that is static // and doesn't contain .dynamic section. - if (self.isStatic() and !comp.config.pie) break :blk false; + if (self.base.isStatic() and !comp.config.pie) break :blk false; break :blk target.dynamic_linker.get() != null; }; if (needs_interp) { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 9f57dab283..a7b876f619 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -377,8 +377,8 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { } pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void { - const is_static = elf_file.isStatic(); - const is_dyn_lib = elf_file.isDynLib(); + const is_static = elf_file.base.isStatic(); + const is_dyn_lib = elf_file.base.isDynLib(); const file_ptr = self.file(elf_file).?; const rels = self.relocs(elf_file); var i: usize = 0; @@ -660,7 +660,7 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction { fn outputType(elf_file: *Elf) u2 { const comp = elf_file.base.comp; - assert(!elf_file.isRelocatable()); + assert(!elf_file.base.isRelocatable()); return switch (elf_file.base.comp.config.output_mode) { .Obj => unreachable, .Lib => 0, diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 35df214b18..b6dced258c 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -250,7 +250,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 { const name = blk: { const name = self.getString(shdr.sh_name); - if (elf_file.isRelocatable()) break :blk name; + if (elf_file.base.isRelocatable()) break :blk name; if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; const sh_name_prefixes: []const [:0]const u8 = &.{ ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", @@ -278,7 +278,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem }; const flags = blk: { var flags = shdr.sh_flags; - if (!elf_file.isRelocatable()) { + if (!elf_file.base.isRelocatable()) { flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); } break :blk switch (@"type") { @@ -520,7 +520,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { } const is_import = blk: { - if (!elf_file.isDynLib()) break :blk false; + if (!elf_file.base.isDynLib()) break :blk false; const vis = @as(elf.STV, @enumFromInt(esym.st_other)); if (vis == .HIDDEN) break :blk false; break :blk true; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index b6be4013ce..3a8a77de68 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -370,7 +370,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void { } const is_import = blk: { - if (!elf_file.isDynLib()) break :blk false; + if (!elf_file.base.isDynLib()) break :blk false; const vis = @as(elf.STV, @enumFromInt(esym.st_other)); if (vis == .HIDDEN) break :blk false; break :blk true; diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index e8500e8aa9..75401824ab 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -271,7 +271,7 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { } } - if (!elf_file.isRelocatable()) { + if (!elf_file.base.isRelocatable()) { offset += 4; // NULL terminator } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 9af563b047..35d5c85c2d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -155,6 +155,7 @@ frameworks: []const Framework, install_name: ?[]const u8, /// Path to entitlements file. entitlements: ?[]const u8, +compatibility_version: ?std.SemanticVersion, /// When adding a new field, remember to update `hashAddFrameworks`. pub const Framework = struct { @@ -185,7 +186,6 @@ pub fn open( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*MachO { - if (build_options.only_c) unreachable; const target = comp.root_mod.resolved_target.result; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; @@ -295,6 +295,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, @@ -315,6 +316,7 @@ pub fn createEmpty( .frameworks = options.frameworks, .install_name = options.install_name, .entitlements = options.entitlements, + .compatibility_version = options.compatibility_version, }; if (use_llvm and comp.module != null) { @@ -632,7 +634,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No }); { const platform = Platform.fromTarget(target); - const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(arena, comp); + const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(self); if (platform.isBuildVersionCompatible()) { try load_commands.writeBuildVersionLC(platform, sdk_version, lc_writer); } else if (platform.isVersionMinCompatible()) { @@ -2237,10 +2239,10 @@ fn allocateGlobal(self: *MachO) !u32 { return index; } -pub fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { - if (self.got_table.lookup.contains(target)) return; +pub fn addGotEntry(self: *MachO, reloc_target: SymbolWithLoc) !void { + if (self.got_table.lookup.contains(reloc_target)) return; const gpa = self.base.comp.gpa; - const got_index = try self.got_table.allocateEntry(gpa, target); + const got_index = try self.got_table.allocateEntry(gpa, reloc_target); if (self.got_section_index == null) { self.got_section_index = try self.initSection("__DATA_CONST", "__got", .{ .flags = macho.S_NON_LAZY_SYMBOL_POINTERS, @@ -2249,20 +2251,22 @@ pub fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void { if (self.mode == .incremental) { try self.writeOffsetTableEntry(got_index); self.got_table_count_dirty = true; - self.markRelocsDirtyByTarget(target); + self.markRelocsDirtyByTarget(reloc_target); } } -pub fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { - if (self.stub_table.lookup.contains(target)) return; - const gpa = self.base.comp.gpa; - const stub_index = try self.stub_table.allocateEntry(gpa, target); +pub fn addStubEntry(self: *MachO, reloc_target: SymbolWithLoc) !void { + if (self.stub_table.lookup.contains(reloc_target)) return; + const comp = self.base.comp; + const gpa = comp.gpa; + const cpu_arch = comp.root_mod.resolved_target.result.cpu.arch; + const stub_index = try self.stub_table.allocateEntry(gpa, reloc_target); if (self.stubs_section_index == null) { self.stubs_section_index = try self.initSection("__TEXT", "__stubs", .{ .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, - .reserved2 = stubs.stubSize(target.cpu.arch), + .reserved2 = stubs.stubSize(cpu_arch), }); self.stub_helper_section_index = try self.initSection("__TEXT", "__stub_helper", .{ .flags = macho.S_REGULAR | @@ -2276,14 +2280,14 @@ pub fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { if (self.mode == .incremental) { try self.writeStubTableEntry(stub_index); self.stub_table_count_dirty = true; - self.markRelocsDirtyByTarget(target); + self.markRelocsDirtyByTarget(reloc_target); } } -pub fn addTlvPtrEntry(self: *MachO, target: SymbolWithLoc) !void { - if (self.tlv_ptr_table.lookup.contains(target)) return; +pub fn addTlvPtrEntry(self: *MachO, reloc_target: SymbolWithLoc) !void { + if (self.tlv_ptr_table.lookup.contains(reloc_target)) return; const gpa = self.base.comp.gpa; - _ = try self.tlv_ptr_table.allocateEntry(gpa, target); + _ = try self.tlv_ptr_table.allocateEntry(gpa, reloc_target); if (self.tlv_ptr_section_index == null) { self.tlv_ptr_section_index = try self.initSection("__DATA", "__thread_ptrs", .{ .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS, diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 5185b93386..ad069b845e 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -342,19 +342,22 @@ pub const SplitIntoAtomsError = error{ }; pub fn splitIntoAtoms(self: *Object, macho_file: *MachO, object_id: u32) SplitIntoAtomsError!void { + const comp = macho_file.base.comp; + const gpa = comp.gpa; log.debug("splitting object({d}, {s}) into atoms", .{ object_id, self.name }); try self.splitRegularSections(macho_file, object_id); try self.parseEhFrameSection(macho_file, object_id); try self.parseUnwindInfo(macho_file, object_id); - try self.parseDataInCode(macho_file.base.allocator); + try self.parseDataInCode(gpa); } /// Splits input regular sections into Atoms. /// If the Object was compiled with `MH_SUBSECTIONS_VIA_SYMBOLS`, splits section /// into subsections where each subsection then represents an Atom. pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target = macho_file.base.comp.root_mod.resolved_target.result; const sections = self.getSourceSections(); @@ -555,7 +558,8 @@ fn createAtomFromSubsection( alignment: Alignment, out_sect_id: u8, ) !Atom.Index { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const atom_index = try macho_file.createAtom(sym_index, .{ .size = size, .alignment = alignment, @@ -671,7 +675,8 @@ fn parseEhFrameSection(self: *Object, macho_file: *MachO, object_id: u32) !void log.debug("parsing __TEXT,__eh_frame section", .{}); - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; if (macho_file.eh_frame_section_index == null) { macho_file.eh_frame_section_index = try macho_file.initSection("__TEXT", "__eh_frame", .{}); @@ -767,7 +772,8 @@ fn parseEhFrameSection(self: *Object, macho_file: *MachO, object_id: u32) !void } fn parseUnwindInfo(self: *Object, macho_file: *MachO, object_id: u32) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target = macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; const sect_id = self.unwind_info_sect_id orelse { diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index a92126c07e..02cf68e46e 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -1,7 +1,8 @@ //! An algorithm for dead stripping of unreferenced Atoms. pub fn gcAtoms(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig index 8223c830e0..4b51d09683 100644 --- a/src/link/MachO/eh_frame.zig +++ b/src/link/MachO/eh_frame.zig @@ -1,5 +1,6 @@ pub fn scanRelocs(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; for (macho_file.objects.items, 0..) |*object, object_id| { var cies = std.AutoHashMap(u32, void).init(gpa); @@ -37,7 +38,8 @@ pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) error const target = macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; var size: u32 = 0; for (macho_file.objects.items, 0..) |*object, object_id| { @@ -89,7 +91,8 @@ pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void { const target = macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; var eh_records = std.AutoArrayHashMap(u32, EhFrameRecord(true)).init(gpa); defer { diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 8bcf439354..e155a7a8ed 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -63,7 +63,7 @@ fn calcLCsSize(m: *MachO, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 { } // LC_RPATH { - var it = RpathIterator.init(gpa, m.rpath_list); + var it = RpathIterator.init(gpa, m.base.rpath_list); defer it.deinit(); while (try it.next()) |rpath| { sizeofcmds += calcInstallNameLen( @@ -189,17 +189,20 @@ fn writeDylibLC(ctx: WriteDylibLCCtx, lc_writer: anytype) !void { } } -pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, lc_writer: anytype) !void { - assert(options.output_mode == .Lib and options.link_mode == .Dynamic); - const emit = options.emit.?; - const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path}); - defer if (options.install_name == null) gpa.free(install_name); - const curr = options.version orelse std.SemanticVersion{ +pub fn writeDylibIdLC(macho_file: *MachO, lc_writer: anytype) !void { + const comp = macho_file.base.comp; + const gpa = comp.gpa; + assert(comp.config.output_mode == .Lib and comp.config.link_mode == .Dynamic); + const emit = macho_file.base.emit; + const install_name = macho_file.install_name orelse + try emit.directory.join(gpa, &.{emit.sub_path}); + defer if (macho_file.install_name == null) gpa.free(install_name); + const curr = comp.version orelse std.SemanticVersion{ .major = 1, .minor = 0, .patch = 0, }; - const compat = options.compatibility_version orelse std.SemanticVersion{ + const compat = macho_file.compatibility_version orelse std.SemanticVersion{ .major = 1, .minor = 0, .patch = 0, @@ -237,8 +240,11 @@ const RpathIterator = struct { } }; -pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, lc_writer: anytype) !void { - var it = RpathIterator.init(gpa, options.rpath_list); +pub fn writeRpathLCs(macho_file: *MachO, lc_writer: anytype) !void { + const comp = macho_file.base.comp; + const gpa = comp.gpa; + + var it = RpathIterator.init(gpa, macho_file.base.rpath_list); defer it.deinit(); while (try it.next()) |rpath| { @@ -467,13 +473,14 @@ pub inline fn appleVersionToSemanticVersion(version: u32) std.SemanticVersion { }; } -pub fn inferSdkVersion(gpa: Allocator, comp: *const Compilation) ?std.SemanticVersion { +pub fn inferSdkVersion(macho_file: *MachO) ?std.SemanticVersion { + const comp = macho_file.base.comp; + const gpa = comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const macho_file = comp.bin_file.cast(MachO).?; - const sdk_layout = macho_file.sdk_layout orelse return null; const sdk_dir = switch (sdk_layout) { .sdk => comp.sysroot.?, diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig index 774a8f7344..f080de7f80 100644 --- a/src/link/MachO/thunks.zig +++ b/src/link/MachO/thunks.zig @@ -68,7 +68,8 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void { const header = &macho_file.sections.items(.header)[sect_id]; if (header.size == 0) return; - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const first_atom_index = macho_file.sections.items(.first_atom_index)[sect_id].?; header.size = 0; @@ -245,7 +246,8 @@ fn scanRelocs( macho_file.getSymbol(target).n_value, }); - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target_sym = macho_file.getSymbol(target); const thunk = &macho_file.thunks.items[thunk_index]; diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index 06fede6e1b..f8715aa447 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -15,7 +15,7 @@ pub fn linkWithZld( const arena = arena_allocator.allocator(); const directory = emit.directory; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{emit.?.sub_path}); + const full_out_path = try directory.join(arena, &[_][]const u8{emit.sub_path}); const opt_zcu = macho_file.base.comp.module; // If there is no Zig code to compile, then we should skip flushing the output file because it @@ -71,14 +71,14 @@ pub fn linkWithZld( // We can skip hashing libc and libc++ components that we are in charge of building from Zig // installation sources because they are always a product of the compiler version + target information. man.hash.add(stack_size); - man.hash.addOptional(macho_file.pagezero_vmsize); - man.hash.addOptional(macho_file.headerpad_size); + man.hash.add(macho_file.pagezero_vmsize); + man.hash.add(macho_file.headerpad_size); man.hash.add(macho_file.headerpad_max_install_names); man.hash.add(macho_file.base.gc_sections); man.hash.add(macho_file.dead_strip_dylibs); man.hash.add(macho_file.base.comp.root_mod.strip); try MachO.hashAddFrameworks(&man, macho_file.frameworks); - man.hash.addListOfBytes(macho_file.rpath_list); + man.hash.addListOfBytes(macho_file.base.rpath_list); if (is_dyn_lib) { man.hash.addOptionalBytes(macho_file.install_name); man.hash.addOptional(comp.version); @@ -151,7 +151,7 @@ pub fn linkWithZld( try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); } } else { - const sub_path = emit.?.sub_path; + const sub_path = emit.sub_path; const old_file = macho_file.base.file; // TODO is this needed at all? defer macho_file.base.file = old_file; @@ -241,7 +241,7 @@ pub fn linkWithZld( try argv.append(@tagName(platform.os_tag)); try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version})); - const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(arena, comp); + const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(macho_file); if (sdk_version) |ver| { try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor })); } else { @@ -254,13 +254,13 @@ pub fn linkWithZld( try argv.append(syslibroot); } - for (macho_file.rpath_list) |rpath| { + for (macho_file.base.rpath_list) |rpath| { try argv.append("-rpath"); try argv.append(rpath); } try argv.appendSlice(&.{ - "-pagezero_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_size}), + "-pagezero_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_vmsize}), "-headerpad_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.headerpad_size}), }); @@ -558,7 +558,7 @@ pub fn linkWithZld( }); { const platform = Platform.fromTarget(target); - const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(arena, comp); + const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(macho_file); if (platform.isBuildVersionCompatible()) { try load_commands.writeBuildVersionLC(platform, sdk_version, lc_writer); } else { @@ -609,7 +609,8 @@ pub fn linkWithZld( } fn createSegments(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target = macho_file.base.comp.root_mod.resolved_target.result; const page_size = MachO.getPageSize(target.cpu.arch); const aligned_pagezero_vmsize = mem.alignBackward(u64, macho_file.pagezero_vmsize, page_size); @@ -683,7 +684,8 @@ fn createSegments(macho_file: *MachO) !void { } fn writeAtoms(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const slice = macho_file.sections.slice(); for (slice.items(.first_atom_index), 0..) |first_atom_index, sect_id| { @@ -758,7 +760,8 @@ fn writeDyldPrivateAtom(macho_file: *MachO) !void { fn writeThunks(macho_file: *MachO) !void { const target = macho_file.base.comp.root_mod.resolved_target.result; assert(target.cpu.arch == .aarch64); - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const sect_id = macho_file.text_section_index orelse return; const header = macho_file.sections.items(.header)[sect_id]; @@ -778,7 +781,8 @@ fn writeThunks(macho_file: *MachO) !void { } fn writePointerEntries(macho_file: *MachO, sect_id: u8, table: anytype) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const header = macho_file.sections.items(.header)[sect_id]; const capacity = math.cast(usize, header.size) orelse return error.Overflow; var buffer = try std.ArrayList(u8).initCapacity(gpa, capacity); @@ -792,7 +796,8 @@ fn writePointerEntries(macho_file: *MachO, sect_id: u8, table: anytype) !void { } fn writeStubs(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target = macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; const stubs_header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?]; @@ -815,7 +820,8 @@ fn writeStubs(macho_file: *MachO) !void { } fn writeStubHelpers(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target = macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; const stub_helper_header = macho_file.sections.items(.header)[macho_file.stub_helper_section_index.?]; @@ -859,7 +865,8 @@ fn writeStubHelpers(macho_file: *MachO) !void { } fn writeLaSymbolPtrs(macho_file: *MachO) !void { - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; const target = macho_file.base.comp.root_mod.resolved_target.result; const cpu_arch = target.cpu.arch; const la_symbol_ptr_header = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_section_index.?]; @@ -892,7 +899,8 @@ fn pruneAndSortSections(macho_file: *MachO) !void { } }; - const gpa = macho_file.base.allocator; + const comp = macho_file.base.comp; + const gpa = comp.gpa; var entries = try std.ArrayList(Entry).initCapacity(gpa, macho_file.sections.slice().len); defer entries.deinit(); diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index b59a527c5a..2025372323 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -31,8 +31,6 @@ pub fn createEmpty( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*NvPtx { - if (build_options.only_c) unreachable; - const target = comp.root_mod.resolved_target.result; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; @@ -55,6 +53,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse false, + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 3fe6aee009..ceabfe2864 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -318,6 +318,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, @@ -1314,8 +1315,6 @@ pub fn open( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*Plan9 { - if (build_options.only_c) unreachable; - const target = comp.root_mod.resolved_target.result; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; @@ -1525,7 +1524,13 @@ pub fn getDeclVAddr( return undefined; } -pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { +pub fn lowerAnonDecl( + self: *Plan9, + decl_val: InternPool.Index, + explicit_alignment: InternPool.Alignment, + src_loc: Module.SrcLoc, +) !codegen.Result { + _ = explicit_alignment; // This is basically the same as lowerUnnamedConst. // example: // const ty = mod.intern_pool.typeOf(decl_val).toType(); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 853d97b014..5124ff19f6 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -24,7 +24,6 @@ const SpirV = @This(); const std = @import("std"); const Allocator = std.mem.Allocator; -const ArenaAllocator = std.heap.ArenaAllocator; const assert = std.debug.assert; const log = std.log.scoped(.link); @@ -65,6 +64,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse false, + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, @@ -98,8 +98,6 @@ pub fn open( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*SpirV { - if (build_options.only_c) unreachable; - const target = comp.root_mod.resolved_target.result; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; @@ -194,7 +192,9 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No const spv = &self.object.spv; + const gpa = comp.gpa; const target = comp.getTarget(); + try writeCapabilities(spv, target); try writeMemoryModel(spv, target); @@ -214,11 +214,11 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No // name if it contains no strange characters is nice for debugging. URI encoding fits the bill. // We're using : as separator, which is a reserved character. - const escaped_name = try std.Uri.escapeString(self.base.allocator, name); - defer self.base.allocator.free(escaped_name); + const escaped_name = try std.Uri.escapeString(gpa, name); + defer gpa.free(escaped_name); try error_info.writer().print(":{s}", .{escaped_name}); } - try spv.sections.debug_strings.emit(spv.gpa, .OpSourceExtension, .{ + try spv.sections.debug_strings.emit(gpa, .OpSourceExtension, .{ .extension = error_info.items, }); @@ -226,6 +226,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No } fn writeCapabilities(spv: *SpvModule, target: std.Target) !void { + const gpa = spv.gpa; // TODO: Integrate with a hypothetical feature system const caps: []const spec.Capability = switch (target.os.tag) { .opencl => &.{ .Kernel, .Addresses, .Int8, .Int16, .Int64, .Float64, .Float16, .GenericPointer }, @@ -235,13 +236,15 @@ fn writeCapabilities(spv: *SpvModule, target: std.Target) !void { }; for (caps) |cap| { - try spv.sections.capabilities.emit(spv.gpa, .OpCapability, .{ + try spv.sections.capabilities.emit(gpa, .OpCapability, .{ .capability = cap, }); } } fn writeMemoryModel(spv: *SpvModule, target: std.Target) !void { + const gpa = spv.gpa; + const addressing_model = switch (target.os.tag) { .opencl => switch (target.cpu.arch) { .spirv32 => spec.AddressingModel.Physical32, @@ -260,7 +263,7 @@ fn writeMemoryModel(spv: *SpvModule, target: std.Target) !void { }; // TODO: Put this in a proper section. - try spv.sections.extensions.emit(spv.gpa, .OpMemoryModel, .{ + try spv.sections.extensions.emit(gpa, .OpMemoryModel, .{ .addressing_model = addressing_model, .memory_model = memory_model, }); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 874cc2d9b3..7ec9506751 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -378,7 +378,6 @@ pub fn open( emit: Compilation.Emit, options: link.File.OpenOptions, ) !*Wasm { - if (build_options.only_c) unreachable; const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .wasm); @@ -549,6 +548,7 @@ pub fn createEmpty( .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (output_mode != .Obj), + .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, @@ -1893,7 +1893,12 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin return target_symbol_index; } -pub fn deleteDeclExport(wasm: *Wasm, decl_index: InternPool.DeclIndex) void { +pub fn deleteDeclExport( + wasm: *Wasm, + decl_index: InternPool.DeclIndex, + name: InternPool.NullTerminatedString, +) void { + _ = name; if (wasm.llvm_object) |_| return; const atom_index = wasm.decls.get(decl_index) orelse return; const sym_index = wasm.getAtom(atom_index).sym_index; diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 610c534c88..f0c21b8c89 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -883,6 +883,8 @@ fn assertEnd(reader: anytype) !void { /// Parses an object file into atoms, for code and data sections pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32, wasm: *Wasm) !Atom.Index { + const comp = wasm.base.comp; + const gpa = comp.gpa; const symbol = &object.symtable[symbol_index]; const relocatable_data: RelocatableData = switch (symbol.tag) { .function => object.relocatable_data.get(.code).?[symbol.index - object.importedCountByKind(.function)], @@ -900,7 +902,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32 }; const final_index = try wasm.getMatchingSegment(object_index, symbol_index); const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len)); - const atom = try wasm.managed_atoms.addOne(wasm.base.allocator); + const atom = try wasm.managed_atoms.addOne(gpa); atom.* = Atom.empty; try wasm.appendAtomAtIndex(final_index, atom_index); @@ -910,7 +912,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32 atom.alignment = relocatable_data.getAlignment(object); atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]); atom.original_offset = relocatable_data.offset; - try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom_index); + try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index); const segment: *Wasm.Segment = &wasm.segments.items[final_index]; if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned segment.alignment = segment.alignment.max(atom.alignment); @@ -927,7 +929,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32 .R_WASM_TABLE_INDEX_SLEB, .R_WASM_TABLE_INDEX_SLEB64, => { - try wasm.function_table.put(wasm.base.allocator, .{ + try wasm.function_table.put(gpa, .{ .file = object_index, .index = reloc.index, }, 0); @@ -938,7 +940,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32 const sym = object.symtable[reloc.index]; if (sym.tag != .global) { try wasm.got_symbols.append( - wasm.base.allocator, + gpa, .{ .file = object_index, .index = reloc.index }, ); } diff --git a/src/main.zig b/src/main.zig index 26e1d79a7b..f412658a67 100644 --- a/src/main.zig +++ b/src/main.zig @@ -874,8 +874,8 @@ fn buildOutputType( var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena); var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no; var subsystem: ?std.Target.SubSystem = null; - var major_subsystem_version: ?u32 = null; - var minor_subsystem_version: ?u32 = null; + var major_subsystem_version: ?u16 = null; + var minor_subsystem_version: ?u16 = null; var enable_link_snapshots: bool = false; var debug_incremental: bool = false; var install_name: ?[]const u8 = null; @@ -2321,21 +2321,17 @@ fn buildOutputType( _ = linker_args_it.nextOrFatal(); } else if (mem.eql(u8, arg, "--major-subsystem-version")) { const major = linker_args_it.nextOrFatal(); - major_subsystem_version = std.fmt.parseUnsigned( - u32, - major, - 10, - ) catch |err| { - fatal("unable to parse major subsystem version '{s}': {s}", .{ major, @errorName(err) }); + major_subsystem_version = std.fmt.parseUnsigned(u16, major, 10) catch |err| { + fatal("unable to parse major subsystem version '{s}': {s}", .{ + major, @errorName(err), + }); }; } else if (mem.eql(u8, arg, "--minor-subsystem-version")) { const minor = linker_args_it.nextOrFatal(); - minor_subsystem_version = std.fmt.parseUnsigned( - u32, - minor, - 10, - ) catch |err| { - fatal("unable to parse minor subsystem version '{s}': {s}", .{ minor, @errorName(err) }); + minor_subsystem_version = std.fmt.parseUnsigned(u16, minor, 10) catch |err| { + fatal("unable to parse minor subsystem version '{s}': {s}", .{ + minor, @errorName(err), + }); }; } else if (mem.eql(u8, arg, "-framework")) { try frameworks.put(arena, linker_args_it.nextOrFatal(), .{}); -- cgit v1.2.3 From 0be97b5ae3d32ca9cd7fbb68d5972538b48d8c76 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Dec 2023 01:49:57 -0700 Subject: fix population of builtin.zig not making the parent dir --- src/Builtin.zig | 2 +- src/Compilation.zig | 9 ++++++++- src/Package.zig | 10 ++++++++++ src/Package/Module.zig | 2 +- src/codegen/llvm.zig | 12 ++++++++++-- 5 files changed, 30 insertions(+), 5 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/Builtin.zig b/src/Builtin.zig index 4c8038019c..f80f466302 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -276,7 +276,7 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void { } fn writeFile(file: *File, mod: *Module) !void { - var af = try mod.root.atomicFile(mod.root_src_path, .{}); + var af = try mod.root.atomicFile(mod.root_src_path, .{ .make_path = true }); defer af.deinit(); try af.file.writeAll(file.source); try af.finish(); diff --git a/src/Compilation.zig b/src/Compilation.zig index fb6e5a44b0..20e2d1ce53 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1119,6 +1119,11 @@ fn addModuleTableToCacheHash( var i: usize = 0; while (i < seen_table.count()) : (i += 1) { const mod = seen_table.keys()[i]; + if (mod.isBuiltin()) { + // Skip builtin.zig; it is useless as an input, and we don't want to + // have to write it before checking for a cache hit. + continue; + } cache_helpers.addResolvedTarget(hash, mod.resolved_target); hash.add(mod.optimize_mode); @@ -1133,6 +1138,8 @@ fn addModuleTableToCacheHash( hash.add(mod.red_zone); hash.add(mod.sanitize_c); hash.add(mod.sanitize_thread); + hash.add(mod.unwind_tables); + hash.add(mod.structured_cfg); switch (hash_type) { .path_bytes => { @@ -2371,7 +2378,6 @@ pub const link_hash_implementation_version = 10; fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { const gpa = comp.gpa; - const target = comp.getTarget(); var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); @@ -2432,6 +2438,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.include_compiler_rt); if (comp.config.link_libc) { man.hash.add(comp.libc_installation != null); + const target = comp.root_mod.resolved_target.result; if (comp.libc_installation) |libc_installation| { man.hash.addOptionalBytes(libc_installation.crt_dir); if (target.abi == .msvc) { diff --git a/src/Package.zig b/src/Package.zig index ab06ca9852..373b46e495 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -108,6 +108,16 @@ pub const Path = struct { return p.root_dir.handle.access(joined_path, flags); } + pub fn makePath(p: Path, sub_path: []const u8) !void { + var buf: [fs.MAX_PATH_BYTES]u8 = undefined; + const joined_path = if (p.sub_path.len == 0) sub_path else p: { + break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{ + p.sub_path, sub_path, + }) catch return error.NameTooLong; + }; + return p.root_dir.handle.makePath(joined_path); + } + pub fn format( self: Path, comptime fmt_string: []const u8, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 4ce0f0a856..2d54c9296c 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -40,7 +40,7 @@ builtin_file: ?*File, pub const Deps = std.StringArrayHashMapUnmanaged(*Module); pub fn isBuiltin(m: Module) bool { - return m.file != null; + return m.builtin_file != null; } pub const Tree = struct { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3a53bddcb8..91c4faffcc 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -898,14 +898,22 @@ pub const Object = struct { // very location dependent. // TODO: the only concern I have with this is WASI as either host or target, should // we leave the paths as relative then? + // TODO: This is totally wrong. In dwarf, paths are encoded as relative to + // a particular directory, and then the directory path is specified elsewhere. + // In the compiler frontend we have it stored correctly in this + // way already, but here we throw all that sweet information + // into the garbage can by converting into absolute paths. What + // a terrible tragedy. const compile_unit_dir_z = blk: { if (comp.module) |zcu| m: { const d = try zcu.root_mod.root.joinStringZ(arena, ""); if (d.len == 0) break :m; if (std.fs.path.isAbsolute(d)) break :blk d; - break :blk std.fs.realpathAlloc(arena, d) catch d; + const realpath = std.fs.realpathAlloc(arena, d) catch break :blk d; + break :blk try arena.dupeZ(u8, realpath); } - break :blk try std.process.getCwdAlloc(arena); + const cwd = try std.process.getCwdAlloc(arena); + break :blk try arena.dupeZ(u8, cwd); }; builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit( -- cgit v1.2.3