diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ead51a35e71..6078cad58636 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -535,7 +535,6 @@ set(ZIG_STAGE2_SOURCES src/Sema.zig src/Sema/bitcast.zig src/Sema/comptime_ptr_access.zig - src/ThreadSafeQueue.zig src/Type.zig src/Value.zig src/Zcu.zig @@ -624,6 +623,7 @@ set(ZIG_STAGE2_SOURCES src/link/Elf/synthetic_sections.zig src/link/Goff.zig src/link/LdScript.zig + src/link/Lld.zig src/link/MachO.zig src/link/MachO/Archive.zig src/link/MachO/Atom.zig @@ -652,6 +652,7 @@ set(ZIG_STAGE2_SOURCES src/link/MachO/uuid.zig src/link/Plan9.zig src/link/Plan9/aout.zig + src/link/Queue.zig src/link/SpirV.zig src/link/SpirV/BinaryModule.zig src/link/SpirV/deduplicate.zig diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index dd8c4158ce17..924dc18f91be 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1834,47 +1834,16 @@ fn make(step: *Step, options: Step.MakeOptions) !void { lp.path = b.fmt("{}", .{output_dir}); } - // -femit-bin[=path] (default) Output machine code - if (compile.generated_bin) |bin| { - bin.path = output_dir.joinString(b.allocator, compile.out_filename) catch @panic("OOM"); - } - - const sep = std.fs.path.sep_str; - - // output PDB if someone requested it - if (compile.generated_pdb) |pdb| { - pdb.path = b.fmt("{}" ++ sep ++ "{s}.pdb", .{ output_dir, compile.name }); - } - - // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL - if (compile.generated_implib) |implib| { - implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name }); - } - - // -femit-h[=path] Generate a C header file (.h) - if (compile.generated_h) |lp| { - lp.path = b.fmt("{}" ++ sep ++ "{s}.h", .{ output_dir, compile.name }); - } - - // -femit-docs[=path] Create a docs/ dir with html documentation - if (compile.generated_docs) |generated_docs| { - generated_docs.path = output_dir.joinString(b.allocator, "docs") catch @panic("OOM"); - } - - // -femit-asm[=path] Output .s (assembly code) - if (compile.generated_asm) |lp| { - lp.path = b.fmt("{}" ++ sep ++ "{s}.s", .{ output_dir, compile.name }); - } - - // -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions) - if (compile.generated_llvm_ir) |lp| { - lp.path = b.fmt("{}" ++ sep ++ "{s}.ll", .{ output_dir, compile.name }); - } - - // -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions) - if (compile.generated_llvm_bc) |lp| { - lp.path = b.fmt("{}" ++ sep ++ "{s}.bc", .{ output_dir, compile.name }); - } + // zig fmt: off + if (compile.generated_bin) |lp| lp.path = compile.outputPath(output_dir, .bin); + if (compile.generated_pdb) |lp| lp.path = compile.outputPath(output_dir, .pdb); + if (compile.generated_implib) |lp| lp.path = compile.outputPath(output_dir, .implib); + if (compile.generated_h) |lp| lp.path = compile.outputPath(output_dir, .h); + if (compile.generated_docs) |lp| lp.path = compile.outputPath(output_dir, .docs); + if (compile.generated_asm) |lp| lp.path = compile.outputPath(output_dir, .@"asm"); + if (compile.generated_llvm_ir) |lp| lp.path = compile.outputPath(output_dir, .llvm_ir); + if (compile.generated_llvm_bc) |lp| lp.path = compile.outputPath(output_dir, .llvm_bc); + // zig fmt: on } if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic and @@ -1888,6 +1857,21 @@ fn make(step: *Step, options: Step.MakeOptions) !void { ); } } +fn outputPath(c: *Compile, out_dir: std.Build.Cache.Path, ea: std.zig.EmitArtifact) []const u8 { + const arena = c.step.owner.graph.arena; + const name = ea.cacheName(arena, .{ + .root_name = c.name, + .target = c.root_module.resolved_target.?.result, + .output_mode = switch (c.kind) { + .lib => .Lib, + .obj, .test_obj => .Obj, + .exe, .@"test" => .Exe, + }, + .link_mode = c.linkage, + .version = c.version, + }) catch @panic("OOM"); + return out_dir.joinString(arena, name) catch @panic("OOM"); +} pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) !Path { const gpa = c.step.owner.allocator; diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index d9ff03a3fe1b..030f3f0a28b7 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -234,6 +234,28 @@ pub const Node = struct { _ = @atomicRmw(u32, &storage.completed_count, .Add, 1, .monotonic); } + /// Thread-safe. Bytes after '0' in `new_name` are ignored. + pub fn setName(n: Node, new_name: []const u8) void { + const index = n.index.unwrap() orelse return; + const storage = storageByIndex(index); + + const name_len = @min(max_name_len, std.mem.indexOfScalar(u8, new_name, 0) orelse new_name.len); + + copyAtomicStore(storage.name[0..name_len], new_name[0..name_len]); + if (name_len < storage.name.len) + @atomicStore(u8, &storage.name[name_len], 0, .monotonic); + } + + /// Gets the name of this `Node`. + /// A pointer to this array can later be passed to `setName` to restore the name. + pub fn getName(n: Node) [max_name_len]u8 { + var dest: [max_name_len]u8 align(@alignOf(usize)) = undefined; + if (n.index.unwrap()) |index| { + copyAtomicLoad(&dest, &storageByIndex(index).name); + } + return dest; + } + /// Thread-safe. pub fn setCompletedItems(n: Node, completed_items: usize) void { const index = n.index.unwrap() orelse return; diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index 3243f1b1bd5f..e8778fc9c1c7 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -212,8 +212,8 @@ pub fn DebugAllocator(comptime config: Config) type { DummyMutex{}; const DummyMutex = struct { - inline fn lock(_: *DummyMutex) void {} - inline fn unlock(_: *DummyMutex) void {} + inline fn lock(_: DummyMutex) void {} + inline fn unlock(_: DummyMutex) void {} }; const stack_n = config.stack_trace_frames; diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 341ca6931efc..279a15079981 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -135,6 +135,22 @@ pub fn MultiArrayList(comptime T: type) type { self.* = undefined; } + /// Returns a `Slice` representing a range of elements in `s`, analagous to `arr[off..len]`. + /// It is illegal to call `deinit` or `toMultiArrayList` on the returned `Slice`. + /// Asserts that `off + len <= s.len`. + pub fn subslice(s: Slice, off: usize, len: usize) Slice { + assert(off + len <= s.len); + var ptrs: [fields.len][*]u8 = undefined; + inline for (s.ptrs, &ptrs, fields) |in, *out, field| { + out.* = in + (off * @sizeOf(field.type)); + } + return .{ + .ptrs = ptrs, + .len = len, + .capacity = len, + }; + } + /// This function is used in the debugger pretty formatters in tools/ to fetch the /// child field order and entry type to facilitate fancy debug printing for this type. fn dbHelper(self: *Slice, child: *Elem, field: *Field, entry: *Entry) void { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index a946fe5e8bc7..21f129676623 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -884,6 +884,35 @@ pub const SimpleComptimeReason = enum(u32) { } }; +/// Every kind of artifact which the compiler can emit. +pub const EmitArtifact = enum { + bin, + @"asm", + implib, + llvm_ir, + llvm_bc, + docs, + pdb, + h, + + /// If using `Server` to communicate with the compiler, it will place requested artifacts in + /// paths under the output directory, where those paths are named according to this function. + /// Returned string is allocated with `gpa` and owned by the caller. + pub fn cacheName(ea: EmitArtifact, gpa: Allocator, opts: BinNameOptions) Allocator.Error![]const u8 { + const suffix: []const u8 = switch (ea) { + .bin => return binNameAlloc(gpa, opts), + .@"asm" => ".s", + .implib => ".lib", + .llvm_ir => ".ll", + .llvm_bc => ".bc", + .docs => "-docs", + .pdb => ".pdb", + .h => ".h", + }; + return std.fmt.allocPrint(gpa, "{s}{s}", .{ opts.root_name, suffix }); + } +}; + test { _ = Ast; _ = AstRlAnnotate; diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 440b4df9fc54..17643e6f1e7c 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -4861,6 +4861,15 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index { } } +pub fn getParamName(zir: Zir, param_inst: Inst.Index) ?NullTerminatedString { + const inst = zir.instructions.get(@intFromEnum(param_inst)); + return switch (inst.tag) { + .param, .param_comptime => zir.extraData(Inst.Param, inst.data.pl_tok.payload_index).data.name, + .param_anytype, .param_anytype_comptime => inst.data.str_tok.start, + else => null, + }; +} + pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { const tags = zir.instructions.items(.tag); const datas = zir.instructions.items(.data); diff --git a/src/Air.zig b/src/Air.zig index 4810766e710d..74f4c5742486 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -1153,9 +1153,7 @@ pub const Inst = struct { ty: Type, arg: struct { ty: Ref, - /// Index into `extra` of a null-terminated string representing the parameter name. - /// This is `.none` if debug info is stripped. - name: NullTerminatedString, + zir_param_index: u32, }, ty_op: struct { ty: Ref, diff --git a/src/Air/print.zig b/src/Air/print.zig index 343c640a6312..7f5f396cae14 100644 --- a/src/Air/print.zig +++ b/src/Air/print.zig @@ -363,10 +363,7 @@ const Writer = struct { fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg; try w.writeType(s, arg.ty.toType()); - switch (arg.name) { - .none => {}, - _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}), - } + try s.print(", {d}", .{arg.zir_param_index}); } fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { diff --git a/src/Compilation.zig b/src/Compilation.zig index 81d150b03fea..065b717931cd 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -43,7 +43,6 @@ const Air = @import("Air.zig"); const Builtin = @import("Builtin.zig"); const LlvmObject = @import("codegen/llvm.zig").Object; const dev = @import("dev.zig"); -const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue; pub const Config = @import("Compilation/Config.zig"); @@ -56,8 +55,7 @@ gpa: Allocator, arena: Allocator, /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`. zcu: ?*Zcu, -/// Contains different state depending on whether the Compilation uses -/// incremental or whole cache mode. +/// Contains different state depending on the `CacheMode` used by this `Compilation`. cache_use: CacheUse, /// All compilations have a root module because this is where some important /// settings are stored, such as target and optimization mode. This module @@ -68,17 +66,13 @@ root_mod: *Package.Module, config: Config, /// 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. +/// In `CacheMode.whole`, this is null except for during the body of `update`. +/// In `CacheMode.none` and `CacheMode.incremental`, this is long-lived. +/// Regardless of cache mode, 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) sysroot: ?[]const u8, -/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used. -implib_emit: ?Cache.Path, -/// This is non-null when `-femit-docs` is provided. -docs_emit: ?Cache.Path, root_name: [:0]const u8, compiler_rt_strat: RtStrat, ubsan_rt_strat: RtStrat, @@ -113,17 +107,7 @@ win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMa } = .{}, link_diags: link.Diags, -link_task_queue: ThreadSafeQueue(link.Task) = .empty, -/// Ensure only 1 simultaneous call to `flushTaskQueue`. -link_task_queue_safety: std.debug.SafetyLock = .{}, -/// If any tasks are queued up that depend on prelink being finished, they are moved -/// here until prelink finishes. -link_task_queue_postponed: std.ArrayListUnmanaged(link.Task) = .empty, -/// Initialized with how many link input tasks are expected. After this reaches zero -/// the linker will begin the prelink phase. -/// Initialized in the Compilation main thread before the pipeline; modified only in -/// the linker task thread. -remaining_prelink_tasks: u32, +link_task_queue: link.Queue = .empty, /// Set of work that can be represented by only flags to determine whether the /// work is queued or not. @@ -270,12 +254,8 @@ mutex: if (builtin.single_threaded) struct { test_filters: []const []const u8, test_name_prefix: ?[]const u8, -emit_asm: ?EmitLoc, -emit_llvm_ir: ?EmitLoc, -emit_llvm_bc: ?EmitLoc, - link_task_wait_group: WaitGroup = .{}, -work_queue_progress_node: std.Progress.Node = .none, +link_prog_node: std.Progress.Node = std.Progress.Node.none, llvm_opt_bisect_limit: c_int, @@ -285,6 +265,31 @@ file_system_inputs: ?*std.ArrayListUnmanaged(u8), /// This digest will be known after update() is called. digest: ?[Cache.bin_digest_len]u8 = null, +/// Non-`null` iff we are emitting a binary. +/// Does not change for the lifetime of this `Compilation`. +/// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. +emit_bin: ?[]const u8, +/// Non-`null` iff we are emitting assembly. +/// Does not change for the lifetime of this `Compilation`. +/// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. +emit_asm: ?[]const u8, +/// Non-`null` iff we are emitting an implib. +/// Does not change for the lifetime of this `Compilation`. +/// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. +emit_implib: ?[]const u8, +/// Non-`null` iff we are emitting LLVM IR. +/// Does not change for the lifetime of this `Compilation`. +/// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. +emit_llvm_ir: ?[]const u8, +/// Non-`null` iff we are emitting LLVM bitcode. +/// Does not change for the lifetime of this `Compilation`. +/// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. +emit_llvm_bc: ?[]const u8, +/// Non-`null` iff we are emitting documentation. +/// Does not change for the lifetime of this `Compilation`. +/// Cwd-relative if `cache_use == .none`. Otherwise, relative to our subdirectory in the cache. +emit_docs: ?[]const u8, + const QueuedJobs = struct { compiler_rt_lib: bool = false, compiler_rt_obj: bool = false, @@ -785,13 +790,6 @@ pub const CrtFile = struct { lock: Cache.Lock, full_object_path: Cache.Path, - pub fn isObject(cf: CrtFile) bool { - return switch (classifyFileExt(cf.full_object_path.sub_path)) { - .object => true, - else => false, - }; - } - pub fn deinit(self: *CrtFile, gpa: Allocator) void { self.lock.release(); gpa.free(self.full_object_path.sub_path); @@ -846,19 +844,34 @@ pub const RcIncludes = enum { }; const Job = union(enum) { - /// Corresponds to the task in `link.Task`. - /// Only needed for backends that haven't yet been updated to not race against Sema. - codegen_nav: InternPool.Nav.Index, - /// Corresponds to the task in `link.Task`. - /// Only needed for backends that haven't yet been updated to not race against Sema. - codegen_func: link.Task.CodegenFunc, - /// Corresponds to the task in `link.Task`. - /// Only needed for backends that haven't yet been updated to not race against Sema. - codegen_type: InternPool.Index, + /// Given the generated AIR for a function, put it onto the code generation queue. + /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that + /// all types are resolved before the linker task is queued. + /// If the backend does not support `Zcu.Feature.separate_thread`, codegen and linking happen immediately. + /// Before queueing this `Job`, increase the estimated total item count for both + /// `comp.zcu.?.codegen_prog_node` and `comp.link_prog_node`. + codegen_func: struct { + func: InternPool.Index, + /// The AIR emitted from analyzing `func`; owned by this `Job` in `gpa`. + air: Air, + }, + /// Queue a `link.ZcuTask` to emit this non-function `Nav` into the output binary. + /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that + /// all types are resolved before the linker task is queued. + /// If the backend does not support `Zcu.Feature.separate_thread`, the task is run immediately. + /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`. + link_nav: InternPool.Nav.Index, + /// Queue a `link.ZcuTask` to emit debug information for this container type. + /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that + /// all types are resolved before the linker task is queued. + /// If the backend does not support `Zcu.Feature.separate_thread`, the task is run immediately. + /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`. + link_type: InternPool.Index, + /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`. update_line_number: InternPool.TrackedInst.Index, /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed. /// This may be its first time being analyzed, or it may be outdated. - /// If the unit is a function, a `codegen_func` job will then be queued. + /// If the unit is a test function, an `analyze_func` job will then be queued. analyze_comptime_unit: InternPool.AnalUnit, /// This function must be semantically analyzed. /// This may be its first time being analyzed, or it may be outdated. @@ -1322,14 +1335,6 @@ pub const MiscError = struct { } }; -pub const EmitLoc = struct { - /// If this is `null` it means the file will be output to the cache directory. - /// When provided, both the open file handle and the path name must outlive the `Compilation`. - directory: ?Cache.Directory, - /// This may not have sub-directories in it. - basename: []const u8, -}; - pub const cache_helpers = struct { pub fn addModule(hh: *Cache.HashHelper, mod: *const Package.Module) void { addResolvedTarget(hh, mod.resolved_target); @@ -1369,15 +1374,6 @@ pub const cache_helpers = struct { hh.add(resolved_target.is_explicit_dynamic_linker); } - pub fn addEmitLoc(hh: *Cache.HashHelper, emit_loc: EmitLoc) void { - hh.addBytes(emit_loc.basename); - } - - pub fn addOptionalEmitLoc(hh: *Cache.HashHelper, optional_emit_loc: ?EmitLoc) void { - hh.add(optional_emit_loc != null); - addEmitLoc(hh, optional_emit_loc orelse return); - } - pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?Config.DebugFormat) void { hh.add(x != null); addDebugFormat(hh, x orelse return); @@ -1424,7 +1420,38 @@ pub const ClangPreprocessorMode = enum { pub const Framework = link.File.MachO.Framework; pub const SystemLib = link.SystemLib; -pub const CacheMode = enum { incremental, whole }; +pub const CacheMode = enum { + /// The results of this compilation are not cached. The compilation is always performed, and the + /// results are emitted directly to their output locations. Temporary files will be placed in a + /// temporary directory in the cache, but deleted after the compilation is done. + /// + /// This mode is typically used for direct CLI invocations like `zig build-exe`, because such + /// processes are typically low-level usages which would not make efficient use of the cache. + none, + /// The compilation is cached based only on the options given when creating the `Compilation`. + /// In particular, Zig source file contents are not included in the cache manifest. This mode + /// allows incremental compilation, because the old cached compilation state can be restored + /// and the old binary patched up with the changes. All files, including temporary files, are + /// stored in the cache directory like '/o//'. Temporary files are not deleted. + /// + /// At the time of writing, incremental compilation is only supported with the `-fincremental` + /// command line flag, so this mode is rarely used. However, it is required in order to use + /// incremental compilation. + incremental, + /// The compilation is cached based on the `Compilation` options and every input, including Zig + /// source files, linker inputs, and `@embedFile` targets. If any of them change, we will see a + /// cache miss, and the entire compilation will be re-run. On a cache miss, we initially write + /// all output files to a directory under '/tmp/', because we don't know the final + /// manifest digest until the update is almost done. Once we can compute the final digest, this + /// directory is moved to '/o//'. Temporary files are not deleted. + /// + /// At the time of writing, this is the most commonly used cache mode: it is used by the build + /// system (and any other parent using `--listen`) unless incremental compilation is enabled. + /// Once incremental compilation is more mature, it will be replaced by `incremental` in many + /// cases, but still has use cases, such as for release binaries, particularly globally cached + /// artifacts like compiler_rt. + whole, +}; pub const ParentWholeCache = struct { manifest: *Cache.Manifest, @@ -1433,22 +1460,33 @@ pub const ParentWholeCache = struct { }; const CacheUse = union(CacheMode) { + none: *None, incremental: *Incremental, whole: *Whole, + const None = struct { + /// User-requested artifacts are written directly to their output path in this cache mode. + /// However, if we need to emit any temporary files, they are placed in this directory. + /// We will recursively delete this directory at the end of this update. This field is + /// non-`null` only inside `update`. + tmp_artifact_directory: ?Cache.Directory, + }; + + const Incremental = struct { + /// All output files, including artifacts and incremental compilation metadata, are placed + /// in this directory, which is some 'o/' in a cache directory. + artifact_directory: Cache.Directory, + }; + const Whole = struct { - /// This is a pointer to a local variable inside `update()`. - cache_manifest: ?*Cache.Manifest = null, - cache_manifest_mutex: std.Thread.Mutex = .{}, - /// null means -fno-emit-bin. - /// This is mutable memory allocated into the Compilation-lifetime arena (`arena`) - /// 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 `bin_sub_path` but for implibs. - implib_sub_path: ?[]u8, - docs_sub_path: ?[]u8, + /// Since we don't open the output file until `update`, we must save these options for then. lf_open_opts: link.File.OpenOptions, + /// This is a pointer to a local variable inside `update`. + cache_manifest: ?*Cache.Manifest, + cache_manifest_mutex: std.Thread.Mutex, + /// This is non-`null` for most of the body of `update`. It is the temporary directory which + /// we initially emit our artifacts to. After the main part of the update is done, it will + /// be closed and moved to its final location, and this field set to `null`. tmp_artifact_directory: ?Cache.Directory, /// Prevents other processes from clobbering files in the output directory. lock: ?Cache.Lock, @@ -1467,17 +1505,16 @@ const CacheUse = union(CacheMode) { } }; - const Incremental = struct { - /// Where build artifacts and incremental compilation metadata serialization go. - artifact_directory: Cache.Directory, - }; - fn deinit(cu: CacheUse) void { switch (cu) { + .none => |none| { + assert(none.tmp_artifact_directory == null); + }, .incremental => |incremental| { incremental.artifact_directory.handle.close(); }, .whole => |whole| { + assert(whole.tmp_artifact_directory == null); whole.releaseLock(); }, } @@ -1504,28 +1541,14 @@ pub const CreateOptions = struct { std_mod: ?*Package.Module = null, root_name: []const u8, sysroot: ?[]const u8 = null, - /// `null` means to not emit a binary file. - emit_bin: ?EmitLoc, - /// `null` means to not emit a C header file. - emit_h: ?EmitLoc = null, - /// `null` means to not emit assembly. - emit_asm: ?EmitLoc = null, - /// `null` means to not emit LLVM IR. - emit_llvm_ir: ?EmitLoc = null, - /// `null` means to not emit LLVM module bitcode. - emit_llvm_bc: ?EmitLoc = null, - /// `null` means to not emit docs. - emit_docs: ?EmitLoc = null, - /// `null` means to not emit an import lib. - emit_implib: ?EmitLoc = null, - /// 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. - /// In the case that the output binary is being emitted into a directory which - /// is externally modified - essentially anything other than zig-cache - then - /// this flag would be set to disable this machinery to avoid false positives. - disable_lld_caching: bool = false, - cache_mode: CacheMode = .incremental, + cache_mode: CacheMode, + emit_h: Emit = .no, + emit_bin: Emit, + emit_asm: Emit = .no, + emit_implib: Emit = .no, + emit_llvm_ir: Emit = .no, + emit_llvm_bc: Emit = .no, + emit_docs: Emit = .no, /// This field is intended to be removed. /// The ELF implementation no longer uses this data, however the MachO and COFF /// implementations still do. @@ -1591,9 +1614,9 @@ pub const CreateOptions = struct { linker_tsaware: bool = false, linker_nxcompat: bool = false, linker_dynamicbase: bool = true, - linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null, + linker_compress_debug_sections: ?link.File.Lld.Elf.CompressDebugSections = null, linker_module_definition_file: ?[]const u8 = null, - linker_sort_section: ?link.File.Elf.SortSection = null, + linker_sort_section: ?link.File.Lld.Elf.SortSection = null, major_subsystem_version: ?u16 = null, minor_subsystem_version: ?u16 = null, clang_passthrough_mode: bool = false, @@ -1615,7 +1638,7 @@ pub const CreateOptions = struct { /// building such dependencies themselves, this flag must be set to avoid /// infinite recursion. skip_linker_dependencies: bool = false, - hash_style: link.File.Elf.HashStyle = .both, + hash_style: link.File.Lld.Elf.HashStyle = .both, entry: Entry = .default, force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .empty, stack_size: ?u64 = null, @@ -1663,6 +1686,38 @@ pub const CreateOptions = struct { parent_whole_cache: ?ParentWholeCache = null, pub const Entry = link.File.OpenOptions.Entry; + + /// Which fields are valid depends on the `cache_mode` given. + pub const Emit = union(enum) { + /// Do not emit this file. Always valid. + no, + /// Emit this file into its default name in the cache directory. + /// Requires `cache_mode` to not be `.none`. + yes_cache, + /// Emit this file to the given path (absolute or cwd-relative). + /// Requires `cache_mode` to be `.none`. + yes_path: []const u8, + + fn resolve(emit: Emit, arena: Allocator, opts: *const CreateOptions, ea: std.zig.EmitArtifact) Allocator.Error!?[]const u8 { + switch (emit) { + .no => return null, + .yes_cache => { + assert(opts.cache_mode != .none); + return try ea.cacheName(arena, .{ + .root_name = opts.root_name, + .target = opts.root_mod.resolved_target.result, + .output_mode = opts.config.output_mode, + .link_mode = opts.config.link_mode, + .version = opts.version, + }); + }, + .yes_path => |path| { + assert(opts.cache_mode == .none); + return try arena.dupe(u8, path); + }, + } + } + }; }; fn addModuleTableToCacheHash( @@ -1870,13 +1925,18 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil cache.hash.add(options.config.link_libunwind); cache.hash.add(output_mode); cache_helpers.addDebugFormat(&cache.hash, options.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); cache.hash.addBytes(options.root_name); cache.hash.add(options.config.wasi_exec_model); cache.hash.add(options.config.san_cov_trace_pc_guard); cache.hash.add(options.debug_compiler_runtime_libs); + // The actual emit paths don't matter. They're only user-specified if we aren't using the + // cache! However, it does matter whether the files are emitted at all. + cache.hash.add(options.emit_bin != .no); + cache.hash.add(options.emit_asm != .no); + cache.hash.add(options.emit_implib != .no); + cache.hash.add(options.emit_llvm_ir != .no); + cache.hash.add(options.emit_llvm_bc != .no); + cache.hash.add(options.emit_docs != .no); // TODO audit this and make sure everything is in it const main_mod = options.main_mod orelse options.root_mod; @@ -1926,7 +1986,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil try zcu.init(options.thread_pool.getIdCount()); break :blk zcu; } else blk: { - if (options.emit_h != null) return error.NoZigModuleForCHeader; + if (options.emit_h != .no) return error.NoZigModuleForCHeader; break :blk null; }; errdefer if (opt_zcu) |zcu| zcu.deinit(); @@ -1939,18 +1999,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .arena = arena, .zcu = opt_zcu, .cache_use = undefined, // populated below - .bin_file = null, // populated below - .implib_emit = null, // handled below - .docs_emit = null, // handled below + .bin_file = null, // populated below if necessary .root_mod = options.root_mod, .config = options.config, .dirs = options.dirs, - .emit_asm = options.emit_asm, - .emit_llvm_ir = options.emit_llvm_ir, - .emit_llvm_bc = options.emit_llvm_bc, .work_queues = @splat(.init(gpa)), - .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), - .win32_resource_work_queue = if (dev.env.supports(.win32_resource)) std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa) else .{}, + .c_object_work_queue = .init(gpa), + .win32_resource_work_queue = if (dev.env.supports(.win32_resource)) .init(gpa) else .{}, .c_source_files = options.c_source_files, .rc_source_files = options.rc_source_files, .cache_parent = cache, @@ -2003,7 +2058,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .file_system_inputs = options.file_system_inputs, .parent_whole_cache = options.parent_whole_cache, .link_diags = .init(gpa), - .remaining_prelink_tasks = 0, + .emit_bin = try options.emit_bin.resolve(arena, &options, .bin), + .emit_asm = try options.emit_asm.resolve(arena, &options, .@"asm"), + .emit_implib = try options.emit_implib.resolve(arena, &options, .implib), + .emit_llvm_ir = try options.emit_llvm_ir.resolve(arena, &options, .llvm_ir), + .emit_llvm_bc = try options.emit_llvm_bc.resolve(arena, &options, .llvm_bc), + .emit_docs = try options.emit_docs.resolve(arena, &options, .docs), }; // Prevent some footguns by making the "any" fields of config reflect @@ -2070,7 +2130,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .soname = options.soname, .compatibility_version = options.compatibility_version, .build_id = build_id, - .disable_lld_caching = options.disable_lld_caching or options.cache_mode == .whole, .subsystem = options.subsystem, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, @@ -2089,6 +2148,17 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil }; switch (options.cache_mode) { + .none => { + const none = try arena.create(CacheUse.None); + none.* = .{ .tmp_artifact_directory = null }; + comp.cache_use = .{ .none = none }; + if (comp.emit_bin) |path| { + comp.bin_file = try link.File.open(arena, comp, .{ + .root_dir = .cwd(), + .sub_path = path, + }, lf_open_opts); + } + }, .incremental => { // Options that are specific to zig source files, that cannot be // modified between incremental updates. @@ -2102,7 +2172,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil hash.addListOfBytes(options.test_filters); hash.addOptionalBytes(options.test_name_prefix); hash.add(options.skip_linker_dependencies); - hash.add(options.emit_h != null); + hash.add(options.emit_h != .no); hash.add(error_limit); // Here we put the root source file path name, but *not* with addFile. @@ -2137,49 +2207,26 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil }; comp.cache_use = .{ .incremental = incremental }; - if (options.emit_bin) |emit_bin| { + if (comp.emit_bin) |cache_rel_path| { const emit: Cache.Path = .{ - .root_dir = emit_bin.directory orelse artifact_directory, - .sub_path = emit_bin.basename, + .root_dir = artifact_directory, + .sub_path = cache_rel_path, }; comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts); } - - if (options.emit_implib) |emit_implib| { - comp.implib_emit = .{ - .root_dir = emit_implib.directory orelse artifact_directory, - .sub_path = emit_implib.basename, - }; - } - - if (options.emit_docs) |emit_docs| { - comp.docs_emit = .{ - .root_dir = emit_docs.directory orelse artifact_directory, - .sub_path = emit_docs.basename, - }; - } }, .whole => { - // For whole cache mode, we don't know where to put outputs from - // the linker until the final cache hash, which is available after - // the compilation is complete. + // For whole cache mode, we don't know where to put outputs from the linker until + // the final cache hash, which is available after the compilation is complete. // - // Therefore, bin_file is left null until the beginning of update(), - // where it may find a cache hit, or use a temporary directory to - // hold output artifacts. + // Therefore, `comp.bin_file` is left `null` (already done) until `update`, where + // it may find a cache hit, or else will use a temporary directory to hold output + // artifacts. const whole = try arena.create(CacheUse.Whole); whole.* = .{ - // This is kept here so that link.File.open can be called later. .lf_open_opts = lf_open_opts, - // This is so that when doing `CacheMode.whole`, the mechanism in update() - // can use it for communicating the result directory via `bin_file.emit`. - // This is used to distinguish between -fno-emit-bin and -femit-bin - // for `CacheMode.whole`. - // This memory will be overwritten with the real digest in update() but - // the basename will be preserved. - .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), + .cache_manifest = null, + .cache_manifest_mutex = .{}, .tmp_artifact_directory = null, .lock = null, }; @@ -2187,14 +2234,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil }, } - // Handle the case of e.g. -fno-emit-bin -femit-llvm-ir. - if (options.emit_bin == null and (comp.verbose_llvm_ir != null or - comp.verbose_llvm_bc != null or - (use_llvm and comp.emit_asm != null) or - comp.emit_llvm_ir != null or - comp.emit_llvm_bc != null)) - { - if (opt_zcu) |zcu| zcu.llvm_object = try LlvmObject.create(arena, comp); + if (use_llvm) { + if (opt_zcu) |zcu| { + zcu.llvm_object = try LlvmObject.create(arena, comp); + } } break :comp comp; @@ -2216,7 +2259,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil }; comp.c_object_table.putAssumeCapacityNoClobber(c_object, {}); } - comp.remaining_prelink_tasks += @intCast(comp.c_object_table.count()); + comp.link_task_queue.pending_prelink_tasks += @intCast(comp.c_object_table.count()); // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`. const win32_resource_count = @@ -2227,7 +2270,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // Add this after adding logic to updateWin32Resource to pass the // result into link.loadInput. loadInput integration is not implemented // for Windows linking logic yet. - //comp.remaining_prelink_tasks += @intCast(win32_resource_count); + //comp.link_task_queue.pending_prelink_tasks += @intCast(win32_resource_count); for (options.rc_source_files) |rc_source_file| { const win32_resource = try gpa.create(Win32Resource); errdefer gpa.destroy(win32_resource); @@ -2251,12 +2294,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil } } - 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 target.ofmt != .c) { + if (comp.emit_bin != null and target.ofmt != .c) { if (!comp.skip_linker_dependencies) { // If we need to build libc for the target, add work items for it. // We go through the work queue so that building can be done in parallel. @@ -2278,78 +2316,76 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil const paths = try lci.resolveCrtPaths(arena, basenames, target); const fields = @typeInfo(@TypeOf(paths)).@"struct".fields; - try comp.link_task_queue.shared.ensureUnusedCapacity(gpa, fields.len + 1); + try comp.link_task_queue.queued_prelink.ensureUnusedCapacity(gpa, fields.len + 1); inline for (fields) |field| { if (@field(paths, field.name)) |path| { - comp.link_task_queue.shared.appendAssumeCapacity(.{ .load_object = path }); - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.queued_prelink.appendAssumeCapacity(.{ .load_object = path }); } } // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`. - comp.link_task_queue.shared.appendAssumeCapacity(.load_host_libc); - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.queued_prelink.appendAssumeCapacity(.load_host_libc); } else if (target.isMuslLibC()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| { comp.queued_jobs.musl_crt_file[@intFromEnum(f)] = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } switch (comp.config.link_mode) { .static => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_a)] = true, .dynamic => comp.queued_jobs.musl_crt_file[@intFromEnum(musl.CrtFile.libc_so)] = true, } - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } else if (target.isGnuLibC()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; if (glibc.needsCrt0(comp.config.output_mode)) |f| { comp.queued_jobs.glibc_crt_file[@intFromEnum(f)] = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } comp.queued_jobs.glibc_shared_objects = true; - comp.remaining_prelink_tasks += glibc.sharedObjectsCount(&target); + comp.link_task_queue.pending_prelink_tasks += glibc.sharedObjectsCount(&target); comp.queued_jobs.glibc_crt_file[@intFromEnum(glibc.CrtFile.libc_nonshared_a)] = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } else if (target.isFreeBSDLibC()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; if (freebsd.needsCrt0(comp.config.output_mode)) |f| { comp.queued_jobs.freebsd_crt_file[@intFromEnum(f)] = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } comp.queued_jobs.freebsd_shared_objects = true; - comp.remaining_prelink_tasks += freebsd.sharedObjectsCount(); + comp.link_task_queue.pending_prelink_tasks += freebsd.sharedObjectsCount(); } else if (target.isNetBSDLibC()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; if (netbsd.needsCrt0(comp.config.output_mode)) |f| { comp.queued_jobs.netbsd_crt_file[@intFromEnum(f)] = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } comp.queued_jobs.netbsd_shared_objects = true; - comp.remaining_prelink_tasks += netbsd.sharedObjectsCount(); + comp.link_task_queue.pending_prelink_tasks += netbsd.sharedObjectsCount(); } else if (target.isWasiLibC()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; for (comp.wasi_emulated_libs) |crt_file| { comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = true; } - comp.remaining_prelink_tasks += @intCast(comp.wasi_emulated_libs.len); + comp.link_task_queue.pending_prelink_tasks += @intCast(comp.wasi_emulated_libs.len); comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.execModelCrtFile(comp.config.wasi_exec_model))] = true; comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(wasi_libc.CrtFile.libc_a)] = true; - comp.remaining_prelink_tasks += 2; + comp.link_task_queue.pending_prelink_tasks += 2; } else if (target.isMinGW()) { if (!std.zig.target.canBuildLibC(target)) return error.LibCUnavailable; const main_crt_file: mingw.CrtFile = if (is_dyn_lib) .dllcrt2_o else .crt2_o; comp.queued_jobs.mingw_crt_file[@intFromEnum(main_crt_file)] = true; comp.queued_jobs.mingw_crt_file[@intFromEnum(mingw.CrtFile.libmingw32_lib)] = true; - comp.remaining_prelink_tasks += 2; + comp.link_task_queue.pending_prelink_tasks += 2; // When linking mingw-w64 there are some import libs we always need. try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len); @@ -2363,7 +2399,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil target.isMinGW()) { comp.queued_jobs.zigc_lib = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } } @@ -2380,53 +2416,53 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil } if (comp.wantBuildLibUnwindFromSource()) { comp.queued_jobs.libunwind = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { comp.queued_jobs.libcxx = true; comp.queued_jobs.libcxxabi = true; - comp.remaining_prelink_tasks += 2; + comp.link_task_queue.pending_prelink_tasks += 2; } if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.any_sanitize_thread) { comp.queued_jobs.libtsan = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } if (can_build_compiler_rt) { if (comp.compiler_rt_strat == .lib) { log.debug("queuing a job to build compiler_rt_lib", .{}); comp.queued_jobs.compiler_rt_lib = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } else if (comp.compiler_rt_strat == .obj) { log.debug("queuing a job to build compiler_rt_obj", .{}); // In this case we are making a static library, so we ask // for a compiler-rt object to put in it. comp.queued_jobs.compiler_rt_obj = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } if (comp.ubsan_rt_strat == .lib) { log.debug("queuing a job to build ubsan_rt_lib", .{}); comp.queued_jobs.ubsan_rt_lib = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } else if (comp.ubsan_rt_strat == .obj) { log.debug("queuing a job to build ubsan_rt_obj", .{}); comp.queued_jobs.ubsan_rt_obj = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } if (is_exe_or_dyn_lib and comp.config.any_fuzz) { log.debug("queuing a job to build libfuzzer", .{}); comp.queued_jobs.fuzzer_lib = true; - comp.remaining_prelink_tasks += 1; + comp.link_task_queue.pending_prelink_tasks += 1; } } } - try comp.link_task_queue.shared.append(gpa, .load_explicitly_provided); - comp.remaining_prelink_tasks += 1; + try comp.link_task_queue.queued_prelink.append(gpa, .load_explicitly_provided); } - log.debug("total prelink tasks: {d}", .{comp.remaining_prelink_tasks}); + log.debug("queued prelink tasks: {d}", .{comp.link_task_queue.queued_prelink.items.len}); + log.debug("pending prelink tasks: {d}", .{comp.link_task_queue.pending_prelink_tasks}); return comp; } @@ -2434,6 +2470,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil pub fn destroy(comp: *Compilation) void { const gpa = comp.gpa; + // This needs to be destroyed first, because it might contain MIR which we only know + // how to interpret (which kind of MIR it is) from `comp.bin_file`. + comp.link_task_queue.deinit(comp); + if (comp.bin_file) |lf| lf.destroy(); if (comp.zcu) |zcu| zcu.deinit(); comp.cache_use.deinit(); @@ -2515,8 +2555,6 @@ pub fn destroy(comp: *Compilation) void { comp.failed_win32_resources.deinit(gpa); comp.link_diags.deinit(); - comp.link_task_queue.deinit(gpa); - comp.link_task_queue_postponed.deinit(gpa); comp.clearMiscFailures(); @@ -2550,8 +2588,28 @@ pub fn hotCodeSwap( try lf.makeExecutable(); } -fn cleanupAfterUpdate(comp: *Compilation) void { +fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { switch (comp.cache_use) { + .none => |none| { + if (none.tmp_artifact_directory) |*tmp_dir| { + tmp_dir.handle.close(); + none.tmp_artifact_directory = null; + if (dev.env == .bootstrap) { + // zig1 uses `CacheMode.none`, but it doesn't need to know how to delete + // temporary directories; it doesn't have a real cache directory anyway. + return; + } + const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); + comp.dirs.local_cache.handle.deleteTree(tmp_dir_sub_path) catch |err| { + log.warn("failed to delete temporary directory '{s}{c}{s}': {s}", .{ + comp.dirs.local_cache.path orelse ".", + std.fs.path.sep, + tmp_dir_sub_path, + @errorName(err), + }); + }; + } + }, .incremental => return, .whole => |whole| { if (whole.cache_manifest) |man| { @@ -2562,10 +2620,18 @@ fn cleanupAfterUpdate(comp: *Compilation) void { lf.destroy(); comp.bin_file = null; } - if (whole.tmp_artifact_directory) |*directory| { - directory.handle.close(); - if (directory.path) |p| comp.gpa.free(p); + if (whole.tmp_artifact_directory) |*tmp_dir| { + tmp_dir.handle.close(); whole.tmp_artifact_directory = null; + const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); + comp.dirs.local_cache.handle.deleteTree(tmp_dir_sub_path) catch |err| { + log.warn("failed to delete temporary directory '{s}{c}{s}': {s}", .{ + comp.dirs.local_cache.path orelse ".", + std.fs.path.sep, + tmp_dir_sub_path, + @errorName(err), + }); + }; } }, } @@ -2585,14 +2651,27 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { comp.clearMiscFailures(); comp.last_update_was_cache_hit = false; - var man: Cache.Manifest = undefined; - defer cleanupAfterUpdate(comp); - var tmp_dir_rand_int: u64 = undefined; + var man: Cache.Manifest = undefined; + defer cleanupAfterUpdate(comp, tmp_dir_rand_int); // If using the whole caching strategy, we check for *everything* up front, including // C source files. + log.debug("Compilation.update for {s}, CacheMode.{s}", .{ comp.root_name, @tagName(comp.cache_use) }); switch (comp.cache_use) { + .none => |none| { + assert(none.tmp_artifact_directory == null); + none.tmp_artifact_directory = d: { + tmp_dir_rand_int = std.crypto.random.int(u64); + const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); + const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); + break :d .{ + .path = path, + .handle = try comp.dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{}), + }; + }; + }, + .incremental => {}, .whole => |whole| { assert(comp.bin_file == null); // We are about to obtain this lock, so here we give other processes a chance first. @@ -2639,10 +2718,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { comp.last_update_was_cache_hit = true; log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); const bin_digest = man.finalBin(); - const hex_digest = Cache.binToHex(bin_digest); comp.digest = bin_digest; - comp.wholeCacheModeSetBinFilePath(whole, &hex_digest); assert(whole.lock == null); whole.lock = man.toOwnedLock(); @@ -2651,52 +2728,23 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); // Compile the artifacts to a temporary directory. - const tmp_artifact_directory: Cache.Directory = d: { - const s = std.fs.path.sep_str; + whole.tmp_artifact_directory = d: { tmp_dir_rand_int = std.crypto.random.int(u64); - const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int); - - const path = try comp.dirs.local_cache.join(gpa, &.{tmp_dir_sub_path}); - errdefer gpa.free(path); - - const handle = try comp.dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{}); - errdefer handle.close(); - + const tmp_dir_sub_path = "tmp" ++ std.fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); + const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); break :d .{ .path = path, - .handle = handle, + .handle = try comp.dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{}), }; }; - whole.tmp_artifact_directory = tmp_artifact_directory; - - // Now that the directory is known, it is time to create the Emit - // objects and call link.File.open. - - if (whole.implib_sub_path) |sub_path| { - comp.implib_emit = .{ - .root_dir = tmp_artifact_directory, - .sub_path = std.fs.path.basename(sub_path), - }; - } - - if (whole.docs_sub_path) |sub_path| { - comp.docs_emit = .{ - .root_dir = tmp_artifact_directory, - .sub_path = std.fs.path.basename(sub_path), - }; - } - - if (whole.bin_sub_path) |sub_path| { + if (comp.emit_bin) |sub_path| { const emit: Cache.Path = .{ - .root_dir = tmp_artifact_directory, - .sub_path = std.fs.path.basename(sub_path), + .root_dir = whole.tmp_artifact_directory.?, + .sub_path = sub_path, }; comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts); } }, - .incremental => { - log.debug("Compilation.update for {s}, CacheMode.incremental", .{comp.root_name}); - }, } // From this point we add a preliminary set of file system inputs that @@ -2757,6 +2805,17 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { } } + // The linker progress node is set up here instead of in `performAllTheWork`, because + // we also want it around during `flush`. + const have_link_node = comp.bin_file != null; + if (have_link_node) { + comp.link_prog_node = main_progress_node.start("Linking", 0); + } + defer if (have_link_node) { + comp.link_prog_node.end(); + comp.link_prog_node = .none; + }; + try comp.performAllTheWork(main_progress_node); if (comp.zcu) |zcu| { @@ -2768,7 +2827,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { // 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. - try pt.populateTestFunctions(main_progress_node); + try pt.populateTestFunctions(); } try pt.processExports(); @@ -2795,11 +2854,18 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { return; } - // Flush below handles -femit-bin but there is still -femit-llvm-ir, - // -femit-llvm-bc, and -femit-asm, in the case of C objects. - comp.emitOthers(); + if (comp.zcu == null and comp.config.output_mode == .Obj and comp.c_object_table.count() == 1) { + // This is `zig build-obj foo.c`. We can emit asm and LLVM IR/bitcode. + const c_obj_path = comp.c_object_table.keys()[0].status.success.object_path; + if (comp.emit_asm) |path| try comp.emitFromCObject(arena, c_obj_path, ".s", path); + if (comp.emit_llvm_ir) |path| try comp.emitFromCObject(arena, c_obj_path, ".ll", path); + if (comp.emit_llvm_bc) |path| try comp.emitFromCObject(arena, c_obj_path, ".bc", path); + } switch (comp.cache_use) { + .none, .incremental => { + try flush(comp, arena, .main); + }, .whole => |whole| { if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); if (comp.parent_whole_cache) |pwc| { @@ -2811,18 +2877,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { const bin_digest = man.finalBin(); const hex_digest = Cache.binToHex(bin_digest); - // 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| { - tmp_directory.handle.close(); - if (tmp_directory.path) |p| gpa.free(p); - whole.tmp_artifact_directory = null; - } else unreachable; - - const s = std.fs.path.sep_str; - const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int); - const o_sub_path = "o" ++ s ++ hex_digest; - // Work around windows `AccessDenied` if any files within this // directory are open by closing and reopening the file handles. const need_writable_dance: enum { no, lf_only, lf_and_debug } = w: { @@ -2847,6 +2901,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { break :w .no; }; + // Rename the temporary directory into place. + // Close tmp dir and link.File to avoid open handle during rename. + whole.tmp_artifact_directory.?.handle.close(); + whole.tmp_artifact_directory = null; + const s = std.fs.path.sep_str; + const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int); + const o_sub_path = "o" ++ s ++ hex_digest; renameTmpIntoCache(comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| { return comp.setMiscFailure( .rename_results, @@ -2859,7 +2920,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { ); }; comp.digest = bin_digest; - comp.wholeCacheModeSetBinFilePath(whole, &hex_digest); // The linker flush functions need to know the final output path // for debug info purposes because executable debug info contains @@ -2867,10 +2927,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { if (comp.bin_file) |lf| { lf.emit = .{ .root_dir = comp.dirs.local_cache, - .sub_path = whole.bin_sub_path.?, + .sub_path = try std.fs.path.join(arena, &.{ o_sub_path, comp.emit_bin.? }), }; - // Has to be after the `wholeCacheModeSetBinFilePath` above. switch (need_writable_dance) { .no => {}, .lf_only => try lf.makeWritable(), @@ -2881,10 +2940,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { } } - try flush(comp, arena, .{ - .root_dir = comp.dirs.local_cache, - .sub_path = o_sub_path, - }, .main, main_progress_node); + try flush(comp, arena, .main); // Calling `flush` may have produced errors, in which case the // cache manifest must not be written. @@ -2903,11 +2959,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { assert(whole.lock == null); whole.lock = man.toOwnedLock(); }, - .incremental => |incremental| { - try flush(comp, arena, .{ - .root_dir = incremental.artifact_directory, - }, .main, main_progress_node); - }, } } @@ -2937,27 +2988,98 @@ pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocat fsi.appendSliceAssumeCapacity(path.sub_path); } +fn resolveEmitPath(comp: *Compilation, path: []const u8) Cache.Path { + return .{ + .root_dir = switch (comp.cache_use) { + .none => .cwd(), + .incremental => |i| i.artifact_directory, + .whole => |w| w.tmp_artifact_directory.?, + }, + .sub_path = path, + }; +} +/// Like `resolveEmitPath`, but for calling during `flush`. The returned `Cache.Path` may reference +/// memory from `arena`, and may reference `path` itself. +/// If `kind == .temp`, then the returned path will be in a temporary or cache directory. This is +/// useful for intermediate files, such as the ZCU object file emitted by the LLVM backend. +pub fn resolveEmitPathFlush( + comp: *Compilation, + arena: Allocator, + kind: enum { temp, artifact }, + path: []const u8, +) Allocator.Error!Cache.Path { + switch (comp.cache_use) { + .none => |none| return .{ + .root_dir = switch (kind) { + .temp => none.tmp_artifact_directory.?, + .artifact => .cwd(), + }, + .sub_path = path, + }, + .incremental, .whole => return .{ + .root_dir = comp.dirs.local_cache, + .sub_path = try fs.path.join(arena, &.{ + "o", + &Cache.binToHex(comp.digest.?), + path, + }), + }, + } +} fn flush( comp: *Compilation, arena: Allocator, - default_artifact_directory: Cache.Path, tid: Zcu.PerThread.Id, - prog_node: std.Progress.Node, ) !void { + if (comp.zcu) |zcu| { + if (zcu.llvm_object) |llvm_object| { + // Emit the ZCU object from LLVM now; it's required to flush the output file. + // If there's an output file, it wants to decide where the LLVM object goes! + const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0); + defer sub_prog_node.end(); + try llvm_object.emit(.{ + .pre_ir_path = comp.verbose_llvm_ir, + .pre_bc_path = comp.verbose_llvm_bc, + + .bin_path = p: { + const lf = comp.bin_file orelse break :p null; + const p = try comp.resolveEmitPathFlush(arena, .temp, lf.zcu_object_basename.?); + break :p try p.toStringZ(arena); + }, + .asm_path = p: { + const raw = comp.emit_asm orelse break :p null; + const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); + break :p try p.toStringZ(arena); + }, + .post_ir_path = p: { + const raw = comp.emit_llvm_ir orelse break :p null; + const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); + break :p try p.toStringZ(arena); + }, + .post_bc_path = p: { + const raw = comp.emit_llvm_bc orelse break :p null; + const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); + break :p try p.toStringZ(arena); + }, + + .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, + .fuzz = comp.config.any_fuzz, + .lto = comp.config.lto, + }); + } + } if (comp.bin_file) |lf| { // This is needed before reading the error flags. - lf.flush(arena, tid, prog_node) catch |err| switch (err) { + lf.flush(arena, tid, comp.link_prog_node) catch |err| switch (err) { error.LinkFailure => {}, // Already reported. error.OutOfMemory => return error.OutOfMemory, }; } - if (comp.zcu) |zcu| { try link.File.C.flushEmitH(zcu); - - if (zcu.llvm_object) |llvm_object| { - try emitLlvmObject(comp, arena, default_artifact_directory, null, llvm_object, prog_node); - } } } @@ -3009,45 +3131,6 @@ fn renameTmpIntoCache( } } -/// Communicate the output binary location to parent Compilations. -fn wholeCacheModeSetBinFilePath( - comp: *Compilation, - whole: *CacheUse.Whole, - digest: *const [Cache.hex_digest_len]u8, -) void { - const digest_start = 2; // "o/[digest]/[basename]" - - if (whole.bin_sub_path) |sub_path| { - @memcpy(sub_path[digest_start..][0..digest.len], digest); - } - - if (whole.implib_sub_path) |sub_path| { - @memcpy(sub_path[digest_start..][0..digest.len], digest); - - comp.implib_emit = .{ - .root_dir = comp.dirs.local_cache, - .sub_path = sub_path, - }; - } - - if (whole.docs_sub_path) |sub_path| { - @memcpy(sub_path[digest_start..][0..digest.len], digest); - - comp.docs_emit = .{ - .root_dir = comp.dirs.local_cache, - .sub_path = sub_path, - }; - } -} - -fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemory}!?[]u8 { - const emit = opt_emit orelse return null; - if (emit.directory != null) return null; - const s = std.fs.path.sep_str; - const format = "o" ++ s ++ ("x" ** Cache.hex_digest_len) ++ s ++ "{s}"; - return try std.fmt.allocPrint(arena, format, .{emit.basename}); -} - /// This is only observed at compile-time and used to emit a compile error /// to remind the programmer to update multiple related pieces of code that /// are in different locations. Bump this number when adding or deleting @@ -3068,7 +3151,7 @@ fn addNonIncrementalStuffToCacheManifest( man.hash.addListOfBytes(comp.test_filters); man.hash.addOptionalBytes(comp.test_name_prefix); man.hash.add(comp.skip_linker_dependencies); - //man.hash.add(zcu.emit_h != null); + //man.hash.add(zcu.emit_h != .no); man.hash.add(zcu.error_limit); } else { cache_helpers.addModule(&man.hash, comp.root_mod); @@ -3114,10 +3197,6 @@ fn addNonIncrementalStuffToCacheManifest( man.hash.addListOfBytes(comp.framework_dirs); man.hash.addListOfBytes(comp.windows_libs.keys()); - 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.addListOfBytes(comp.global_cc_argv); const opts = comp.cache_use.whole.lf_open_opts; @@ -3195,82 +3274,39 @@ fn addNonIncrementalStuffToCacheManifest( man.hash.addOptional(opts.minor_subsystem_version); } -fn emitOthers(comp: *Compilation) void { - if (comp.config.output_mode != .Obj or comp.zcu != null or - comp.c_object_table.count() == 0) - { - return; - } - const obj_path = comp.c_object_table.keys()[0].status.success.object_path; - const ext = std.fs.path.extension(obj_path.sub_path); - const dirname = obj_path.sub_path[0 .. obj_path.sub_path.len - ext.len]; - // This obj path always ends with the object file extension, but if we change the - // extension to .ll, .bc, or .s, then it will be the path to those things. - const outs = [_]struct { - emit: ?EmitLoc, - ext: []const u8, - }{ - .{ .emit = comp.emit_asm, .ext = ".s" }, - .{ .emit = comp.emit_llvm_ir, .ext = ".ll" }, - .{ .emit = comp.emit_llvm_bc, .ext = ".bc" }, - }; - for (outs) |out| { - if (out.emit) |loc| { - if (loc.directory) |directory| { - const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ - dirname, out.ext, - }) catch |err| { - log.err("unable to copy {s}{s}: {s}", .{ dirname, out.ext, @errorName(err) }); - continue; - }; - defer comp.gpa.free(src_path); - obj_path.root_dir.handle.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| { - log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) }); - }; - } - } - } -} - -pub fn emitLlvmObject( +fn emitFromCObject( comp: *Compilation, arena: Allocator, - default_artifact_directory: Cache.Path, - bin_emit_loc: ?EmitLoc, - llvm_object: LlvmObject.Ptr, - prog_node: std.Progress.Node, -) !void { - const sub_prog_node = prog_node.start("LLVM Emit Object", 0); - defer sub_prog_node.end(); - - try llvm_object.emit(.{ - .pre_ir_path = comp.verbose_llvm_ir, - .pre_bc_path = comp.verbose_llvm_bc, - .bin_path = try resolveEmitLoc(arena, default_artifact_directory, bin_emit_loc), - .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm), - .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir), - .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, 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, - .fuzz = comp.config.any_fuzz, - .lto = comp.config.lto, - }); -} + c_obj_path: Cache.Path, + new_ext: []const u8, + unresolved_emit_path: []const u8, +) Allocator.Error!void { + // The dirname and stem (i.e. everything but the extension), of the sub path of the C object. + // We'll append `new_ext` to it to get the path to the right thing (asm, LLVM IR, etc). + const c_obj_dir_and_stem: []const u8 = p: { + const p = c_obj_path.sub_path; + const ext_len = fs.path.extension(p).len; + break :p p[0 .. p.len - ext_len]; + }; + const src_path: Cache.Path = .{ + .root_dir = c_obj_path.root_dir, + .sub_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ + c_obj_dir_and_stem, + new_ext, + }), + }; + const emit_path = comp.resolveEmitPath(unresolved_emit_path); -fn resolveEmitLoc( - arena: Allocator, - default_artifact_directory: Cache.Path, - opt_loc: ?EmitLoc, -) Allocator.Error!?[*:0]const u8 { - const loc = opt_loc orelse return null; - const slice = if (loc.directory) |directory| - try directory.joinZ(arena, &.{loc.basename}) - else - try default_artifact_directory.joinStringZ(arena, loc.basename); - return slice.ptr; + src_path.root_dir.handle.copyFile( + src_path.sub_path, + emit_path.root_dir.handle, + emit_path.sub_path, + .{}, + ) catch |err| log.err("unable to copy '{}' to '{}': {s}", .{ + src_path, + emit_path, + @errorName(err), + }); } /// Having the file open for writing is problematic as far as executing the @@ -3512,7 +3548,7 @@ pub fn saveState(comp: *Compilation) !void { // TODO handle the union safety field //addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.data))); addBuf(&bufs, mem.sliceAsBytes(wasm.mir_extra.items)); - addBuf(&bufs, mem.sliceAsBytes(wasm.all_zcu_locals.items)); + addBuf(&bufs, mem.sliceAsBytes(wasm.mir_locals.items)); addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_bytes.items)); addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_offs.items)); @@ -4156,28 +4192,15 @@ pub fn addWholeFileError( } } -pub fn performAllTheWork( +fn performAllTheWork( comp: *Compilation, main_progress_node: std.Progress.Node, ) JobError!void { - comp.work_queue_progress_node = main_progress_node; - defer comp.work_queue_progress_node = .none; - + // Regardless of errors, `comp.zcu` needs to update its generation number. defer if (comp.zcu) |zcu| { - zcu.sema_prog_node.end(); - zcu.sema_prog_node = .none; - zcu.codegen_prog_node.end(); - zcu.codegen_prog_node = .none; - zcu.generation += 1; }; - try comp.performAllTheWorkInner(main_progress_node); -} -fn performAllTheWorkInner( - comp: *Compilation, - main_progress_node: std.Progress.Node, -) JobError!void { // Here we queue up all the AstGen tasks first, followed by C object compilation. // We wait until the AstGen tasks are all completed before proceeding to the // (at least for now) single-threaded main work queue. However, C object compilation @@ -4189,11 +4212,13 @@ fn performAllTheWorkInner( comp.link_task_wait_group.reset(); defer comp.link_task_wait_group.wait(); - if (comp.link_task_queue.start()) { - comp.thread_pool.spawnWgId(&comp.link_task_wait_group, link.flushTaskQueue, .{comp}); - } + comp.link_prog_node.increaseEstimatedTotalItems( + comp.link_task_queue.queued_prelink.items.len + // already queued prelink tasks + comp.link_task_queue.pending_prelink_tasks, // prelink tasks which will be queued + ); + comp.link_task_queue.start(comp); - if (comp.docs_emit != null) { + if (comp.emit_docs != null) { dev.check(.docs_emit); comp.thread_pool.spawnWg(&work_queue_wait_group, workerDocsCopy, .{comp}); work_queue_wait_group.spawnManager(workerDocsWasm, .{ comp, main_progress_node }); @@ -4471,7 +4496,7 @@ fn performAllTheWorkInner( }; } }, - .incremental => {}, + .none, .incremental => {}, } if (any_fatal_files or @@ -4499,15 +4524,31 @@ fn performAllTheWorkInner( } zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); - zcu.codegen_prog_node = if (comp.bin_file != null) main_progress_node.start("Code Generation", 0) else .none; + if (comp.bin_file != null) { + zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0); + } + // We increment `pending_codegen_jobs` so that it doesn't reach 0 until after analysis finishes. + // That prevents the "Code Generation" node from constantly disappearing and reappearing when + // we're probably going to analyze more functions at some point. + assert(zcu.pending_codegen_jobs.swap(1, .monotonic) == 0); // don't let this become 0 until analysis finishes } + // When analysis ends, delete the progress nodes for "Semantic Analysis" and possibly "Code Generation". + defer if (comp.zcu) |zcu| { + zcu.sema_prog_node.end(); + zcu.sema_prog_node = .none; + if (zcu.pending_codegen_jobs.rmw(.Sub, 1, .monotonic) == 1) { + // Decremented to 0, so all done. + zcu.codegen_prog_node.end(); + zcu.codegen_prog_node = .none; + } + }; if (!comp.separateCodegenThreadOk()) { // Waits until all input files have been parsed. comp.link_task_wait_group.wait(); comp.link_task_wait_group.reset(); std.log.scoped(.link).debug("finished waiting for link_task_wait_group", .{}); - if (comp.remaining_prelink_tasks > 0) { + if (comp.link_task_queue.pending_prelink_tasks > 0) { // Indicates an error occurred preventing prelink phase from completing. return; } @@ -4552,26 +4593,91 @@ pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void { fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void { switch (job) { - .codegen_nav => |nav_index| { + .codegen_func => |func| { + const zcu = comp.zcu.?; + const gpa = zcu.gpa; + var air = func.air; + errdefer { + zcu.codegen_prog_node.completeOne(); + comp.link_prog_node.completeOne(); + air.deinit(gpa); + } + if (!air.typesFullyResolved(zcu)) { + // Type resolution failed in a way which affects this function. This is a transitive + // failure, but it doesn't need recording, because this function semantically depends + // on the failed type, so when it is changed the function is updated. + zcu.codegen_prog_node.completeOne(); + comp.link_prog_node.completeOne(); + air.deinit(gpa); + return; + } + const shared_mir = try gpa.create(link.ZcuTask.LinkFunc.SharedMir); + shared_mir.* = .{ + .status = .init(.pending), + .value = undefined, + }; + assert(zcu.pending_codegen_jobs.rmw(.Add, 1, .monotonic) > 0); // the "Code Generation" node hasn't been ended + // This value is used as a heuristic to avoid queueing too much AIR/MIR at once (hence + // using a lot of memory). If this would cause too many AIR bytes to be in-flight, we + // will block on the `dispatchZcuLinkTask` call below. + const air_bytes: u32 = @intCast(air.instructions.len * 5 + air.extra.items.len * 4); + if (comp.separateCodegenThreadOk()) { + // `workerZcuCodegen` takes ownership of `air`. + comp.thread_pool.spawnWgId(&comp.link_task_wait_group, workerZcuCodegen, .{ comp, func.func, air, shared_mir }); + comp.dispatchZcuLinkTask(tid, .{ .link_func = .{ + .func = func.func, + .mir = shared_mir, + .air_bytes = air_bytes, + } }); + } else { + { + const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); + defer pt.deactivate(); + pt.runCodegen(func.func, &air, shared_mir); + } + assert(shared_mir.status.load(.monotonic) != .pending); + comp.dispatchZcuLinkTask(tid, .{ .link_func = .{ + .func = func.func, + .mir = shared_mir, + .air_bytes = air_bytes, + } }); + air.deinit(gpa); + } + }, + .link_nav => |nav_index| { const zcu = comp.zcu.?; const nav = zcu.intern_pool.getNav(nav_index); if (nav.analysis != null) { const unit: InternPool.AnalUnit = .wrap(.{ .nav_val = nav_index }); if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) { + comp.link_prog_node.completeOne(); return; } } assert(nav.status == .fully_resolved); - comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index }); - }, - .codegen_func => |func| { - comp.dispatchCodegenTask(tid, .{ .codegen_func = func }); + if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) { + // Type resolution failed in a way which affects this `Nav`. This is a transitive + // failure, but it doesn't need recording, because this `Nav` semantically depends + // on the failed type, so when it is changed the `Nav` will be updated. + comp.link_prog_node.completeOne(); + return; + } + comp.dispatchZcuLinkTask(tid, .{ .link_nav = nav_index }); }, - .codegen_type => |ty| { - comp.dispatchCodegenTask(tid, .{ .codegen_type = ty }); + .link_type => |ty| { + const zcu = comp.zcu.?; + if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa); + if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) { + // Type resolution failed in a way which affects this type. This is a transitive + // failure, but it doesn't need recording, because this type semantically depends + // on the failed type, so when that is changed, this type will be updated. + comp.link_prog_node.completeOne(); + return; + } + comp.dispatchZcuLinkTask(tid, .{ .link_type = ty }); }, .update_line_number => |ti| { - comp.dispatchCodegenTask(tid, .{ .update_line_number = ti }); + comp.dispatchZcuLinkTask(tid, .{ .update_line_number = ti }); }, .analyze_func => |func| { const named_frame = tracy.namedFrame("analyze_func"); @@ -4663,18 +4769,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void { } } -/// The reason for the double-queue here is that the first queue ensures any -/// resolve_type_fully tasks are complete before this dispatch function is called. -fn dispatchCodegenTask(comp: *Compilation, tid: usize, link_task: link.Task) void { - if (comp.separateCodegenThreadOk()) { - comp.queueLinkTasks(&.{link_task}); - } else { - assert(comp.remaining_prelink_tasks == 0); - link.doTask(comp, tid, link_task); - } -} - -fn separateCodegenThreadOk(comp: *const Compilation) bool { +pub fn separateCodegenThreadOk(comp: *const Compilation) bool { if (InternPool.single_threaded) return false; const zcu = comp.zcu orelse return true; return zcu.backendSupportsFeature(.separate_thread); @@ -4694,12 +4789,12 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { const zcu = comp.zcu orelse return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{}); - const emit = comp.docs_emit.?; - var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| { + const docs_path = comp.resolveEmitPath(comp.emit_docs.?); + var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| { return comp.lockAndSetMiscFailure( .docs_copy, - "unable to create output directory '{}{s}': {s}", - .{ emit.root_dir, emit.sub_path, @errorName(err) }, + "unable to create output directory '{}': {s}", + .{ docs_path, @errorName(err) }, ); }; defer out_dir.close(); @@ -4718,8 +4813,8 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { var tar_file = out_dir.createFile("sources.tar", .{}) catch |err| { return comp.lockAndSetMiscFailure( .docs_copy, - "unable to create '{}{s}/sources.tar': {s}", - .{ emit.root_dir, emit.sub_path, @errorName(err) }, + "unable to create '{}/sources.tar': {s}", + .{ docs_path, @errorName(err) }, ); }; defer tar_file.close(); @@ -4869,11 +4964,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye .parent = root_mod, }); try root_mod.deps.put(arena, "Walk", walk_mod); - const bin_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = root_name, - .target = resolved_target.result, - .output_mode = output_mode, - }); const sub_compilation = try Compilation.create(gpa, arena, .{ .dirs = dirs, @@ -4885,10 +4975,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye .root_name = root_name, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = .{ - .directory = null, // Put it in the cache directory. - .basename = bin_basename, - }, + .emit_bin = .yes_cache, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, @@ -4903,27 +4990,31 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node); - const emit = comp.docs_emit.?; - var out_dir = emit.root_dir.handle.makeOpenPath(emit.sub_path, .{}) catch |err| { + var crt_file = try sub_compilation.toCrtFile(); + defer crt_file.deinit(gpa); + + const docs_bin_file = crt_file.full_object_path; + assert(docs_bin_file.sub_path.len > 0); // emitted binary is not a directory + + const docs_path = comp.resolveEmitPath(comp.emit_docs.?); + var out_dir = docs_path.root_dir.handle.makeOpenPath(docs_path.sub_path, .{}) catch |err| { return comp.lockAndSetMiscFailure( .docs_copy, - "unable to create output directory '{}{s}': {s}", - .{ emit.root_dir, emit.sub_path, @errorName(err) }, + "unable to create output directory '{}': {s}", + .{ docs_path, @errorName(err) }, ); }; defer out_dir.close(); - sub_compilation.dirs.local_cache.handle.copyFile( - sub_compilation.cache_use.whole.bin_sub_path.?, + crt_file.full_object_path.root_dir.handle.copyFile( + crt_file.full_object_path.sub_path, out_dir, "main.wasm", .{}, ) catch |err| { - return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{ - sub_compilation.dirs.local_cache, - sub_compilation.cache_use.whole.bin_sub_path.?, - emit.root_dir, - emit.sub_path, + return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}' to '{}': {s}", .{ + crt_file.full_object_path, + docs_path, @errorName(err), }); }; @@ -5185,7 +5276,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module defer whole.cache_manifest_mutex.unlock(); try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); }, - .incremental => {}, + .incremental, .none => {}, } const bin_digest = man.finalBin(); @@ -5261,6 +5352,21 @@ pub const RtOptions = struct { allow_lto: bool = true, }; +fn workerZcuCodegen( + tid: usize, + comp: *Compilation, + func_index: InternPool.Index, + orig_air: Air, + out: *link.ZcuTask.LinkFunc.SharedMir, +) void { + var air = orig_air; + // We own `air` now, so we are responsbile for freeing it. + defer air.deinit(comp.gpa); + const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); + defer pt.deactivate(); + pt.runCodegen(func_index, &air, out); +} + fn buildRt( comp: *Compilation, root_source_name: []const u8, @@ -5515,9 +5621,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr defer man.deinit(); man.hash.add(comp.clang_preprocessor_mode); - 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.addOptionalBytes(comp.emit_asm); + man.hash.addOptionalBytes(comp.emit_llvm_ir); + man.hash.addOptionalBytes(comp.emit_llvm_bc); try cache_helpers.hashCSource(&man, c_object.src); @@ -5751,7 +5857,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); } }, - .incremental => {}, + .incremental, .none => {}, } } @@ -5792,7 +5898,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr }, }; - comp.queueLinkTasks(&.{.{ .load_object = c_object.status.success.object_path }}); + comp.queuePrelinkTasks(&.{.{ .load_object = c_object.status.success.object_path }}); } fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void { @@ -5995,7 +6101,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 defer whole.cache_manifest_mutex.unlock(); try whole_cache_manifest.addFilePost(dep_file_path); }, - .incremental => {}, + .incremental, .none => {}, } } } @@ -7167,12 +7273,6 @@ fn buildOutputFromZig( .cc_argv = &.{}, .parent = null, }); - const target = comp.getTarget(); - const bin_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = root_name, - .target = target, - .output_mode = output_mode, - }); const parent_whole_cache: ?ParentWholeCache = switch (comp.cache_use) { .whole => |whole| .{ @@ -7185,7 +7285,7 @@ fn buildOutputFromZig( 3, // global cache is the same }, }, - .incremental => null, + .incremental, .none => null, }; const sub_compilation = try Compilation.create(gpa, arena, .{ @@ -7198,13 +7298,9 @@ fn buildOutputFromZig( .root_name = root_name, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = .{ - .directory = null, // Put it in the cache directory. - .basename = bin_basename, - }, + .emit_bin = .yes_cache, .function_sections = true, .data_sections = true, - .emit_h = null, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, @@ -7225,7 +7321,7 @@ fn buildOutputFromZig( assert(out.* == null); out.* = crt_file; - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); } pub const CrtFileOptions = struct { @@ -7324,13 +7420,9 @@ pub fn build_crt_file( .root_name = root_name, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = .{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }, + .emit_bin = .yes_cache, .function_sections = options.function_sections orelse false, .data_sections = options.data_sections orelse false, - .emit_h = null, .c_source_files = c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, @@ -7349,7 +7441,7 @@ pub fn build_crt_file( try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); const crt_file = try sub_compilation.toCrtFile(); - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); { comp.mutex.lock(); @@ -7359,8 +7451,8 @@ pub fn build_crt_file( } } -pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) void { - comp.queueLinkTasks(switch (config.output_mode) { +pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) void { + comp.queuePrelinkTasks(switch (config.output_mode) { .Exe => unreachable, .Obj => &.{.{ .load_object = path }}, .Lib => &.{switch (config.link_mode) { @@ -7372,19 +7464,41 @@ pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Co /// Only valid to call during `update`. Automatically handles queuing up a /// linker worker task if there is not already one. -pub fn queueLinkTasks(comp: *Compilation, tasks: []const link.Task) void { - if (comp.link_task_queue.enqueue(comp.gpa, tasks) catch |err| switch (err) { +pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) void { + comp.link_task_queue.enqueuePrelink(comp, tasks) catch |err| switch (err) { error.OutOfMemory => return comp.setAllocFailure(), - }) { - comp.thread_pool.spawnWgId(&comp.link_task_wait_group, link.flushTaskQueue, .{comp}); + }; +} + +/// The reason for the double-queue here is that the first queue ensures any +/// resolve_type_fully tasks are complete before this dispatch function is called. +fn dispatchZcuLinkTask(comp: *Compilation, tid: usize, task: link.ZcuTask) void { + if (!comp.separateCodegenThreadOk()) { + assert(tid == 0); + if (task == .link_func) { + assert(task.link_func.mir.status.load(.monotonic) != .pending); + } + link.doZcuTask(comp, tid, task); + task.deinit(comp.zcu.?); + return; } + comp.link_task_queue.enqueueZcu(comp, task) catch |err| switch (err) { + error.OutOfMemory => { + task.deinit(comp.zcu.?); + comp.setAllocFailure(); + }, + }; } pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile { return .{ .full_object_path = .{ .root_dir = comp.dirs.local_cache, - .sub_path = try comp.gpa.dupe(u8, comp.cache_use.whole.bin_sub_path.?), + .sub_path = try std.fs.path.join(comp.gpa, &.{ + "o", + &Cache.binToHex(comp.digest.?), + comp.emit_bin.?, + }), }, .lock = comp.cache_use.whole.moveLock(), }; diff --git a/src/InternPool.zig b/src/InternPool.zig index de1a434c029e..7c3e52a8cf0b 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -3249,6 +3249,9 @@ pub const LoadedUnionType = struct { name: NullTerminatedString, /// Represents the declarations inside this union. namespace: NamespaceIndex, + /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. + /// Otherwise, this is `.none`. + name_nav: Nav.Index.Optional, /// The enum tag type. enum_tag_ty: Index, /// List of field types in declaration order. @@ -3567,6 +3570,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { .tid = unwrapped_index.tid, .extra_index = data, .name = type_union.data.name, + .name_nav = type_union.data.name_nav, .namespace = type_union.data.namespace, .enum_tag_ty = type_union.data.tag_ty, .field_types = field_types, @@ -3584,6 +3588,9 @@ pub const LoadedStructType = struct { /// The name of this struct type. name: NullTerminatedString, namespace: NamespaceIndex, + /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. + /// Otherwise, or if this is a file's root struct type, this is `.none`. + name_nav: Nav.Index.Optional, /// Index of the `struct_decl` or `reify` ZIR instruction. zir_index: TrackedInst.Index, layout: std.builtin.Type.ContainerLayout, @@ -4173,6 +4180,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { switch (item.tag) { .type_struct => { const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]); + const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?]); const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]); const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]); const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "fields_len").?]; @@ -4259,6 +4267,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { .tid = unwrapped_index.tid, .extra_index = item.data, .name = name, + .name_nav = name_nav, .namespace = namespace, .zir_index = zir_index, .layout = if (flags.is_extern) .@"extern" else .auto, @@ -4275,6 +4284,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { }, .type_struct_packed, .type_struct_packed_inits => { const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?]); + const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?]); const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]); const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?]; const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?]); @@ -4321,6 +4331,7 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { .tid = unwrapped_index.tid, .extra_index = item.data, .name = name, + .name_nav = name_nav, .namespace = namespace, .zir_index = zir_index, .layout = .@"packed", @@ -4345,6 +4356,9 @@ pub const LoadedEnumType = struct { name: NullTerminatedString, /// Represents the declarations inside this enum. namespace: NamespaceIndex, + /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. + /// Otherwise, this is `.none`. + name_nav: Nav.Index.Optional, /// An integer type which is used for the numerical value of the enum. /// This field is present regardless of whether the enum has an /// explicitly provided tag type or auto-numbered. @@ -4428,6 +4442,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { } else extra.data.captures_len; return .{ .name = extra.data.name, + .name_nav = extra.data.name_nav, .namespace = extra.data.namespace, .tag_ty = extra.data.int_tag_type, .names = .{ @@ -4462,6 +4477,7 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { } else extra.data.captures_len; return .{ .name = extra.data.name, + .name_nav = extra.data.name_nav, .namespace = extra.data.namespace, .tag_ty = extra.data.int_tag_type, .names = .{ @@ -4493,6 +4509,9 @@ pub const LoadedOpaqueType = struct { // TODO: the non-fqn will be needed by the new dwarf structure /// The name of this opaque type. name: NullTerminatedString, + /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. + /// Otherwise, this is `.none`. + name_nav: Nav.Index.Optional, /// Index of the `opaque_decl` or `reify` instruction. zir_index: TrackedInst.Index, captures: CaptureValue.Slice, @@ -4509,6 +4528,7 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType { extra.data.captures_len; return .{ .name = extra.data.name, + .name_nav = extra.data.name_nav, .namespace = extra.data.namespace, .zir_index = extra.data.zir_index, .captures = .{ @@ -6022,6 +6042,7 @@ pub const Tag = enum(u8) { /// 4. field align: Alignment for each field; declaration order pub const TypeUnion = struct { name: NullTerminatedString, + name_nav: Nav.Index.Optional, flags: Flags, /// This could be provided through the tag type, but it is more convenient /// to store it directly. This is also necessary for `dumpStatsFallible` to @@ -6061,6 +6082,7 @@ pub const Tag = enum(u8) { /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits pub const TypeStructPacked = struct { name: NullTerminatedString, + name_nav: Nav.Index.Optional, zir_index: TrackedInst.Index, fields_len: u32, namespace: NamespaceIndex, @@ -6108,6 +6130,7 @@ pub const Tag = enum(u8) { /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved pub const TypeStruct = struct { name: NullTerminatedString, + name_nav: Nav.Index.Optional, zir_index: TrackedInst.Index, namespace: NamespaceIndex, fields_len: u32, @@ -6151,6 +6174,7 @@ pub const Tag = enum(u8) { /// 0. capture: CaptureValue // for each `captures_len` pub const TypeOpaque = struct { name: NullTerminatedString, + name_nav: Nav.Index.Optional, /// Contains the declarations inside this opaque. namespace: NamespaceIndex, /// The index of the `opaque_decl` instruction. @@ -6429,6 +6453,7 @@ pub const Array = struct { /// 4. tag value: Index for each fields_len; declaration order pub const EnumExplicit = struct { name: NullTerminatedString, + name_nav: Nav.Index.Optional, /// `std.math.maxInt(u32)` indicates this type is reified. captures_len: u32, namespace: NamespaceIndex, @@ -6454,6 +6479,7 @@ pub const EnumExplicit = struct { /// 3. field name: NullTerminatedString for each fields_len; declaration order pub const EnumAuto = struct { name: NullTerminatedString, + name_nav: Nav.Index.Optional, /// `std.math.maxInt(u32)` indicates this type is reified. captures_len: u32, namespace: NamespaceIndex, @@ -8666,6 +8692,7 @@ pub fn getUnionType( .size = std.math.maxInt(u32), .padding = std.math.maxInt(u32), .name = undefined, // set by `finish` + .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` .tag_ty = ini.enum_tag_ty, .zir_index = switch (ini.key) { @@ -8717,6 +8744,7 @@ pub fn getUnionType( .tid = tid, .index = gop.put(), .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, + .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, } }; } @@ -8726,15 +8754,20 @@ pub const WipNamespaceType = struct { index: Index, type_name_extra_index: u32, namespace_extra_index: u32, + name_nav_extra_index: u32, pub fn setName( wip: WipNamespaceType, ip: *InternPool, type_name: NullTerminatedString, + /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise. + /// This is also `.none` if we use `.parent` because we are the root struct type for a file. + name_nav: Nav.Index.Optional, ) void { const extra = ip.getLocalShared(wip.tid).extra.acquire(); const extra_items = extra.view().items(.@"0"); extra_items[wip.type_name_extra_index] = @intFromEnum(type_name); + extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav); } pub fn finish( @@ -8843,6 +8876,7 @@ pub fn getStructType( ini.fields_len); // inits const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ .name = undefined, // set by `finish` + .name_nav = undefined, // set by `finish` .zir_index = zir_index, .fields_len = ini.fields_len, .namespace = undefined, // set by `finish` @@ -8887,6 +8921,7 @@ pub fn getStructType( .tid = tid, .index = gop.put(), .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, + .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?, .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, } }; }, @@ -8909,6 +8944,7 @@ pub fn getStructType( 1); // names_map const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ .name = undefined, // set by `finish` + .name_nav = undefined, // set by `finish` .zir_index = zir_index, .namespace = undefined, // set by `finish` .fields_len = ini.fields_len, @@ -8977,6 +9013,7 @@ pub fn getStructType( .tid = tid, .index = gop.put(), .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, + .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?, .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, } }; } @@ -9766,6 +9803,7 @@ pub const WipEnumType = struct { tag_ty_index: u32, type_name_extra_index: u32, namespace_extra_index: u32, + name_nav_extra_index: u32, names_map: MapIndex, names_start: u32, values_map: OptionalMapIndex, @@ -9775,10 +9813,13 @@ pub const WipEnumType = struct { wip: WipEnumType, ip: *InternPool, type_name: NullTerminatedString, + /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise. + name_nav: Nav.Index.Optional, ) void { const extra = ip.getLocalShared(wip.tid).extra.acquire(); const extra_items = extra.view().items(.@"0"); extra_items[wip.type_name_extra_index] = @intFromEnum(type_name); + extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav); } pub fn prepare( @@ -9893,6 +9934,7 @@ pub fn getEnumType( const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ .name = undefined, // set by `prepare` + .name_nav = undefined, // set by `prepare` .captures_len = switch (ini.key) { inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), .reified => std.math.maxInt(u32), @@ -9921,6 +9963,7 @@ pub fn getEnumType( .index = gop.put(), .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?, + .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name_nav").?, .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?, .names_map = names_map, .names_start = @intCast(names_start), @@ -9950,6 +9993,7 @@ pub fn getEnumType( const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{ .name = undefined, // set by `prepare` + .name_nav = undefined, // set by `prepare` .captures_len = switch (ini.key) { inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), .reified => std.math.maxInt(u32), @@ -9987,6 +10031,7 @@ pub fn getEnumType( .index = gop.put(), .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?, + .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name_nav").?, .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?, .names_map = names_map, .names_start = @intCast(names_start), @@ -10055,6 +10100,7 @@ pub fn getGeneratedTagEnumType( .tag = .type_enum_auto, .data = addExtraAssumeCapacity(extra, EnumAuto{ .name = ini.name, + .name_nav = .none, .captures_len = 0, .namespace = namespace, .int_tag_type = ini.tag_ty, @@ -10088,6 +10134,7 @@ pub fn getGeneratedTagEnumType( }, .data = addExtraAssumeCapacity(extra, EnumExplicit{ .name = ini.name, + .name_nav = .none, .captures_len = 0, .namespace = namespace, .int_tag_type = ini.tag_ty, @@ -10161,6 +10208,7 @@ pub fn getOpaqueType( }); const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{ .name = undefined, // set by `finish` + .name_nav = undefined, // set by `finish` .namespace = undefined, // set by `finish` .zir_index = switch (ini.key) { inline else => |x| x.zir_index, @@ -10183,6 +10231,7 @@ pub fn getOpaqueType( .tid = tid, .index = gop.put(), .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, + .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?, .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, }, }; @@ -10299,6 +10348,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { extra.appendAssumeCapacity(.{switch (field.type) { Index, Nav.Index, + Nav.Index.Optional, NamespaceIndex, OptionalNamespaceIndex, MapIndex, @@ -10361,6 +10411,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat @field(result, field.name) = switch (field.type) { Index, Nav.Index, + Nav.Index.Optional, NamespaceIndex, OptionalNamespaceIndex, MapIndex, diff --git a/src/Sema.zig b/src/Sema.zig index e20fb17f2626..5b3e6419a64d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2963,13 +2963,14 @@ fn zirStructDecl( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, try sema.createTypeName( + const type_name = try sema.createTypeName( block, small.name_strategy, "struct", inst, wip_ty.index, - )); + ); + wip_ty.setName(ip, type_name.name, type_name.nav); const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -2991,7 +2992,8 @@ fn zirStructDecl( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } try sema.declareDependency(.{ .interned = wip_ty.index }); try sema.addTypeReferenceEntry(src, wip_ty.index); @@ -3007,7 +3009,10 @@ pub fn createTypeName( inst: ?Zir.Inst.Index, /// This is used purely to give the type a unique name in the `anon` case. type_index: InternPool.Index, -) !InternPool.NullTerminatedString { +) !struct { + name: InternPool.NullTerminatedString, + nav: InternPool.Nav.Index.Optional, +} { const pt = sema.pt; const zcu = pt.zcu; const gpa = zcu.gpa; @@ -3015,7 +3020,10 @@ pub fn createTypeName( switch (name_strategy) { .anon => {}, // handled after switch - .parent => return block.type_name_ctx, + .parent => return .{ + .name = block.type_name_ctx, + .nav = sema.owner.unwrap().nav_val.toOptional(), + }, .func => func_strat: { const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); const zir_tags = sema.code.instructions.items(.tag); @@ -3057,7 +3065,10 @@ pub fn createTypeName( }; try writer.writeByte(')'); - return ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls); + return .{ + .name = try ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls), + .nav = .none, + }; }, .dbg_var => { // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. @@ -3066,9 +3077,12 @@ pub fn createTypeName( const zir_data = sema.code.instructions.items(.data); for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) { .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { - return ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{ - block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), - }, .no_embedded_nulls); + return .{ + .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{ + block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), + }, .no_embedded_nulls), + .nav = .none, + }; }, else => {}, }; @@ -3086,9 +3100,12 @@ pub fn createTypeName( // types appropriately. However, `@typeName` becomes a problem then. If we remove // that builtin from the language, we can consider this. - return ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{ - block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index), - }, .no_embedded_nulls); + return .{ + .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{ + block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index), + }, .no_embedded_nulls), + .nav = .none, + }; } fn zirEnumDecl( @@ -3209,7 +3226,7 @@ fn zirEnumDecl( inst, wip_ty.index, ); - wip_ty.setName(ip, type_name); + wip_ty.setName(ip, type_name.name, type_name.nav); const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -3236,7 +3253,7 @@ fn zirEnumDecl( inst, tracked_inst, new_namespace_index, - type_name, + type_name.name, small, body, tag_type_ref, @@ -3250,7 +3267,8 @@ fn zirEnumDecl( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } return Air.internedToRef(wip_ty.index); } @@ -3340,13 +3358,14 @@ fn zirUnionDecl( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, try sema.createTypeName( + const type_name = try sema.createTypeName( block, small.name_strategy, "union", inst, wip_ty.index, - )); + ); + wip_ty.setName(ip, type_name.name, type_name.nav); const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -3368,7 +3387,8 @@ fn zirUnionDecl( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } try sema.declareDependency(.{ .interned = wip_ty.index }); try sema.addTypeReferenceEntry(src, wip_ty.index); @@ -3432,13 +3452,14 @@ fn zirOpaqueDecl( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, try sema.createTypeName( + const type_name = try sema.createTypeName( block, small.name_strategy, "opaque", inst, wip_ty.index, - )); + ); + wip_ty.setName(ip, type_name.name, type_name.nav); const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -3455,7 +3476,8 @@ fn zirOpaqueDecl( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } try sema.addTypeReferenceEntry(src, wip_ty.index); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); @@ -20062,7 +20084,8 @@ fn structInitAnon( }, false)) { .wip => |wip| ty: { errdefer wip.cancel(ip, pt.tid); - wip.setName(ip, try sema.createTypeName(block, .anon, "struct", inst, wip.index)); + const type_name = try sema.createTypeName(block, .anon, "struct", inst, wip.index); + wip.setName(ip, type_name.name, type_name.nav); const struct_type = ip.loadStructType(wip.index); @@ -20086,7 +20109,8 @@ fn structInitAnon( codegen_type: { if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; - try zcu.comp.queueJob(.{ .codegen_type = wip.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip.index }); } if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); break :ty wip.finish(ip, new_namespace_index); @@ -21122,13 +21146,14 @@ fn zirReify( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, try sema.createTypeName( + const type_name = try sema.createTypeName( block, name_strategy, "opaque", inst, wip_ty.index, - )); + ); + wip_ty.setName(ip, type_name.name, type_name.nav); const new_namespace_index = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -21327,13 +21352,14 @@ fn reifyEnum( return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); } - wip_ty.setName(ip, try sema.createTypeName( + const type_name = try sema.createTypeName( block, name_strategy, "enum", inst, wip_ty.index, - )); + ); + wip_ty.setName(ip, type_name.name, type_name.nav); const new_namespace_index = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), @@ -21396,7 +21422,8 @@ fn reifyEnum( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } return Air.internedToRef(wip_ty.index); } @@ -21498,7 +21525,7 @@ fn reifyUnion( inst, wip_ty.index, ); - wip_ty.setName(ip, type_name); + wip_ty.setName(ip, type_name.name, type_name.nav); const field_types = try sema.arena.alloc(InternPool.Index, fields_len); const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined; @@ -21591,7 +21618,7 @@ fn reifyUnion( } } - const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name); + const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name); break :tag_ty .{ enum_tag_ty, false }; }; errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error @@ -21650,7 +21677,8 @@ fn reifyUnion( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } try sema.declareDependency(.{ .interned = wip_ty.index }); try sema.addTypeReferenceEntry(src, wip_ty.index); @@ -21853,13 +21881,14 @@ fn reifyStruct( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, try sema.createTypeName( + const type_name = try sema.createTypeName( block, name_strategy, "struct", inst, wip_ty.index, - )); + ); + wip_ty.setName(ip, type_name.name, type_name.nav); const struct_type = ip.loadStructType(wip_ty.index); @@ -22004,7 +22033,8 @@ fn reifyStruct( if (zcu.comp.config.use_llvm) break :codegen_type; if (block.ownerModule().strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } try sema.declareDependency(.{ .interned = wip_ty.index }); try sema.addTypeReferenceEntry(src, wip_ty.index); @@ -35032,7 +35062,7 @@ pub fn resolveUnionAlignment( union_type.setAlignment(ip, max_align); } -/// This logic must be kept in sync with `Zcu.getUnionLayout`. +/// This logic must be kept in sync with `Type.getUnionLayout`. pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { const pt = sema.pt; const ip = &pt.zcu.intern_pool; @@ -35066,24 +35096,32 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { var max_align: Alignment = .@"1"; for (0..union_type.field_types.len) |field_index| { const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]); - - if (try field_ty.comptimeOnlySema(pt) or field_ty.zigTypeTag(pt.zcu) == .noreturn) continue; // TODO: should this affect alignment? - - max_size = @max(max_size, field_ty.abiSizeSema(pt) catch |err| switch (err) { - error.AnalysisFail => { - const msg = sema.err orelse return err; - try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{}); - return err; - }, - else => return err, - }); + if (field_ty.isNoReturn(pt.zcu)) continue; + + // We need to call `hasRuntimeBits` before calling `abiSize` to prevent reachable `unreachable`s, + // but `hasRuntimeBits` only resolves field types and so may infinite recurse on a layout wip type, + // so we must resolve the layout manually first, instead of waiting for `abiSize` to do it for us. + // This is arguably just hacking around bugs in both `abiSize` for not allowing arbitrary types to + // be queried, enabling failures to be handled with the emission of a compile error, and also in + // `hasRuntimeBits` for ever being able to infinite recurse in the first place. + try field_ty.resolveLayout(pt); + + if (try field_ty.hasRuntimeBitsSema(pt)) { + max_size = @max(max_size, field_ty.abiSizeSema(pt) catch |err| switch (err) { + error.AnalysisFail => { + const msg = sema.err orelse return err; + try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{}); + return err; + }, + else => return err, + }); + } const explicit_align = union_type.fieldAlign(ip, field_index); const field_align = if (explicit_align != .none) explicit_align else try field_ty.abiAlignmentSema(pt); - max_align = max_align.max(field_align); } diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index 77065a07e8ec..8dfb710ac0a1 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -157,13 +157,14 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter )) { .wip => |wip| ty: { errdefer wip.cancel(ip, pt.tid); - wip.setName(ip, try self.sema.createTypeName( + const type_name = try self.sema.createTypeName( self.block, .anon, "struct", self.base_node_inst.resolve(ip), wip.index, - )); + ); + wip.setName(ip, type_name.name, type_name.nav); const struct_type = ip.loadStructType(wip.index); @@ -194,7 +195,8 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter codegen_type: { if (pt.zcu.comp.config.use_llvm) break :codegen_type; if (self.block.ownerModule().strip) break :codegen_type; - try pt.zcu.comp.queueJob(.{ .codegen_type = wip.index }); + pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try pt.zcu.comp.queueJob(.{ .link_type = wip.index }); } break :ty wip.finish(ip, new_namespace_index); }, diff --git a/src/ThreadSafeQueue.zig b/src/ThreadSafeQueue.zig deleted file mode 100644 index 74bbdc418f43..000000000000 --- a/src/ThreadSafeQueue.zig +++ /dev/null @@ -1,72 +0,0 @@ -const std = @import("std"); -const assert = std.debug.assert; -const Allocator = std.mem.Allocator; - -pub fn ThreadSafeQueue(comptime T: type) type { - return struct { - worker_owned: std.ArrayListUnmanaged(T), - /// Protected by `mutex`. - shared: std.ArrayListUnmanaged(T), - mutex: std.Thread.Mutex, - state: State, - - const Self = @This(); - - pub const State = enum { wait, run }; - - pub const empty: Self = .{ - .worker_owned = .empty, - .shared = .empty, - .mutex = .{}, - .state = .wait, - }; - - pub fn deinit(self: *Self, gpa: Allocator) void { - self.worker_owned.deinit(gpa); - self.shared.deinit(gpa); - self.* = undefined; - } - - /// Must be called from the worker thread. - pub fn check(self: *Self) ?[]T { - assert(self.worker_owned.items.len == 0); - { - self.mutex.lock(); - defer self.mutex.unlock(); - assert(self.state == .run); - if (self.shared.items.len == 0) { - self.state = .wait; - return null; - } - std.mem.swap(std.ArrayListUnmanaged(T), &self.worker_owned, &self.shared); - } - const result = self.worker_owned.items; - self.worker_owned.clearRetainingCapacity(); - return result; - } - - /// Adds items to the queue, returning true if and only if the worker - /// thread is waiting. Thread-safe. - /// Not safe to call from the worker thread. - pub fn enqueue(self: *Self, gpa: Allocator, items: []const T) error{OutOfMemory}!bool { - self.mutex.lock(); - defer self.mutex.unlock(); - try self.shared.appendSlice(gpa, items); - return switch (self.state) { - .run => false, - .wait => { - self.state = .run; - return true; - }, - }; - } - - /// Safe only to call exactly once when initially starting the worker. - pub fn start(self: *Self) bool { - assert(self.state == .wait); - if (self.shared.items.len == 0) return false; - self.state = .run; - return true; - } - }; -} diff --git a/src/Type.zig b/src/Type.zig index 00f1c701297b..eafdd65531c4 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -177,6 +177,7 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error const zcu = pt.zcu; const ip = &zcu.intern_pool; switch (ip.indexToKey(ty.toIntern())) { + .undef => return writer.writeAll("@as(type, undefined)"), .int_type => |int_type| { const sign_char: u8 = switch (int_type.signedness) { .signed => 'i', @@ -398,7 +399,6 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error }, // values, not types - .undef, .simple_value, .variable, .@"extern", @@ -3915,29 +3915,32 @@ fn resolveUnionInner( pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout { const ip = &zcu.intern_pool; assert(loaded_union.haveLayout(ip)); - var most_aligned_field: u32 = undefined; - var most_aligned_field_size: u64 = undefined; - var biggest_field: u32 = undefined; + var most_aligned_field: u32 = 0; + var most_aligned_field_align: InternPool.Alignment = .@"1"; + var most_aligned_field_size: u64 = 0; + var biggest_field: u32 = 0; var payload_size: u64 = 0; var payload_align: InternPool.Alignment = .@"1"; - for (loaded_union.field_types.get(ip), 0..) |field_ty, field_index| { - if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(zcu)) continue; + for (loaded_union.field_types.get(ip), 0..) |field_ty_ip_index, field_index| { + const field_ty: Type = .fromInterned(field_ty_ip_index); + if (field_ty.isNoReturn(zcu)) continue; const explicit_align = loaded_union.fieldAlign(ip, field_index); const field_align = if (explicit_align != .none) explicit_align else - Type.fromInterned(field_ty).abiAlignment(zcu); - const field_size = Type.fromInterned(field_ty).abiSize(zcu); + field_ty.abiAlignment(zcu); + const field_size = field_ty.abiSize(zcu); if (field_size > payload_size) { payload_size = field_size; biggest_field = @intCast(field_index); } - if (field_align.compare(.gte, payload_align)) { - payload_align = field_align; + if (field_size > 0 and field_align.compare(.gte, most_aligned_field_align)) { most_aligned_field = @intCast(field_index); + most_aligned_field_align = field_align; most_aligned_field_size = field_size; } + payload_align = payload_align.max(field_align); } const have_tag = loaded_union.flagsUnordered(ip).runtime_tag.hasTag(); if (!have_tag or !Type.fromInterned(loaded_union.enum_tag_ty).hasRuntimeBits(zcu)) { diff --git a/src/Zcu.zig b/src/Zcu.zig index 7223e5a55e04..513492e8187e 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -56,9 +56,8 @@ comptime { /// General-purpose allocator. Used for both temporary and long-term storage. gpa: Allocator, comp: *Compilation, -/// Usually, the LlvmObject is managed by linker code, however, in the case -/// that -fno-emit-bin is specified, the linker code never executes, so we -/// store the LlvmObject here. +/// If the ZCU is emitting an LLVM object (i.e. we are using the LLVM backend), then this is the +/// `LlvmObject` we are emitting to. llvm_object: ?LlvmObject.Ptr, /// Pointer to externally managed resource. @@ -67,8 +66,18 @@ root_mod: *Package.Module, /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests. main_mod: *Package.Module, std_mod: *Package.Module, -sema_prog_node: std.Progress.Node = std.Progress.Node.none, -codegen_prog_node: std.Progress.Node = std.Progress.Node.none, +sema_prog_node: std.Progress.Node = .none, +codegen_prog_node: std.Progress.Node = .none, +/// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value +/// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this +/// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is +/// completed (since semantic analysis could trigger more codegen work). +pending_codegen_jobs: std.atomic.Value(u32) = .init(0), + +/// This is the progress node *under* `sema_prog_node` which is currently running. +/// When we have to pause to analyze something else, we just temporarily rename this node. +/// Eventually, when we thread semantic analysis, we will want one of these per thread. +cur_sema_prog_node: std.Progress.Node = .none, /// Used by AstGen worker to load and store ZIR cache. global_zir_cache: Cache.Directory, @@ -172,6 +181,8 @@ transitive_failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .emp /// This `Nav` succeeded analysis, but failed codegen. /// This may be a simple "value" `Nav`, or it may be a function. /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. +/// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as +/// codegen and linking run on a separate thread. failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty, failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty, /// Keep track of `@compileLog`s per `AnalUnit`. @@ -267,16 +278,6 @@ resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = n /// Reset to `false` at the start of each update in `Compilation.update`. skip_analysis_this_update: bool = false, -stage1_flags: packed struct { - have_winmain: bool = false, - have_wwinmain: bool = false, - have_winmain_crt_startup: bool = false, - have_wwinmain_crt_startup: bool = false, - have_dllmain_crt_startup: bool = false, - have_c_main: bool = false, - reserved: u2 = 0, -} = .{}, - test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty, @@ -3828,7 +3829,36 @@ pub const Feature = enum { is_named_enum_value, error_set_has_value, field_reordering, - /// If the backend supports running from another thread. + /// In theory, backends are supposed to work like this: + /// + /// * The AIR emitted by `Sema` is converted into MIR by `codegen.generateFunction`. This pass + /// is "pure", in that it does not depend on or modify any external mutable state. + /// + /// * That MIR is sent to the linker, which calls `codegen.emitFunction` to convert the MIR to + /// finalized machine code. This process is permitted to query and modify linker state. + /// + /// * The linker stores the resulting machine code in the binary as needed. + /// + /// The first stage described above can run in parallel to the rest of the compiler, and even to + /// other code generation work; we can run as many codegen threads as we want in parallel because + /// of the fact that this pass is pure. Emit and link must be single-threaded, but are generally + /// very fast, so that isn't a problem. + /// + /// Unfortunately, some code generation implementations currently query and/or mutate linker state + /// or even (in the case of the LLVM backend) semantic analysis state. Such backends cannot be run + /// in parallel with each other, with linking, or (potentially) with semantic analysis. + /// + /// Additionally, some backends continue to need the AIR in the "emit" stage, despite this pass + /// operating on MIR. This complicates memory management under the threading model above. + /// + /// These are both **bugs** in backend implementations, left over from legacy code. However, they + /// are difficult to fix. So, this `Feature` currently guards correct threading of code generation: + /// + /// * With this feature enabled, the backend is threaded as described above. The "emit" stage does + /// not have access to AIR (it will be `undefined`; see `codegen.emitFunction`). + /// + /// * With this feature disabled, semantic analysis, code generation, and linking all occur on the + /// same thread, and the "emit" stage has access to AIR. separate_thread, }; @@ -4577,22 +4607,29 @@ pub fn codegenFail( comptime format: []const u8, args: anytype, ) CodegenFailError { - const gpa = zcu.gpa; - try zcu.failed_codegen.ensureUnusedCapacity(gpa, 1); - const msg = try Zcu.ErrorMsg.create(gpa, zcu.navSrcLoc(nav_index), format, args); - zcu.failed_codegen.putAssumeCapacityNoClobber(nav_index, msg); - return error.CodegenFail; + const msg = try Zcu.ErrorMsg.create(zcu.gpa, zcu.navSrcLoc(nav_index), format, args); + return zcu.codegenFailMsg(nav_index, msg); } +/// Takes ownership of `msg`, even on OOM. pub fn codegenFailMsg(zcu: *Zcu, nav_index: InternPool.Nav.Index, msg: *ErrorMsg) CodegenFailError { const gpa = zcu.gpa; { + zcu.comp.mutex.lock(); + defer zcu.comp.mutex.unlock(); errdefer msg.deinit(gpa); try zcu.failed_codegen.putNoClobber(gpa, nav_index, msg); } return error.CodegenFail; } +/// Asserts that `zcu.failed_codegen` contains the key `nav`, with the necessary lock held. +pub fn assertCodegenFailed(zcu: *Zcu, nav: InternPool.Nav.Index) void { + zcu.comp.mutex.lock(); + defer zcu.comp.mutex.unlock(); + assert(zcu.failed_codegen.contains(nav)); +} + pub fn codegenFailType( zcu: *Zcu, ty_index: InternPool.Index, @@ -4726,3 +4763,27 @@ fn explainWhyFileIsInModule( import = importer_ref.import; } } + +const SemaProgNode = struct { + /// `null` means we created the node, so should end it. + old_name: ?[std.Progress.Node.max_name_len]u8, + pub fn end(spn: SemaProgNode, zcu: *Zcu) void { + if (spn.old_name) |old_name| { + zcu.sema_prog_node.completeOne(); // we're just renaming, but it's effectively completion + zcu.cur_sema_prog_node.setName(&old_name); + } else { + zcu.cur_sema_prog_node.end(); + zcu.cur_sema_prog_node = .none; + } + } +}; +pub fn startSemaProgNode(zcu: *Zcu, name: []const u8) SemaProgNode { + if (zcu.cur_sema_prog_node.index != .none) { + const old_name = zcu.cur_sema_prog_node.getName(); + zcu.cur_sema_prog_node.setName(name); + return .{ .old_name = old_name }; + } else { + zcu.cur_sema_prog_node = zcu.sema_prog_node.start(name, 0); + return .{ .old_name = null }; + } +} diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 8b35d8d7999f..4d9087842007 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -27,6 +27,7 @@ const Type = @import("../Type.zig"); const Value = @import("../Value.zig"); const Zcu = @import("../Zcu.zig"); const Compilation = @import("../Compilation.zig"); +const codegen = @import("../codegen.zig"); const Zir = std.zig.Zir; const Zoir = std.zig.Zoir; const ZonGen = std.zig.ZonGen; @@ -795,8 +796,8 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU info.deps.clearRetainingCapacity(); } - const unit_prog_node = zcu.sema_prog_node.start("comptime", 0); - defer unit_prog_node.end(); + const unit_prog_node = zcu.startSemaProgNode("comptime"); + defer unit_prog_node.end(zcu); return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) { error.AnalysisFail => { @@ -975,8 +976,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu info.deps.clearRetainingCapacity(); } - const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0); - defer unit_prog_node.end(); + const unit_prog_node = zcu.startSemaProgNode(nav.fqn.toSlice(ip)); + defer unit_prog_node.end(zcu); const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: { break :res .{ @@ -1320,7 +1321,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr } // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_nav = nav_id }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_nav = nav_id }); } switch (old_nav.status) { @@ -1395,8 +1397,8 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc info.deps.clearRetainingCapacity(); } - const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0); - defer unit_prog_node.end(); + const unit_prog_node = zcu.startSemaProgNode(nav.fqn.toSlice(ip)); + defer unit_prog_node.end(zcu); const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id)) |result| res: { break :res .{ @@ -1616,8 +1618,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter info.deps.clearRetainingCapacity(); } - const func_prog_node = zcu.sema_prog_node.start(ip.getNav(func.owner_nav).fqn.toSlice(ip), 0); - defer func_prog_node.end(); + const func_prog_node = zcu.startSemaProgNode(ip.getNav(func.owner_nav).fqn.toSlice(ip)); + defer func_prog_node.end(zcu); const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index)) |result| .{ prev_failed or result.ies_outdated, false } @@ -1716,6 +1718,8 @@ fn analyzeFuncBody( } // This job depends on any resolve_type_fully jobs queued up before it. + zcu.codegen_prog_node.increaseEstimatedTotalItems(1); + comp.link_prog_node.increaseEstimatedTotalItems(1); try comp.queueJob(.{ .codegen_func = .{ .func = func_index, .air = air, @@ -1724,87 +1728,6 @@ fn analyzeFuncBody( return .{ .ies_outdated = ies_outdated }; } -/// Takes ownership of `air`, even on error. -/// If any types referenced by `air` are unresolved, marks the codegen as failed. -pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) Allocator.Error!void { - const zcu = pt.zcu; - const gpa = zcu.gpa; - const ip = &zcu.intern_pool; - const comp = zcu.comp; - - const func = zcu.funcInfo(func_index); - const nav_index = func.owner_nav; - const nav = ip.getNav(nav_index); - - const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0); - defer codegen_prog_node.end(); - - if (!air.typesFullyResolved(zcu)) { - // A type we depend on failed to resolve. This is a transitive failure. - // Correcting this failure will involve changing a type this function - // depends on, hence triggering re-analysis of this function, so this - // interacts correctly with incremental compilation. - return; - } - - legalize: { - try air.legalize(pt, @import("../codegen.zig").legalizeFeatures(pt, nav_index) orelse break :legalize); - } - - var liveness = try Air.Liveness.analyze(zcu, air.*, ip); - defer liveness.deinit(gpa); - - if (build_options.enable_debug_extensions and comp.verbose_air) { - std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)}); - air.dump(pt, liveness); - std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)}); - } - - if (std.debug.runtime_safety) { - var verify: Air.Liveness.Verify = .{ - .gpa = gpa, - .zcu = zcu, - .air = air.*, - .liveness = liveness, - .intern_pool = ip, - }; - defer verify.deinit(); - - verify.verify() catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => { - try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( - gpa, - zcu.navSrcLoc(nav_index), - "invalid liveness: {s}", - .{@errorName(err)}, - )); - return; - }, - }; - } - - if (comp.bin_file) |lf| { - lf.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), - error.Overflow, error.RelocationNotByteAligned => { - try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( - gpa, - zcu.navSrcLoc(nav_index), - "unable to codegen: {s}", - .{@errorName(err)}, - )); - // Not a retryable failure. - }, - }; - } else if (zcu.llvm_object) |llvm_object| { - llvm_object.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - }; - } -} - pub fn semaMod(pt: Zcu.PerThread, mod: *Module) !void { dev.check(.sema); const file_index = pt.zcu.module_roots.get(mod).?.unwrap().?; @@ -1867,7 +1790,7 @@ fn createFileRootStruct( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, try file.internFullyQualifiedName(pt)); + wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none); ip.namespacePtr(namespace_index).owner_type = wip_ty.index; if (zcu.comp.incremental) { @@ -1877,10 +1800,10 @@ fn createFileRootStruct( try pt.scanNamespace(namespace_index, decls); try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); codegen_type: { - if (zcu.comp.config.use_llvm) break :codegen_type; if (file.mod.?.strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } zcu.setFileRootType(file_index, wip_ty.index); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); @@ -2574,7 +2497,7 @@ fn newEmbedFile( cache: { const whole = switch (zcu.comp.cache_use) { .whole => |whole| whole, - .incremental => break :cache, + .incremental, .none => break :cache, }; const man = whole.cache_manifest orelse break :cache; const ip_str = opt_ip_str orelse break :cache; // this will be a compile error @@ -2974,17 +2897,10 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE runtime_params_len; var runtime_param_index: usize = 0; - for (fn_info.param_body[0..src_params_len]) |inst| { + for (fn_info.param_body[0..src_params_len], 0..) |inst, zir_param_index| { const gop = sema.inst_map.getOrPutAssumeCapacity(inst); if (gop.found_existing) continue; // provided above by comptime arg - const param_inst_info = sema.code.instructions.get(@intFromEnum(inst)); - const param_name: Zir.NullTerminatedString = switch (param_inst_info.tag) { - .param_anytype => param_inst_info.data.str_tok.start, - .param => sema.code.extraData(Zir.Inst.Param, param_inst_info.data.pl_tok.payload_index).data.name, - else => unreachable, - }; - const param_ty = fn_ty_info.param_types.get(ip)[runtime_param_index]; runtime_param_index += 1; @@ -3004,10 +2920,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE .tag = .arg, .data = .{ .arg = .{ .ty = Air.internedToRef(param_ty), - .name = if (inner_block.ownerModule().strip) - .none - else - try sema.appendAirString(sema.code.nullTerminatedString(param_name)), + .zir_param_index = @intCast(zir_param_index), } }, }); } @@ -3189,7 +3102,9 @@ pub fn processExports(pt: Zcu.PerThread) !void { // This export might already have been sent to the linker on a previous update, in which case we need to delete it. // The linker export API should be modified to eliminate this call. #23616 if (zcu.comp.bin_file) |lf| { - lf.deleteExport(exp.exported, exp.opts.name); + if (zcu.llvm_object == null) { + lf.deleteExport(exp.exported, exp.opts.name); + } } continue; } @@ -3213,8 +3128,10 @@ pub fn processExports(pt: Zcu.PerThread) !void { // This export might already have been sent to the linker on a previous update, in which case we need to delete it. // The linker export API should be modified to eliminate this loop. #23616 if (zcu.comp.bin_file) |lf| { - for (exports) |exp| { - lf.deleteExport(exp.exported, exp.opts.name); + if (zcu.llvm_object == null) { + for (exports) |exp| { + lf.deleteExport(exp.exported, exp.opts.name); + } } } continue; @@ -3309,46 +3226,49 @@ fn processExportsInner( .uav => {}, } - if (zcu.comp.bin_file) |lf| { - try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices)); - } else if (zcu.llvm_object) |llvm_object| { + if (zcu.llvm_object) |llvm_object| { try zcu.handleUpdateExports(export_indices, llvm_object.updateExports(pt, exported, export_indices)); + } else if (zcu.comp.bin_file) |lf| { + try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices)); } } -pub fn populateTestFunctions( - pt: Zcu.PerThread, - main_progress_node: std.Progress.Node, -) Allocator.Error!void { +pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void { const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; + + // Our job is to correctly set the value of the `test_functions` declaration if it has been + // analyzed and sent to codegen, It usually will have been, because the test runner will + // reference it, and `std.builtin` shouldn't have type errors. However, if it hasn't been + // analyzed, we will just terminate early, since clearly the test runner hasn't referenced + // `test_functions` so there's no point populating it. More to the the point, we potentially + // *can't* populate it without doing some type resolution, and... let's try to leave Sema in + // the past here. + const builtin_mod = zcu.builtin_modules.get(zcu.root_mod.getBuiltinOptions(zcu.comp.config).hash()).?; const builtin_file_index = zcu.module_roots.get(builtin_mod).?.unwrap().?; - pt.ensureFileAnalyzed(builtin_file_index) catch |err| switch (err) { - error.AnalysisFail => unreachable, // builtin module is generated so cannot be corrupt - error.OutOfMemory => |e| return e, - }; - const builtin_root_type = Type.fromInterned(zcu.fileRootType(builtin_file_index)); - const builtin_namespace = builtin_root_type.getNamespace(zcu).unwrap().?; + const builtin_root_type = zcu.fileRootType(builtin_file_index); + if (builtin_root_type == .none) return; // `@import("builtin")` never analyzed + const builtin_namespace = Type.fromInterned(builtin_root_type).getNamespace(zcu).unwrap().?; + // We know that the namespace has a `test_functions`... const nav_index = zcu.namespacePtr(builtin_namespace).pub_decls.getKeyAdapted( try ip.getOrPutString(gpa, pt.tid, "test_functions", .no_embedded_nulls), Zcu.Namespace.NameAdapter{ .zcu = zcu }, ).?; + // ...but it might not be populated, so let's check that! + if (zcu.failed_analysis.contains(.wrap(.{ .nav_val = nav_index })) or + zcu.transitive_failed_analysis.contains(.wrap(.{ .nav_val = nav_index })) or + ip.getNav(nav_index).status != .fully_resolved) { - // We have to call `ensureNavValUpToDate` here in case `builtin.test_functions` - // was not referenced by start code. - zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); - defer { - zcu.sema_prog_node.end(); - zcu.sema_prog_node = std.Progress.Node.none; - } - pt.ensureNavValUpToDate(nav_index) catch |err| switch (err) { - error.AnalysisFail => return, - error.OutOfMemory => return error.OutOfMemory, - }; + // The value of `builtin.test_functions` was either never referenced, or failed analysis. + // Either way, we don't need to do anything. + return; } + // Okay, `builtin.test_functions` is (potentially) referenced and valid. Our job now is to swap + // its placeholder `&.{}` value for the actual list of all test functions. + const test_fns_val = zcu.navValue(nav_index); const test_fn_ty = test_fns_val.typeOf(zcu).slicePtrFieldType(zcu).childType(zcu); @@ -3450,81 +3370,8 @@ pub fn populateTestFunctions( } }); ip.mutateVarInit(test_fns_val.toIntern(), new_init); } - { - zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0); - defer { - zcu.codegen_prog_node.end(); - zcu.codegen_prog_node = std.Progress.Node.none; - } - - try pt.linkerUpdateNav(nav_index); - } -} - -pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{OutOfMemory}!void { - const zcu = pt.zcu; - const comp = zcu.comp; - const gpa = zcu.gpa; - const ip = &zcu.intern_pool; - - const nav = zcu.intern_pool.getNav(nav_index); - const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0); - defer codegen_prog_node.end(); - - if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) { - // The value of this nav failed to resolve. This is a transitive failure. - // TODO: do we need to mark this failure anywhere? I don't think so, since compilation - // will fail due to the type error anyway. - } else if (comp.bin_file) |lf| { - lf.updateNav(pt, nav_index) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), - error.Overflow, error.RelocationNotByteAligned => { - try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( - gpa, - zcu.navSrcLoc(nav_index), - "unable to codegen: {s}", - .{@errorName(err)}, - )); - // Not a retryable failure. - }, - }; - } else if (zcu.llvm_object) |llvm_object| { - llvm_object.updateNav(pt, nav_index) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - }; - } -} - -pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) error{OutOfMemory}!void { - const zcu = pt.zcu; - const gpa = zcu.gpa; - const comp = zcu.comp; - const ip = &zcu.intern_pool; - - const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0); - defer codegen_prog_node.end(); - - if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(gpa); - - if (!Air.typeFullyResolved(Type.fromInterned(ty), zcu)) { - // This type failed to resolve. This is a transitive failure. - return; - } - - if (comp.bin_file) |lf| lf.updateContainerType(pt, ty) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.TypeFailureReported => assert(zcu.failed_types.contains(ty)), - }; -} - -pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Index) !void { - if (pt.zcu.comp.bin_file) |lf| { - lf.updateLineNumber(pt, ti) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => |e| log.err("update line number failed: {s}", .{@errorName(e)}), - }; - } + // The linker thread is not running, so we actually need to dispatch this task directly. + @import("../link.zig").linkTestFunctionsNav(pt, nav_index); } /// Stores an error in `pt.zcu.failed_files` for this file, and sets the file @@ -3984,7 +3831,8 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error! const result = try pt.zcu.intern_pool.getExtern(pt.zcu.gpa, pt.tid, key); if (result.new_nav.unwrap()) |nav| { // This job depends on any resolve_type_fully jobs queued up before it. - try pt.zcu.comp.queueJob(.{ .codegen_nav = nav }); + pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try pt.zcu.comp.queueJob(.{ .link_nav = nav }); if (pt.zcu.comp.debugIncremental()) try pt.zcu.incremental_debug_state.newNav(pt.zcu, nav); } return result.index; @@ -4122,17 +3970,17 @@ fn recreateStructType( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, struct_obj.name); + wip_ty.setName(ip, struct_obj.name, struct_obj.name_nav); try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index }); zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index; // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); codegen_type: { - if (zcu.comp.config.use_llvm) break :codegen_type; if (file.mod.?.strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); @@ -4215,17 +4063,17 @@ fn recreateUnionType( }; errdefer wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, union_obj.name); + wip_ty.setName(ip, union_obj.name, union_obj.name_nav); try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index }); zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive. try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); codegen_type: { - if (zcu.comp.config.use_llvm) break :codegen_type; if (file.mod.?.strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. - try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); + zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); + try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); } if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); @@ -4325,7 +4173,7 @@ fn recreateEnumType( var done = true; errdefer if (!done) wip_ty.cancel(ip, pt.tid); - wip_ty.setName(ip, enum_obj.name); + wip_ty.setName(ip, enum_obj.name, enum_obj.name_nav); zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive. @@ -4518,3 +4366,128 @@ pub fn addDependency(pt: Zcu.PerThread, unit: AnalUnit, dependee: InternPool.Dep try info.deps.append(gpa, dependee); } } + +/// Performs code generation, which comes after `Sema` but before `link` in the pipeline. +/// This part of the pipeline is self-contained/"pure", so can be run in parallel with most +/// other code. This function is currently run either on the main thread, or on a separate +/// codegen thread, depending on whether the backend supports `Zcu.Feature.separate_thread`. +pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air, out: *@import("../link.zig").ZcuTask.LinkFunc.SharedMir) void { + const zcu = pt.zcu; + if (runCodegenInner(pt, func_index, air)) |mir| { + out.value = mir; + out.status.store(.ready, .release); + } else |err| switch (err) { + error.OutOfMemory => { + zcu.comp.setAllocFailure(); + out.status.store(.failed, .monotonic); + }, + error.CodegenFail => { + zcu.assertCodegenFailed(zcu.funcInfo(func_index).owner_nav); + out.status.store(.failed, .monotonic); + }, + error.NoLinkFile => { + assert(zcu.comp.bin_file == null); + out.status.store(.failed, .monotonic); + }, + error.BackendDoesNotProduceMir => { + const backend = target_util.zigBackend(zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); + switch (backend) { + else => unreachable, // assertion failure + .stage2_spirv64, + .stage2_llvm, + => {}, + } + out.status.store(.failed, .monotonic); + }, + } + zcu.comp.link_task_queue.mirReady(zcu.comp, out); + if (zcu.pending_codegen_jobs.rmw(.Sub, 1, .monotonic) == 1) { + // Decremented to 0, so all done. + zcu.codegen_prog_node.end(); + zcu.codegen_prog_node = .none; + } +} +fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) error{ + OutOfMemory, + CodegenFail, + NoLinkFile, + BackendDoesNotProduceMir, +}!codegen.AnyMir { + const zcu = pt.zcu; + const gpa = zcu.gpa; + const ip = &zcu.intern_pool; + const comp = zcu.comp; + + const nav = zcu.funcInfo(func_index).owner_nav; + const fqn = ip.getNav(nav).fqn; + + const codegen_prog_node = zcu.codegen_prog_node.start(fqn.toSlice(ip), 0); + defer codegen_prog_node.end(); + + if (codegen.legalizeFeatures(pt, nav)) |features| { + try air.legalize(pt, features); + } + + var liveness: Air.Liveness = try .analyze(zcu, air.*, ip); + defer liveness.deinit(gpa); + + if (build_options.enable_debug_extensions and comp.verbose_air) { + std.debug.lockStdErr(); + defer std.debug.unlockStdErr(); + const stderr = std.io.getStdErr().writer(); + stderr.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)}) catch {}; + air.write(stderr, pt, liveness); + stderr.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)}) catch {}; + } + + if (std.debug.runtime_safety) { + var verify: Air.Liveness.Verify = .{ + .gpa = gpa, + .zcu = zcu, + .air = air.*, + .liveness = liveness, + .intern_pool = ip, + }; + defer verify.deinit(); + + verify.verify() catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => return zcu.codegenFail(nav, "invalid liveness: {s}", .{@errorName(err)}), + }; + } + + // The LLVM backend is special, because we only need to do codegen. There is no equivalent to the + // "emit" step because LLVM does not support incremental linking. Our linker (LLD or self-hosted) + // will just see the ZCU object file which LLVM ultimately emits. + if (zcu.llvm_object) |llvm_object| { + assert(pt.tid == .main); // LLVM has a lot of shared state + try llvm_object.updateFunc(pt, func_index, air, &liveness); + return error.BackendDoesNotProduceMir; + } + + const lf = comp.bin_file orelse return error.NoLinkFile; + + // TODO: self-hosted codegen should always have a type of MIR; codegen should produce that MIR, + // and the linker should consume it. However, our SPIR-V backend is currently tightly coupled + // with our SPIR-V linker, so needs to work more like the LLVM backend. This should be fixed to + // unblock threaded codegen for SPIR-V. + if (lf.cast(.spirv)) |spirv_file| { + assert(pt.tid == .main); // SPIR-V has a lot of shared state + spirv_file.object.updateFunc(pt, func_index, air, &liveness) catch |err| { + switch (err) { + error.OutOfMemory => comp.link_diags.setAllocFailure(), + } + return error.CodegenFail; + }; + return error.BackendDoesNotProduceMir; + } + + return codegen.generateFunction(lf, pt, zcu.navSrcLoc(nav), func_index, air, &liveness) catch |err| switch (err) { + error.OutOfMemory, + error.CodegenFail, + => |e| return e, + error.Overflow, + error.RelocationNotByteAligned, + => return zcu.codegenFail(nav, "unable to codegen: {s}", .{@errorName(err)}), + }; +} diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 00cceb0c6775..4aaf6bf85c32 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -49,7 +49,6 @@ pt: Zcu.PerThread, air: Air, liveness: Air.Liveness, bin_file: *link.File, -debug_output: link.File.DebugInfoOutput, target: *const std.Target, func_index: InternPool.Index, owner_nav: InternPool.Nav.Index, @@ -185,6 +184,9 @@ const DbgInfoReloc = struct { } fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) !void { + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (function.debug_output) { .dwarf => |dw| { const loc: link.File.Dwarf.Loc = switch (reloc.mcv) { @@ -213,6 +215,9 @@ const DbgInfoReloc = struct { } fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (function.debug_output) { .dwarf => |dwarf| { const loc: link.File.Dwarf.Loc = switch (reloc.mcv) { @@ -326,11 +331,9 @@ pub fn generate( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, - code: *std.ArrayListUnmanaged(u8), - debug_output: link.File.DebugInfoOutput, -) CodeGenError!void { + air: *const Air, + liveness: *const Air.Liveness, +) CodeGenError!Mir { const zcu = pt.zcu; const gpa = zcu.gpa; const func = zcu.funcInfo(func_index); @@ -349,9 +352,8 @@ pub fn generate( var function: Self = .{ .gpa = gpa, .pt = pt, - .air = air, - .liveness = liveness, - .debug_output = debug_output, + .air = air.*, + .liveness = liveness.*, .target = target, .bin_file = lf, .func_index = func_index, @@ -395,29 +397,13 @@ pub fn generate( var mir: Mir = .{ .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(gpa), - }; - defer mir.deinit(gpa); - - var emit: Emit = .{ - .mir = mir, - .bin_file = lf, - .debug_output = debug_output, - .target = target, - .src_loc = src_loc, - .code = code, - .prev_di_pc = 0, - .prev_di_line = func.lbrace_line, - .prev_di_column = func.lbrace_column, - .stack_size = function.max_end_stack, + .extra = &.{}, // fallible, so assign after errdefer + .max_end_stack = function.max_end_stack, .saved_regs_stack_space = function.saved_regs_stack_space, }; - defer emit.deinit(); - - emit.emitMir() catch |err| switch (err) { - error.EmitFail => return function.failMsg(emit.err_msg.?), - else => |e| return e, - }; + errdefer mir.deinit(gpa); + mir.extra = try function.mir_extra.toOwnedSlice(gpa); + return mir; } fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { @@ -4222,15 +4208,22 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void { while (self.args[arg_index] == .none) arg_index += 1; self.arg_index = arg_index + 1; - const ty = self.typeOfIndex(inst); - const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; - const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{ - .tag = tag, - .ty = ty, - .name = name.toSlice(self.air), - .mcv = self.args[arg_index], - }); + const zcu = self.pt.zcu; + const func_zir = zcu.funcInfo(self.func_index).zir_body_inst.resolveFull(&zcu.intern_pool).?; + const file = zcu.fileByIndex(func_zir.file); + if (!file.mod.?.strip) { + const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; + const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; + const ty = self.typeOfIndex(inst); + const zir = &file.zir.?; + const name = zir.nullTerminatedString(zir.getParamName(zir.getParamBody(func_zir.inst)[arg.zir_param_index]).?); + try self.dbg_info_relocs.append(self.gpa, .{ + .tag = tag, + .ty = ty, + .name = name, + .mcv = self.args[arg_index], + }); + } const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index]; return self.finishAir(inst, result, .{ .none, .none, .none }); diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index edf05f625e10..88089c84883b 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -13,6 +13,14 @@ const assert = std.debug.assert; const bits = @import("bits.zig"); const Register = bits.Register; +const InternPool = @import("../../InternPool.zig"); +const Emit = @import("Emit.zig"); +const codegen = @import("../../codegen.zig"); +const link = @import("../../link.zig"); +const Zcu = @import("../../Zcu.zig"); + +max_end_stack: u32, +saved_regs_stack_space: u32, instructions: std.MultiArrayList(Inst).Slice, /// The meaning of this data is determined by `Inst.Tag` value. @@ -498,6 +506,39 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { mir.* = undefined; } +pub fn emit( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) codegen.CodeGenError!void { + const zcu = pt.zcu; + const func = zcu.funcInfo(func_index); + const nav = func.owner_nav; + const mod = zcu.navFileScope(nav).mod.?; + var e: Emit = .{ + .mir = mir, + .bin_file = lf, + .debug_output = debug_output, + .target = &mod.resolved_target.result, + .src_loc = src_loc, + .code = code, + .prev_di_pc = 0, + .prev_di_line = func.lbrace_line, + .prev_di_column = func.lbrace_column, + .stack_size = mir.max_end_stack, + .saved_regs_stack_space = mir.saved_regs_stack_space, + }; + defer e.deinit(); + e.emitMir() catch |err| switch (err) { + error.EmitFail => return zcu.codegenFailMsg(nav, e.err_msg.?), + else => |e1| return e1, + }; +} + /// Returns the requested data, as well as the new index which is at the start of the /// trailers for the object. pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 421ba7d75338..09304bf1def9 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -50,7 +50,6 @@ pt: Zcu.PerThread, air: Air, liveness: Air.Liveness, bin_file: *link.File, -debug_output: link.File.DebugInfoOutput, target: *const std.Target, func_index: InternPool.Index, err_msg: ?*ErrorMsg, @@ -264,6 +263,9 @@ const DbgInfoReloc = struct { } fn genArgDbgInfo(reloc: DbgInfoReloc, function: Self) !void { + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (function.debug_output) { .dwarf => |dw| { const loc: link.File.Dwarf.Loc = switch (reloc.mcv) { @@ -292,6 +294,9 @@ const DbgInfoReloc = struct { } fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void { + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (function.debug_output) { .dwarf => |dw| { const loc: link.File.Dwarf.Loc = switch (reloc.mcv) { @@ -335,11 +340,9 @@ pub fn generate( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, - code: *std.ArrayListUnmanaged(u8), - debug_output: link.File.DebugInfoOutput, -) CodeGenError!void { + air: *const Air, + liveness: *const Air.Liveness, +) CodeGenError!Mir { const zcu = pt.zcu; const gpa = zcu.gpa; const func = zcu.funcInfo(func_index); @@ -358,11 +361,10 @@ pub fn generate( var function: Self = .{ .gpa = gpa, .pt = pt, - .air = air, - .liveness = liveness, + .air = air.*, + .liveness = liveness.*, .target = target, .bin_file = lf, - .debug_output = debug_output, .func_index = func_index, .err_msg = null, .args = undefined, // populated after `resolveCallingConventionValues` @@ -402,31 +404,15 @@ pub fn generate( return function.fail("failed to generate debug info: {s}", .{@errorName(err)}); } - var mir = Mir{ + var mir: Mir = .{ .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(gpa), - }; - defer mir.deinit(gpa); - - var emit = Emit{ - .mir = mir, - .bin_file = lf, - .debug_output = debug_output, - .target = target, - .src_loc = src_loc, - .code = code, - .prev_di_pc = 0, - .prev_di_line = func.lbrace_line, - .prev_di_column = func.lbrace_column, - .stack_size = function.max_end_stack, + .extra = &.{}, // fallible, so assign after errdefer + .max_end_stack = function.max_end_stack, .saved_regs_stack_space = function.saved_regs_stack_space, }; - defer emit.deinit(); - - emit.emitMir() catch |err| switch (err) { - error.EmitFail => return function.failMsg(emit.err_msg.?), - else => |e| return e, - }; + errdefer mir.deinit(gpa); + mir.extra = try function.mir_extra.toOwnedSlice(gpa); + return mir; } fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { @@ -4205,16 +4191,22 @@ 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 ty = self.typeOfIndex(inst); - const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; - - const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - if (name != .none) try self.dbg_info_relocs.append(self.gpa, .{ - .tag = tag, - .ty = ty, - .name = name.toSlice(self.air), - .mcv = self.args[arg_index], - }); + const zcu = self.pt.zcu; + const func_zir = zcu.funcInfo(self.func_index).zir_body_inst.resolveFull(&zcu.intern_pool).?; + const file = zcu.fileByIndex(func_zir.file); + if (!file.mod.?.strip) { + const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; + const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; + const ty = self.typeOfIndex(inst); + const zir = &file.zir.?; + const name = zir.nullTerminatedString(zir.getParamName(zir.getParamBody(func_zir.inst)[arg.zir_param_index]).?); + try self.dbg_info_relocs.append(self.gpa, .{ + .tag = tag, + .ty = ty, + .name = name, + .mcv = self.args[arg_index], + }); + } const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index]; return self.finishAir(inst, result, .{ .none, .none, .none }); diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig index 5e651b793914..5b7585a2ca9c 100644 --- a/src/arch/arm/Mir.zig +++ b/src/arch/arm/Mir.zig @@ -13,6 +13,14 @@ const assert = std.debug.assert; const bits = @import("bits.zig"); const Register = bits.Register; +const InternPool = @import("../../InternPool.zig"); +const Emit = @import("Emit.zig"); +const codegen = @import("../../codegen.zig"); +const link = @import("../../link.zig"); +const Zcu = @import("../../Zcu.zig"); + +max_end_stack: u32, +saved_regs_stack_space: u32, instructions: std.MultiArrayList(Inst).Slice, /// The meaning of this data is determined by `Inst.Tag` value. @@ -278,6 +286,39 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { mir.* = undefined; } +pub fn emit( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) codegen.CodeGenError!void { + const zcu = pt.zcu; + const func = zcu.funcInfo(func_index); + const nav = func.owner_nav; + const mod = zcu.navFileScope(nav).mod.?; + var e: Emit = .{ + .mir = mir, + .bin_file = lf, + .debug_output = debug_output, + .target = &mod.resolved_target.result, + .src_loc = src_loc, + .code = code, + .prev_di_pc = 0, + .prev_di_line = func.lbrace_line, + .prev_di_column = func.lbrace_column, + .stack_size = mir.max_end_stack, + .saved_regs_stack_space = mir.saved_regs_stack_space, + }; + defer e.deinit(); + e.emitMir() catch |err| switch (err) { + error.EmitFail => return zcu.codegenFailMsg(nav, e.err_msg.?), + else => |e1| return e1, + }; +} + /// Returns the requested data, as well as the new index which is at the start of the /// trailers for the object. pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { diff --git a/src/arch/powerpc/CodeGen.zig b/src/arch/powerpc/CodeGen.zig index 0cfee67ebdbd..4964fe19f484 100644 --- a/src/arch/powerpc/CodeGen.zig +++ b/src/arch/powerpc/CodeGen.zig @@ -19,19 +19,15 @@ pub fn generate( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, - code: *std.ArrayListUnmanaged(u8), - debug_output: link.File.DebugInfoOutput, -) codegen.CodeGenError!void { + air: *const Air, + liveness: *const Air.Liveness, +) codegen.CodeGenError!noreturn { _ = bin_file; _ = pt; _ = src_loc; _ = func_index; _ = air; _ = liveness; - _ = code; - _ = debug_output; unreachable; } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 9fc51bd2d3d2..c82061a5ddc8 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -68,9 +68,9 @@ gpa: Allocator, mod: *Package.Module, target: *const std.Target, -debug_output: link.File.DebugInfoOutput, args: []MCValue, ret_mcv: InstTracking, +func_index: InternPool.Index, fn_type: Type, arg_index: usize, src_loc: Zcu.LazySrcLoc, @@ -746,13 +746,10 @@ pub fn generate( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, - code: *std.ArrayListUnmanaged(u8), - debug_output: link.File.DebugInfoOutput, -) CodeGenError!void { + air: *const Air, + liveness: *const Air.Liveness, +) CodeGenError!Mir { const zcu = pt.zcu; - const comp = zcu.comp; const gpa = zcu.gpa; const ip = &zcu.intern_pool; const func = zcu.funcInfo(func_index); @@ -769,16 +766,16 @@ pub fn generate( var function: Func = .{ .gpa = gpa, - .air = air, + .air = air.*, .pt = pt, .mod = mod, .bin_file = bin_file, - .liveness = liveness, + .liveness = liveness.*, .target = &mod.resolved_target.result, - .debug_output = debug_output, .owner = .{ .nav_index = func.owner_nav }, .args = undefined, // populated after `resolveCallingConventionValues` .ret_mcv = undefined, // populated after `resolveCallingConventionValues` + .func_index = func_index, .fn_type = fn_type, .arg_index = 0, .branch_stack = &branch_stack, @@ -855,33 +852,8 @@ pub fn generate( .instructions = function.mir_instructions.toOwnedSlice(), .frame_locs = function.frame_locs.toOwnedSlice(), }; - defer mir.deinit(gpa); - - var emit: Emit = .{ - .lower = .{ - .pt = pt, - .allocator = gpa, - .mir = mir, - .cc = fn_info.cc, - .src_loc = src_loc, - .output_mode = comp.config.output_mode, - .link_mode = comp.config.link_mode, - .pic = mod.pic, - }, - .bin_file = bin_file, - .debug_output = debug_output, - .code = code, - .prev_di_pc = 0, - .prev_di_line = func.lbrace_line, - .prev_di_column = func.lbrace_column, - }; - defer emit.deinit(); - - emit.emitMir() catch |err| switch (err) { - error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?), - error.InvalidInstruction => |e| return function.fail("emit MIR failed: {s} (Zig compiler bug)", .{@errorName(e)}), - else => |e| return e, - }; + errdefer mir.deinit(gpa); + return mir; } pub fn generateLazy( @@ -904,10 +876,10 @@ pub fn generateLazy( .bin_file = bin_file, .liveness = undefined, .target = &mod.resolved_target.result, - .debug_output = debug_output, .owner = .{ .lazy_sym = lazy_sym }, .args = undefined, // populated after `resolveCallingConventionValues` .ret_mcv = undefined, // populated after `resolveCallingConventionValues` + .func_index = undefined, .fn_type = undefined, .arg_index = 0, .branch_stack = undefined, @@ -3631,9 +3603,7 @@ fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void { const tlv_sym_index = if (func.bin_file.cast(.elf)) |elf_file| sym: { const zo = elf_file.zigObjectPtr().?; if (nav.getExtern(ip)) |e| { - const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); - zo.symbol(sym).flags.is_extern_ptr = true; - break :sym sym; + break :sym try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); } break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav); } else return func.fail("TODO runtime_nav_ptr on {}", .{func.bin_file.tag}); @@ -4755,16 +4725,17 @@ fn airFieldParentPtr(func: *Func, inst: Air.Inst.Index) !void { return func.fail("TODO implement codegen airFieldParentPtr", .{}); } -fn genArgDbgInfo(func: *const Func, inst: Air.Inst.Index, mcv: MCValue) InnerError!void { - const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg; - const ty = arg.ty.toType(); - if (arg.name == .none) return; +fn genArgDbgInfo(func: *const Func, name: []const u8, ty: Type, mcv: MCValue) InnerError!void { + assert(!func.mod.strip); + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (func.debug_output) { .dwarf => |dw| switch (mcv) { .register => |reg| dw.genLocalDebugInfo( .local_arg, - arg.name.toSlice(func.air), + name, ty, .{ .reg = reg.dwarfNum() }, ) catch |err| return func.fail("failed to generate debug info: {s}", .{@errorName(err)}), @@ -4777,6 +4748,8 @@ fn genArgDbgInfo(func: *const Func, inst: Air.Inst.Index, mcv: MCValue) InnerErr } fn airArg(func: *Func, inst: Air.Inst.Index) InnerError!void { + const zcu = func.pt.zcu; + var arg_index = func.arg_index; // we skip over args that have no bits @@ -4793,7 +4766,14 @@ fn airArg(func: *Func, inst: Air.Inst.Index) InnerError!void { try func.genCopy(arg_ty, dst_mcv, src_mcv); - try func.genArgDbgInfo(inst, src_mcv); + const arg = func.air.instructions.items(.data)[@intFromEnum(inst)].arg; + // can delete `func.func_index` if this logic is moved to emit + const func_zir = zcu.funcInfo(func.func_index).zir_body_inst.resolveFull(&zcu.intern_pool).?; + const file = zcu.fileByIndex(func_zir.file); + const zir = &file.zir.?; + const name = zir.nullTerminatedString(zir.getParamName(zir.getParamBody(func_zir.inst)[arg.zir_param_index]).?); + + try func.genArgDbgInfo(name, arg_ty, src_mcv); break :result dst_mcv; }; @@ -5273,6 +5253,9 @@ fn genVarDbgInfo( mcv: MCValue, name: []const u8, ) !void { + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (func.debug_output) { .dwarf => |dwarf| { const loc: link.File.Dwarf.Loc = switch (mcv) { diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index 095cfc278b40..0561eb2019f8 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -50,8 +50,8 @@ pub fn emitMir(emit: *Emit) Error!void { const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?; const sym = zo.symbol(symbol.sym_index); - if (sym.flags.is_extern_ptr and emit.lower.pic) { - return emit.fail("emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)}); + if (emit.lower.pic) { + return emit.fail("know when to emit GOT relocation for symbol '{s}'", .{sym.name(elf_file)}); } const hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index 2ae62fd9b2e2..2ad75e467799 100644 --- a/src/arch/riscv64/Mir.zig +++ b/src/arch/riscv64/Mir.zig @@ -109,6 +109,48 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { mir.* = undefined; } +pub fn emit( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) codegen.CodeGenError!void { + const zcu = pt.zcu; + const comp = zcu.comp; + const gpa = comp.gpa; + const func = zcu.funcInfo(func_index); + const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?; + const nav = func.owner_nav; + const mod = zcu.navFileScope(nav).mod.?; + var e: Emit = .{ + .lower = .{ + .pt = pt, + .allocator = gpa, + .mir = mir, + .cc = fn_info.cc, + .src_loc = src_loc, + .output_mode = comp.config.output_mode, + .link_mode = comp.config.link_mode, + .pic = mod.pic, + }, + .bin_file = lf, + .debug_output = debug_output, + .code = code, + .prev_di_pc = 0, + .prev_di_line = func.lbrace_line, + .prev_di_column = func.lbrace_column, + }; + defer e.deinit(); + e.emitMir() catch |err| switch (err) { + error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?), + error.InvalidInstruction => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}), + else => |err1| return err1, + }; +} + pub const FrameLoc = struct { base: Register, disp: i32, @@ -202,3 +244,9 @@ const FrameIndex = bits.FrameIndex; const FrameAddr = @import("CodeGen.zig").FrameAddr; const IntegerBitSet = std.bit_set.IntegerBitSet; const Mnemonic = @import("mnem.zig").Mnemonic; + +const InternPool = @import("../../InternPool.zig"); +const Emit = @import("Emit.zig"); +const codegen = @import("../../codegen.zig"); +const link = @import("../../link.zig"); +const Zcu = @import("../../Zcu.zig"); diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index ad9884dcdb85..b35f45dd6456 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -57,8 +57,6 @@ liveness: Air.Liveness, bin_file: *link.File, target: *const std.Target, func_index: InternPool.Index, -code: *std.ArrayListUnmanaged(u8), -debug_output: link.File.DebugInfoOutput, err_msg: ?*ErrorMsg, args: []MCValue, ret_mcv: MCValue, @@ -268,11 +266,9 @@ pub fn generate( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, - code: *std.ArrayListUnmanaged(u8), - debug_output: link.File.DebugInfoOutput, -) CodeGenError!void { + air: *const Air, + liveness: *const Air.Liveness, +) CodeGenError!Mir { const zcu = pt.zcu; const gpa = zcu.gpa; const func = zcu.funcInfo(func_index); @@ -291,13 +287,11 @@ pub fn generate( var function: Self = .{ .gpa = gpa, .pt = pt, - .air = air, - .liveness = liveness, + .air = air.*, + .liveness = liveness.*, .target = target, .bin_file = lf, .func_index = func_index, - .code = code, - .debug_output = debug_output, .err_msg = null, .args = undefined, // populated after `resolveCallingConventionValues` .ret_mcv = undefined, // populated after `resolveCallingConventionValues` @@ -330,29 +324,13 @@ pub fn generate( else => |e| return e, }; - var mir = Mir{ + var mir: Mir = .{ .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(gpa), - }; - defer mir.deinit(gpa); - - var emit: Emit = .{ - .mir = mir, - .bin_file = lf, - .debug_output = debug_output, - .target = target, - .src_loc = src_loc, - .code = code, - .prev_di_pc = 0, - .prev_di_line = func.lbrace_line, - .prev_di_column = func.lbrace_column, - }; - defer emit.deinit(); - - emit.emitMir() catch |err| switch (err) { - error.EmitFail => return function.failMsg(emit.err_msg.?), - else => |e| return e, + .extra = &.{}, // fallible, so populated after errdefer }; + errdefer mir.deinit(gpa); + mir.extra = try function.mir_extra.toOwnedSlice(gpa); + return mir; } fn gen(self: *Self) !void { @@ -1017,23 +995,29 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!void { self.arg_index += 1; const ty = self.typeOfIndex(inst); - - const arg = self.args[arg_index]; - const mcv = blk: { - switch (arg) { + const mcv: MCValue = blk: { + switch (self.args[arg_index]) { .stack_offset => |off| { const abi_size = math.cast(u32, ty.abiSize(zcu)) orelse { return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)}); }; const offset = off + abi_size; - break :blk MCValue{ .stack_offset = offset }; + break :blk .{ .stack_offset = offset }; }, - else => break :blk arg, + else => |mcv| break :blk mcv, } }; - self.genArgDbgInfo(inst, mcv) catch |err| - return self.fail("failed to generate debug info for parameter: {s}", .{@errorName(err)}); + const func_zir = zcu.funcInfo(self.func_index).zir_body_inst.resolveFull(&zcu.intern_pool).?; + const file = zcu.fileByIndex(func_zir.file); + if (!file.mod.?.strip) { + const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; + const zir = &file.zir.?; + const name = zir.nullTerminatedString(zir.getParamName(zir.getParamBody(func_zir.inst)[arg.zir_param_index]).?); + + self.genArgDbgInfo(name, ty, mcv) catch |err| + return self.fail("failed to generate debug info for parameter: {s}", .{@errorName(err)}); + } if (self.liveness.isUnused(inst)) return self.finishAirBookkeeping(); @@ -3561,16 +3545,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Air. self.finishAirBookkeeping(); } -fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void { - const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; - const ty = arg.ty.toType(); - if (arg.name == .none) return; - +fn genArgDbgInfo(self: Self, name: []const u8, ty: Type, mcv: MCValue) !void { + // TODO: Add a pseudo-instruction or something to defer this work until Emit. + // We aren't allowed to interact with linker state here. + if (true) return; switch (self.debug_output) { .dwarf => |dw| switch (mcv) { .register => |reg| try dw.genLocalDebugInfo( .local_arg, - arg.name.toSlice(self.air), + name, ty, .{ .reg = reg.dwarfNum() }, ), diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig index e9086db7a54f..842ac10fed1a 100644 --- a/src/arch/sparc64/Mir.zig +++ b/src/arch/sparc64/Mir.zig @@ -12,7 +12,11 @@ const assert = std.debug.assert; const Mir = @This(); const bits = @import("bits.zig"); -const Air = @import("../../Air.zig"); +const InternPool = @import("../../InternPool.zig"); +const Emit = @import("Emit.zig"); +const codegen = @import("../../codegen.zig"); +const link = @import("../../link.zig"); +const Zcu = @import("../../Zcu.zig"); const Instruction = bits.Instruction; const ASI = bits.Instruction.ASI; @@ -370,6 +374,37 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { mir.* = undefined; } +pub fn emit( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) codegen.CodeGenError!void { + const zcu = pt.zcu; + const func = zcu.funcInfo(func_index); + const nav = func.owner_nav; + const mod = zcu.navFileScope(nav).mod.?; + var e: Emit = .{ + .mir = mir, + .bin_file = lf, + .debug_output = debug_output, + .target = &mod.resolved_target.result, + .src_loc = src_loc, + .code = code, + .prev_di_pc = 0, + .prev_di_line = func.lbrace_line, + .prev_di_column = func.lbrace_column, + }; + defer e.deinit(); + e.emitMir() catch |err| switch (err) { + error.EmitFail => return zcu.codegenFailMsg(nav, e.err_msg.?), + else => |err1| return err1, + }; +} + /// Returns the requested data, as well as the new index which is at the start of the /// trailers for the object. pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 264b1e732d9e..2936025a4997 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3,7 +3,6 @@ const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const testing = std.testing; -const leb = std.leb; const mem = std.mem; const log = std.log.scoped(.codegen); @@ -18,12 +17,10 @@ const Compilation = @import("../../Compilation.zig"); const link = @import("../../link.zig"); const Air = @import("../../Air.zig"); const Mir = @import("Mir.zig"); -const Emit = @import("Emit.zig"); const abi = @import("abi.zig"); const Alignment = InternPool.Alignment; const errUnionPayloadOffset = codegen.errUnionPayloadOffset; const errUnionErrorOffset = codegen.errUnionErrorOffset; -const Wasm = link.File.Wasm; const target_util = @import("../../target.zig"); const libcFloatPrefix = target_util.libcFloatPrefix; @@ -78,17 +75,24 @@ simd_immediates: std.ArrayListUnmanaged([16]u8) = .empty, /// The Target we're emitting (used to call intInfo) target: *const std.Target, ptr_size: enum { wasm32, wasm64 }, -wasm: *link.File.Wasm, pt: Zcu.PerThread, /// List of MIR Instructions -mir_instructions: *std.MultiArrayList(Mir.Inst), +mir_instructions: std.MultiArrayList(Mir.Inst), /// Contains extra data for MIR -mir_extra: *std.ArrayListUnmanaged(u32), -start_mir_extra_off: u32, -start_locals_off: u32, +mir_extra: std.ArrayListUnmanaged(u32), /// List of all locals' types generated throughout this declaration /// used to emit locals count at start of 'code' section. -locals: *std.ArrayListUnmanaged(std.wasm.Valtype), +mir_locals: std.ArrayListUnmanaged(std.wasm.Valtype), +/// Set of all UAVs referenced by this function. Key is the UAV value, value is the alignment. +/// `.none` means naturally aligned. An explicit alignment is never less than the natural alignment. +mir_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), +/// Set of all functions whose address this function has taken and which therefore might be called +/// via a `call_indirect` function. +mir_indirect_function_set: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), +/// Set of all function types used by this function. These must be interned by the linker. +mir_func_tys: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), +/// The number of `error_name_table_ref` instructions emitted. +error_name_table_ref_count: u32, /// When a function is executing, we store the the current stack pointer's value within this local. /// This value is then used to restore the stack pointer to the original value at the return of the function. initial_stack_value: WValue = .none, @@ -219,7 +223,7 @@ const WValue = union(enum) { if (local_value < reserved + 2) return; // reserved locals may never be re-used. Also accounts for 2 stack locals. const index = local_value - reserved; - const valtype = gen.locals.items[gen.start_locals_off + index]; + const valtype = gen.mir_locals.items[index]; switch (valtype) { .i32 => gen.free_locals_i32.append(gen.gpa, local_value) catch return, // It's ok to fail any of those, a new local can be allocated instead .i64 => gen.free_locals_i64.append(gen.gpa, local_value) catch return, @@ -716,6 +720,12 @@ pub fn deinit(cg: *CodeGen) void { cg.free_locals_f32.deinit(gpa); cg.free_locals_f64.deinit(gpa); cg.free_locals_v128.deinit(gpa); + cg.mir_instructions.deinit(gpa); + cg.mir_extra.deinit(gpa); + cg.mir_locals.deinit(gpa); + cg.mir_uavs.deinit(gpa); + cg.mir_indirect_function_set.deinit(gpa); + cg.mir_func_tys.deinit(gpa); cg.* = undefined; } @@ -876,7 +886,7 @@ fn addTag(cg: *CodeGen, tag: Mir.Inst.Tag) error{OutOfMemory}!void { } fn addExtended(cg: *CodeGen, opcode: std.wasm.MiscOpcode) error{OutOfMemory}!void { - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); try cg.mir_extra.append(cg.gpa, @intFromEnum(opcode)); try cg.addInst(.{ .tag = .misc_prefix, .data = .{ .payload = extra_index } }); } @@ -889,10 +899,6 @@ fn addLocal(cg: *CodeGen, tag: Mir.Inst.Tag, local: u32) error{OutOfMemory}!void try cg.addInst(.{ .tag = tag, .data = .{ .local = local } }); } -fn addFuncTy(cg: *CodeGen, tag: Mir.Inst.Tag, i: Wasm.FunctionType.Index) error{OutOfMemory}!void { - try cg.addInst(.{ .tag = tag, .data = .{ .func_ty = i } }); -} - /// Accepts an unsigned 32bit integer rather than a signed integer to /// prevent us from having to bitcast multiple times as most values /// within codegen are represented as unsigned rather than signed. @@ -911,7 +917,7 @@ fn addImm64(cg: *CodeGen, imm: u64) error{OutOfMemory}!void { /// Accepts the index into the list of 128bit-immediates fn addImm128(cg: *CodeGen, index: u32) error{OutOfMemory}!void { const simd_values = cg.simd_immediates.items[index]; - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); // tag + 128bit value try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 5); cg.mir_extra.appendAssumeCapacity(@intFromEnum(std.wasm.SimdOpcode.v128_const)); @@ -956,15 +962,13 @@ fn addExtra(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 { /// Returns the index into `mir_extra` fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 { const fields = std.meta.fields(@TypeOf(extra)); - const result = cg.extraLen(); + const result: u32 = @intCast(cg.mir_extra.items.len); inline for (fields) |field| { cg.mir_extra.appendAssumeCapacity(switch (field.type) { u32 => @field(extra, field.name), i32 => @bitCast(@field(extra, field.name)), InternPool.Index, InternPool.Nav.Index, - Wasm.UavsObjIndex, - Wasm.UavsExeIndex, => @intFromEnum(@field(extra, field.name)), else => |field_type| @compileError("Unsupported field type " ++ @typeName(field_type)), }); @@ -1034,18 +1038,12 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { .float32 => |val| try cg.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }), .float64 => |val| try cg.addFloat64(val), .nav_ref => |nav_ref| { - const wasm = cg.wasm; - const comp = wasm.base.comp; - const zcu = comp.zcu.?; + const zcu = cg.pt.zcu; const ip = &zcu.intern_pool; if (ip.getNav(nav_ref.nav_index).isFn(ip)) { assert(nav_ref.offset == 0); - const gop = try wasm.zcu_indirect_function_set.getOrPut(comp.gpa, nav_ref.nav_index); - if (!gop.found_existing) gop.value_ptr.* = {}; - try cg.addInst(.{ - .tag = .func_ref, - .data = .{ .indirect_function_table_index = @enumFromInt(gop.index) }, - }); + try cg.mir_indirect_function_set.put(cg.gpa, nav_ref.nav_index, {}); + try cg.addInst(.{ .tag = .func_ref, .data = .{ .nav_index = nav_ref.nav_index } }); } else if (nav_ref.offset == 0) { try cg.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } }); } else { @@ -1061,41 +1059,37 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { } }, .uav_ref => |uav| { - const wasm = cg.wasm; - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; - const zcu = comp.zcu.?; + const zcu = cg.pt.zcu; const ip = &zcu.intern_pool; - if (ip.isFunctionType(ip.typeOf(uav.ip_index))) { - assert(uav.offset == 0); - const owner_nav = ip.toFunc(uav.ip_index).owner_nav; - const gop = try wasm.zcu_indirect_function_set.getOrPut(comp.gpa, owner_nav); - if (!gop.found_existing) gop.value_ptr.* = {}; - try cg.addInst(.{ - .tag = .func_ref, - .data = .{ .indirect_function_table_index = @enumFromInt(gop.index) }, - }); - } else if (uav.offset == 0) { + assert(!ip.isFunctionType(ip.typeOf(uav.ip_index))); + const gop = try cg.mir_uavs.getOrPut(cg.gpa, uav.ip_index); + const this_align: Alignment = a: { + if (uav.orig_ptr_ty == .none) break :a .none; + const ptr_type = ip.indexToKey(uav.orig_ptr_ty).ptr_type; + const this_align = ptr_type.flags.alignment; + if (this_align == .none) break :a .none; + const abi_align = Type.fromInterned(ptr_type.child).abiAlignment(zcu); + if (this_align.compare(.lte, abi_align)) break :a .none; + break :a this_align; + }; + if (!gop.found_existing or + gop.value_ptr.* == .none or + (this_align != .none and this_align.compare(.gt, gop.value_ptr.*))) + { + gop.value_ptr.* = this_align; + } + if (uav.offset == 0) { try cg.addInst(.{ .tag = .uav_ref, - .data = if (is_obj) .{ - .uav_obj = try wasm.refUavObj(uav.ip_index, uav.orig_ptr_ty), - } else .{ - .uav_exe = try wasm.refUavExe(uav.ip_index, uav.orig_ptr_ty), - }, + .data = .{ .ip_index = uav.ip_index }, }); } else { try cg.addInst(.{ .tag = .uav_ref_off, - .data = .{ - .payload = if (is_obj) try cg.addExtra(Mir.UavRefOffObj{ - .uav_obj = try wasm.refUavObj(uav.ip_index, uav.orig_ptr_ty), - .offset = uav.offset, - }) else try cg.addExtra(Mir.UavRefOffExe{ - .uav_exe = try wasm.refUavExe(uav.ip_index, uav.orig_ptr_ty), - .offset = uav.offset, - }), - }, + .data = .{ .payload = try cg.addExtra(@as(Mir.UavRefOff, .{ + .value = uav.ip_index, + .offset = uav.offset, + })) }, }); } }, @@ -1157,106 +1151,12 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { /// to use a zero-initialized local. fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { const zcu = cg.pt.zcu; - try cg.locals.append(cg.gpa, typeToValtype(ty, zcu, cg.target)); + try cg.mir_locals.append(cg.gpa, typeToValtype(ty, zcu, cg.target)); const initial_index = cg.local_index; cg.local_index += 1; return .{ .local = .{ .value = initial_index, .references = 1 } }; } -pub const Function = extern struct { - /// Index into `Wasm.mir_instructions`. - mir_off: u32, - /// This is unused except for as a safety slice bound and could be removed. - mir_len: u32, - /// Index into `Wasm.mir_extra`. - mir_extra_off: u32, - /// This is unused except for as a safety slice bound and could be removed. - mir_extra_len: u32, - locals_off: u32, - locals_len: u32, - prologue: Prologue, - - pub const Prologue = extern struct { - flags: Flags, - sp_local: u32, - stack_size: u32, - bottom_stack_local: u32, - - pub const Flags = packed struct(u32) { - stack_alignment: Alignment, - padding: u26 = 0, - }; - - pub const none: Prologue = .{ - .sp_local = 0, - .flags = .{ .stack_alignment = .none }, - .stack_size = 0, - .bottom_stack_local = 0, - }; - - pub fn isNone(p: *const Prologue) bool { - return p.flags.stack_alignment != .none; - } - }; - - pub fn lower(f: *Function, wasm: *Wasm, code: *std.ArrayListUnmanaged(u8)) Allocator.Error!void { - const gpa = wasm.base.comp.gpa; - - // Write the locals in the prologue of the function body. - const locals = wasm.all_zcu_locals.items[f.locals_off..][0..f.locals_len]; - try code.ensureUnusedCapacity(gpa, 5 + locals.len * 6 + 38); - - std.leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(locals.len))) catch unreachable; - for (locals) |local| { - std.leb.writeUleb128(code.fixedWriter(), @as(u32, 1)) catch unreachable; - code.appendAssumeCapacity(@intFromEnum(local)); - } - - // Stack management section of function prologue. - const stack_alignment = f.prologue.flags.stack_alignment; - if (stack_alignment.toByteUnits()) |align_bytes| { - const sp_global: Wasm.GlobalIndex = .stack_pointer; - // load stack pointer - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_get)); - std.leb.writeULEB128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable; - // store stack pointer so we can restore it when we return from the function - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_tee)); - leb.writeUleb128(code.fixedWriter(), f.prologue.sp_local) catch unreachable; - // get the total stack size - const aligned_stack: i32 = @intCast(stack_alignment.forward(f.prologue.stack_size)); - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - leb.writeIleb128(code.fixedWriter(), aligned_stack) catch unreachable; - // subtract it from the current stack pointer - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_sub)); - // Get negative stack alignment - const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1; - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); - leb.writeIleb128(code.fixedWriter(), neg_stack_align) catch unreachable; - // Bitwise-and the value to get the new stack pointer to ensure the - // pointers are aligned with the abi alignment. - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_and)); - // The bottom will be used to calculate all stack pointer offsets. - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_tee)); - leb.writeUleb128(code.fixedWriter(), f.prologue.bottom_stack_local) catch unreachable; - // Store the current stack pointer value into the global stack pointer so other function calls will - // start from this value instead and not overwrite the current stack. - code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); - std.leb.writeULEB128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable; - } - - var emit: Emit = .{ - .mir = .{ - .instruction_tags = wasm.mir_instructions.items(.tag)[f.mir_off..][0..f.mir_len], - .instruction_datas = wasm.mir_instructions.items(.data)[f.mir_off..][0..f.mir_len], - .extra = wasm.mir_extra.items[f.mir_extra_off..][0..f.mir_extra_len], - }, - .wasm = wasm, - .code = code, - }; - try emit.lowerToCode(); - } -}; - pub const Error = error{ OutOfMemory, /// Compiler was asked to operate on a number larger than supported. @@ -1265,13 +1165,16 @@ pub const Error = error{ CodegenFail, }; -pub fn function( - wasm: *Wasm, +pub fn generate( + bin_file: *link.File, pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, -) Error!Function { + air: *const Air, + liveness: *const Air.Liveness, +) Error!Mir { + _ = src_loc; + _ = bin_file; const zcu = pt.zcu; const gpa = zcu.gpa; const cg = zcu.funcInfo(func_index); @@ -1279,10 +1182,8 @@ pub fn function( const target = &file_scope.mod.?.resolved_target.result; const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu); const fn_info = zcu.typeToFunc(fn_ty).?; - const ip = &zcu.intern_pool; - const fn_ty_index = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target); - const returns = fn_ty_index.ptr(wasm).returns.slice(wasm); - const any_returns = returns.len != 0; + const ret_ty: Type = .fromInterned(fn_info.return_type); + const any_returns = !firstParamSRet(fn_info.cc, ret_ty, zcu, target) and ret_ty.hasRuntimeBitsIgnoreComptime(zcu); var cc_result = try resolveCallingConventionValues(zcu, fn_ty, target); defer cc_result.deinit(gpa); @@ -1290,8 +1191,8 @@ pub fn function( var code_gen: CodeGen = .{ .gpa = gpa, .pt = pt, - .air = air, - .liveness = liveness, + .air = air.*, + .liveness = liveness.*, .owner_nav = cg.owner_nav, .target = target, .ptr_size = switch (target.cpu.arch) { @@ -1299,31 +1200,33 @@ pub fn function( .wasm64 => .wasm64, else => unreachable, }, - .wasm = wasm, .func_index = func_index, .args = cc_result.args, .return_value = cc_result.return_value, .local_index = cc_result.local_index, - .mir_instructions = &wasm.mir_instructions, - .mir_extra = &wasm.mir_extra, - .locals = &wasm.all_zcu_locals, - .start_mir_extra_off = @intCast(wasm.mir_extra.items.len), - .start_locals_off = @intCast(wasm.all_zcu_locals.items.len), + .mir_instructions = .empty, + .mir_extra = .empty, + .mir_locals = .empty, + .mir_uavs = .empty, + .mir_indirect_function_set = .empty, + .mir_func_tys = .empty, + .error_name_table_ref_count = 0, }; defer code_gen.deinit(); - return functionInner(&code_gen, any_returns) catch |err| switch (err) { - error.CodegenFail => return error.CodegenFail, + try code_gen.mir_func_tys.putNoClobber(gpa, fn_ty.toIntern(), {}); + + return generateInner(&code_gen, any_returns) catch |err| switch (err) { + error.CodegenFail, + error.OutOfMemory, + error.Overflow, + => |e| return e, else => |e| return code_gen.fail("failed to generate function: {s}", .{@errorName(e)}), }; } -fn functionInner(cg: *CodeGen, any_returns: bool) InnerError!Function { - const wasm = cg.wasm; +fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir { const zcu = cg.pt.zcu; - - const start_mir_off: u32 = @intCast(wasm.mir_instructions.len); - try cg.branches.append(cg.gpa, .{}); // clean up outer branch defer { @@ -1347,20 +1250,25 @@ fn functionInner(cg: *CodeGen, any_returns: bool) InnerError!Function { try cg.addTag(.end); try cg.addTag(.dbg_epilogue_begin); - return .{ - .mir_off = start_mir_off, - .mir_len = @intCast(wasm.mir_instructions.len - start_mir_off), - .mir_extra_off = cg.start_mir_extra_off, - .mir_extra_len = cg.extraLen(), - .locals_off = cg.start_locals_off, - .locals_len = @intCast(wasm.all_zcu_locals.items.len - cg.start_locals_off), + var mir: Mir = .{ + .instructions = cg.mir_instructions.toOwnedSlice(), + .extra = &.{}, // fallible so assigned after errdefer + .locals = &.{}, // fallible so assigned after errdefer .prologue = if (cg.initial_stack_value == .none) .none else .{ .sp_local = cg.initial_stack_value.local.value, .flags = .{ .stack_alignment = cg.stack_alignment }, .stack_size = cg.stack_size, .bottom_stack_local = cg.bottom_stack_value.local.value, }, + .uavs = cg.mir_uavs.move(), + .indirect_function_set = cg.mir_indirect_function_set.move(), + .func_tys = cg.mir_func_tys.move(), + .error_name_table_ref_count = cg.error_name_table_ref_count, }; + errdefer mir.deinit(cg.gpa); + mir.extra = try cg.mir_extra.toOwnedSlice(cg.gpa); + mir.locals = try cg.mir_locals.toOwnedSlice(cg.gpa); + return mir; } const CallWValues = struct { @@ -1969,7 +1877,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .dbg_inline_block => cg.airDbgInlineBlock(inst), .dbg_var_ptr => cg.airDbgVar(inst, .local_var, true), .dbg_var_val => cg.airDbgVar(inst, .local_var, false), - .dbg_arg_inline => cg.airDbgVar(inst, .local_arg, false), + .dbg_arg_inline => cg.airDbgVar(inst, .arg, false), .call => cg.airCall(inst, .auto), .call_always_tail => cg.airCall(inst, .always_tail), @@ -2220,7 +2128,6 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) InnerError!void { - const wasm = cg.wasm; if (modifier == .always_tail) return cg.fail("TODO implement tail calls for wasm", .{}); const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const extra = cg.air.extraData(Air.Call, pl_op.payload); @@ -2277,8 +2184,11 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie const operand = try cg.resolveInst(pl_op.operand); try cg.emitWValue(operand); - const fn_type_index = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), cg.target); - try cg.addFuncTy(.call_indirect, fn_type_index); + try cg.mir_func_tys.put(cg.gpa, fn_ty.toIntern(), {}); + try cg.addInst(.{ + .tag = .call_indirect, + .data = .{ .ip_index = fn_ty.toIntern() }, + }); } const result_value = result_value: { @@ -2449,7 +2359,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr try cg.emitWValue(lhs); try cg.lowerToStack(rhs); // TODO: Add helper functions for simd opcodes - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); // stores as := opcode, offset, alignment (opcode::memarg) try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{ @intFromEnum(std.wasm.SimdOpcode.v128_store), @@ -2574,7 +2484,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue if (ty.zigTypeTag(zcu) == .vector) { // TODO: Add helper functions for simd opcodes - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); // stores as := opcode, offset, alignment (opcode::memarg) try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{ @intFromEnum(std.wasm.SimdOpcode.v128_load), @@ -4971,7 +4881,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.emitWValue(array); - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); try cg.mir_extra.appendSlice(cg.gpa, &operands); try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); @@ -5123,7 +5033,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { else => break :blk, // Cannot make use of simd-instructions }; try cg.emitWValue(operand); - const extra_index: u32 = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); // stores as := opcode, offset, alignment (opcode::memarg) try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{ opcode, @@ -5142,7 +5052,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { else => break :blk, // Cannot make use of simd-instructions }; try cg.emitWValue(operand); - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); try cg.mir_extra.append(cg.gpa, opcode); try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); return cg.finishAir(inst, .stack, &.{ty_op.operand}); @@ -5246,7 +5156,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } try cg.emitWValue(operand_a); try cg.emitWValue(operand_b); - const extra_index = cg.extraLen(); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); try cg.mir_extra.appendSlice(cg.gpa, &.{ @intFromEnum(std.wasm.SimdOpcode.i8x16_shuffle), @bitCast(lane_map[0..4].*), @@ -6016,9 +5926,8 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const name_ty = Type.slice_const_u8_sentinel_0; const abi_size = name_ty.abiSize(pt.zcu); - cg.wasm.error_name_table_ref_count += 1; - // Lowers to a i32.const or i64.const with the error table memory address. + cg.error_name_table_ref_count += 1; try cg.addTag(.error_name_table_ref); try cg.emitWValue(operand); switch (cg.ptr_size) { @@ -6046,7 +5955,7 @@ fn airPtrSliceFieldPtr(cg: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerErr /// NOTE: Allocates place for result on virtual stack, when integer size > 64 bits fn intZeroValue(cg: *CodeGen, ty: Type) InnerError!WValue { - const zcu = cg.wasm.base.comp.zcu.?; + const zcu = cg.pt.zcu; const int_info = ty.intInfo(zcu); const wasm_bits = toWasmBits(int_info.bits) orelse { return cg.fail("TODO: Implement intZeroValue for integer bitsize: {d}", .{int_info.bits}); @@ -6518,7 +6427,7 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn airDbgVar( cg: *CodeGen, inst: Air.Inst.Index, - local_tag: link.File.Dwarf.WipNav.LocalTag, + local_tag: link.File.Dwarf.WipNav.LocalVarTag, is_ptr: bool, ) InnerError!void { _ = is_ptr; @@ -7673,7 +7582,3 @@ fn floatCmpIntrinsic(op: std.math.CompareOperator, bits: u16) Mir.Intrinsic { }, }; } - -fn extraLen(cg: *const CodeGen) u32 { - return @intCast(cg.mir_extra.items.len - cg.start_mir_extra_off); -} diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 28159f33361e..8024f2db9e1f 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -31,8 +31,8 @@ pub fn lowerToCode(emit: *Emit) Error!void { const target = &comp.root_mod.resolved_target.result; const is_wasm32 = target.cpu.arch == .wasm32; - const tags = mir.instruction_tags; - const datas = mir.instruction_datas; + const tags = mir.instructions.items(.tag); + const datas = mir.instructions.items(.data); var inst: u32 = 0; loop: switch (tags[inst]) { @@ -50,18 +50,19 @@ pub fn lowerToCode(emit: *Emit) Error!void { }, .uav_ref => { if (is_obj) { - try uavRefOffObj(wasm, code, .{ .uav_obj = datas[inst].uav_obj, .offset = 0 }, is_wasm32); + try uavRefObj(wasm, code, datas[inst].ip_index, 0, is_wasm32); } else { - try uavRefOffExe(wasm, code, .{ .uav_exe = datas[inst].uav_exe, .offset = 0 }, is_wasm32); + try uavRefExe(wasm, code, datas[inst].ip_index, 0, is_wasm32); } inst += 1; continue :loop tags[inst]; }, .uav_ref_off => { + const extra = mir.extraData(Mir.UavRefOff, datas[inst].payload).data; if (is_obj) { - try uavRefOffObj(wasm, code, mir.extraData(Mir.UavRefOffObj, datas[inst].payload).data, is_wasm32); + try uavRefObj(wasm, code, extra.value, extra.offset, is_wasm32); } else { - try uavRefOffExe(wasm, code, mir.extraData(Mir.UavRefOffExe, datas[inst].payload).data, is_wasm32); + try uavRefExe(wasm, code, extra.value, extra.offset, is_wasm32); } inst += 1; continue :loop tags[inst]; @@ -77,11 +78,14 @@ pub fn lowerToCode(emit: *Emit) Error!void { continue :loop tags[inst]; }, .func_ref => { + const indirect_func_idx: Wasm.ZcuIndirectFunctionSetIndex = @enumFromInt( + wasm.zcu_indirect_function_set.getIndex(datas[inst].nav_index).?, + ); code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); if (is_obj) { @panic("TODO"); } else { - leb.writeUleb128(code.fixedWriter(), 1 + @intFromEnum(datas[inst].indirect_function_table_index)) catch unreachable; + leb.writeUleb128(code.fixedWriter(), 1 + @intFromEnum(indirect_func_idx)) catch unreachable; } inst += 1; continue :loop tags[inst]; @@ -101,6 +105,7 @@ pub fn lowerToCode(emit: *Emit) Error!void { continue :loop tags[inst]; }, .error_name_table_ref => { + wasm.error_name_table_ref_count += 1; try code.ensureUnusedCapacity(gpa, 11); const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; code.appendAssumeCapacity(@intFromEnum(opcode)); @@ -176,7 +181,13 @@ pub fn lowerToCode(emit: *Emit) Error!void { .call_indirect => { try code.ensureUnusedCapacity(gpa, 11); - const func_ty_index = datas[inst].func_ty; + const fn_info = comp.zcu.?.typeToFunc(.fromInterned(datas[inst].ip_index)).?; + const func_ty_index = wasm.getExistingFunctionType( + fn_info.cc, + fn_info.param_types.get(&comp.zcu.?.intern_pool), + .fromInterned(fn_info.return_type), + target, + ).?; code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call_indirect)); if (is_obj) { try wasm.out_relocs.append(gpa, .{ @@ -912,7 +923,7 @@ fn encodeMemArg(code: *std.ArrayListUnmanaged(u8), mem_arg: Mir.MemArg) void { leb.writeUleb128(code.fixedWriter(), mem_arg.offset) catch unreachable; } -fn uavRefOffObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRefOffObj, is_wasm32: bool) !void { +fn uavRefObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { const comp = wasm.base.comp; const gpa = comp.gpa; const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; @@ -922,14 +933,14 @@ fn uavRefOffObj(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRef try wasm.out_relocs.append(gpa, .{ .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(data.uav_obj.key(wasm).*) }, + .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(value) }, .tag = if (is_wasm32) .memory_addr_leb else .memory_addr_leb64, - .addend = data.offset, + .addend = offset, }); code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10); } -fn uavRefOffExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRefOffExe, is_wasm32: bool) !void { +fn uavRefExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), value: InternPool.Index, offset: i32, is_wasm32: bool) !void { const comp = wasm.base.comp; const gpa = comp.gpa; const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const; @@ -937,8 +948,8 @@ fn uavRefOffExe(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.UavRef try code.ensureUnusedCapacity(gpa, 11); code.appendAssumeCapacity(@intFromEnum(opcode)); - const addr = wasm.uavAddr(data.uav_exe); - leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + data.offset))) catch unreachable; + const addr = wasm.uavAddr(value); + leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + offset))) catch unreachable; } fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff, is_wasm32: bool) !void { diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index 5c8c558926be..3aee13acd703 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -9,16 +9,53 @@ const Mir = @This(); const InternPool = @import("../../InternPool.zig"); const Wasm = @import("../../link/Wasm.zig"); +const Emit = @import("Emit.zig"); +const Alignment = InternPool.Alignment; const builtin = @import("builtin"); const std = @import("std"); const assert = std.debug.assert; +const leb = std.leb; -instruction_tags: []const Inst.Tag, -instruction_datas: []const Inst.Data, +instructions: std.MultiArrayList(Inst).Slice, /// A slice of indexes where the meaning of the data is determined by the /// `Inst.Tag` value. extra: []const u32, +locals: []const std.wasm.Valtype, +prologue: Prologue, + +/// Not directly used by `Emit`, but the linker needs this to merge it with a global set. +/// Value is the explicit alignment if greater than natural alignment, `.none` otherwise. +uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), +/// Not directly used by `Emit`, but the linker needs this to merge it with a global set. +indirect_function_set: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), +/// Not directly used by `Emit`, but the linker needs this to ensure these types are interned. +func_tys: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), +/// Not directly used by `Emit`, but the linker needs this to add it to its own refcount. +error_name_table_ref_count: u32, + +pub const Prologue = extern struct { + flags: Flags, + sp_local: u32, + stack_size: u32, + bottom_stack_local: u32, + + pub const Flags = packed struct(u32) { + stack_alignment: Alignment, + padding: u26 = 0, + }; + + pub const none: Prologue = .{ + .sp_local = 0, + .flags = .{ .stack_alignment = .none }, + .stack_size = 0, + .bottom_stack_local = 0, + }; + + pub fn isNone(p: *const Prologue) bool { + return p.flags.stack_alignment != .none; + } +}; pub const Inst = struct { /// The opcode that represents this instruction @@ -80,7 +117,7 @@ pub const Inst = struct { /// Lowers to an i32_const which is the index of the function in the /// table section. /// - /// Uses `indirect_function_table_index`. + /// Uses `nav_index`. func_ref, /// Inserts debug information about the current line and column /// of the source code @@ -123,7 +160,7 @@ pub const Inst = struct { /// Calls a function pointer by its function signature /// and index into the function table. /// - /// Uses `func_ty` + /// Uses `ip_index`; the `InternPool.Index` is the function type. call_indirect, /// Calls a function by its index. /// @@ -611,11 +648,7 @@ pub const Inst = struct { ip_index: InternPool.Index, nav_index: InternPool.Nav.Index, - func_ty: Wasm.FunctionType.Index, intrinsic: Intrinsic, - uav_obj: Wasm.UavsObjIndex, - uav_exe: Wasm.UavsExeIndex, - indirect_function_table_index: Wasm.ZcuIndirectFunctionSetIndex, comptime { switch (builtin.mode) { @@ -626,10 +659,66 @@ pub const Inst = struct { }; }; -pub fn deinit(self: *Mir, gpa: std.mem.Allocator) void { - self.instructions.deinit(gpa); - gpa.free(self.extra); - self.* = undefined; +pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { + mir.instructions.deinit(gpa); + gpa.free(mir.extra); + gpa.free(mir.locals); + mir.uavs.deinit(gpa); + mir.indirect_function_set.deinit(gpa); + mir.func_tys.deinit(gpa); + mir.* = undefined; +} + +pub fn lower(mir: *const Mir, wasm: *Wasm, code: *std.ArrayListUnmanaged(u8)) std.mem.Allocator.Error!void { + const gpa = wasm.base.comp.gpa; + + // Write the locals in the prologue of the function body. + try code.ensureUnusedCapacity(gpa, 5 + mir.locals.len * 6 + 38); + + std.leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(mir.locals.len))) catch unreachable; + for (mir.locals) |local| { + std.leb.writeUleb128(code.fixedWriter(), @as(u32, 1)) catch unreachable; + code.appendAssumeCapacity(@intFromEnum(local)); + } + + // Stack management section of function prologue. + const stack_alignment = mir.prologue.flags.stack_alignment; + if (stack_alignment.toByteUnits()) |align_bytes| { + const sp_global: Wasm.GlobalIndex = .stack_pointer; + // load stack pointer + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_get)); + std.leb.writeULEB128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable; + // store stack pointer so we can restore it when we return from the function + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_tee)); + leb.writeUleb128(code.fixedWriter(), mir.prologue.sp_local) catch unreachable; + // get the total stack size + const aligned_stack: i32 = @intCast(stack_alignment.forward(mir.prologue.stack_size)); + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); + leb.writeIleb128(code.fixedWriter(), aligned_stack) catch unreachable; + // subtract it from the current stack pointer + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_sub)); + // Get negative stack alignment + const neg_stack_align = @as(i32, @intCast(align_bytes)) * -1; + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); + leb.writeIleb128(code.fixedWriter(), neg_stack_align) catch unreachable; + // Bitwise-and the value to get the new stack pointer to ensure the + // pointers are aligned with the abi alignment. + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_and)); + // The bottom will be used to calculate all stack pointer offsets. + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_tee)); + leb.writeUleb128(code.fixedWriter(), mir.prologue.bottom_stack_local) catch unreachable; + // Store the current stack pointer value into the global stack pointer so other function calls will + // start from this value instead and not overwrite the current stack. + code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); + std.leb.writeULEB128(code.fixedWriter(), @intFromEnum(sp_global)) catch unreachable; + } + + var emit: Emit = .{ + .mir = mir.*, + .wasm = wasm, + .code = code, + }; + try emit.lowerToCode(); } pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data: T, end: usize } { @@ -643,6 +732,7 @@ pub fn extraData(self: *const Mir, comptime T: type, index: usize) struct { data Wasm.UavsObjIndex, Wasm.UavsExeIndex, InternPool.Nav.Index, + InternPool.Index, => @enumFromInt(self.extra[i]), else => |field_type| @compileError("Unsupported field type " ++ @typeName(field_type)), }; @@ -695,13 +785,8 @@ pub const MemArg = struct { alignment: u32, }; -pub const UavRefOffObj = struct { - uav_obj: Wasm.UavsObjIndex, - offset: i32, -}; - -pub const UavRefOffExe = struct { - uav_exe: Wasm.UavsExeIndex, +pub const UavRefOff = struct { + value: InternPool.Index, offset: i32, }; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b38492d500d3..c652d48f3e12 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -124,13 +124,13 @@ gpa: Allocator, pt: Zcu.PerThread, air: Air, liveness: Air.Liveness, -bin_file: *link.File, -debug_output: link.File.DebugInfoOutput, target: *const std.Target, -owner: Owner, +owner: union(enum) { + nav_index: InternPool.Nav.Index, + lazy_sym: link.File.LazySymbol, +}, inline_func: InternPool.Index, mod: *Module, -arg_index: u32, args: []MCValue, va_info: union { sysv: struct { @@ -152,6 +152,14 @@ eflags_inst: ?Air.Inst.Index = null, mir_instructions: std.MultiArrayList(Mir.Inst) = .empty, /// MIR extra data mir_extra: std.ArrayListUnmanaged(u32) = .empty, +mir_string_bytes: std.ArrayListUnmanaged(u8) = .empty, +mir_strings: std.HashMapUnmanaged( + u32, + void, + std.hash_map.StringIndexContext, + std.hash_map.default_max_load_percentage, +) = .empty, +mir_locals: std.ArrayListUnmanaged(Mir.Local) = .empty, mir_table: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty, /// The value is an offset into the `Function` `code` from the beginning. @@ -194,41 +202,6 @@ loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { next_temp_index: Temp.Index = @enumFromInt(0), temp_type: [Temp.Index.max]Type = undefined, -const Owner = union(enum) { - nav_index: InternPool.Nav.Index, - lazy_sym: link.File.LazySymbol, - - fn getSymbolIndex(owner: Owner, ctx: *CodeGen) !u32 { - const pt = ctx.pt; - switch (owner) { - .nav_index => |nav_index| if (ctx.bin_file.cast(.elf)) |elf_file| { - return elf_file.zigObjectPtr().?.getOrCreateMetadataForNav(pt.zcu, nav_index); - } else if (ctx.bin_file.cast(.macho)) |macho_file| { - return macho_file.getZigObject().?.getOrCreateMetadataForNav(macho_file, nav_index); - } else if (ctx.bin_file.cast(.coff)) |coff_file| { - const atom = try coff_file.getOrCreateAtomForNav(nav_index); - return coff_file.getAtom(atom).getSymbolIndex().?; - } else if (ctx.bin_file.cast(.plan9)) |p9_file| { - return p9_file.seeNav(pt, nav_index); - } else unreachable, - .lazy_sym => |lazy_sym| if (ctx.bin_file.cast(.elf)) |elf_file| { - return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| - ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); - } else if (ctx.bin_file.cast(.macho)) |macho_file| { - return macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err| - ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); - } else if (ctx.bin_file.cast(.coff)) |coff_file| { - const atom = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| - return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); - return coff_file.getAtom(atom).getSymbolIndex().?; - } else if (ctx.bin_file.cast(.plan9)) |p9_file| { - return p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| - return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); - } else unreachable, - } - } -}; - const MaskInfo = packed struct { kind: enum(u1) { sign, all }, inverted: bool = false, @@ -269,37 +242,22 @@ pub const MCValue = union(enum) { /// The value is in memory at a hard-coded address. /// If the type is a pointer, it means the pointer address is stored at this memory location. memory: u64, - /// The value is in memory at an address not-yet-allocated by the linker. - /// This traditionally corresponds to a relocation emitted in a relocatable object file. - load_symbol: bits.SymbolOffset, - /// The address of the memory location not-yet-allocated by the linker. - lea_symbol: bits.SymbolOffset, - /// The value is in memory at an address not-yet-allocated by the linker. - /// This must use a non-got pc-relative relocation. - load_pcrel: bits.SymbolOffset, - /// The address of the memory location not-yet-allocated by the linker. - /// This must use a non-got pc-relative relocation. - lea_pcrel: bits.SymbolOffset, /// The value is in memory at a constant offset from the address in a register. indirect: bits.RegisterOffset, - /// The value is in memory. - /// Payload is a symbol index. - load_direct: u32, - /// The value is a pointer to a value in memory. - /// Payload is a symbol index. - lea_direct: u32, - /// The value is in memory referenced indirectly via GOT. - /// Payload is a symbol index. - load_got: u32, - /// The value is a pointer to a value referenced indirectly via GOT. - /// Payload is a symbol index. - lea_got: u32, /// The value stored at an offset from a frame index /// Payload is a frame address. load_frame: bits.FrameAddr, /// The address of an offset from a frame index /// Payload is a frame address. lea_frame: bits.FrameAddr, + load_nav: InternPool.Nav.Index, + lea_nav: InternPool.Nav.Index, + load_uav: InternPool.Key.Ptr.BaseAddr.Uav, + lea_uav: InternPool.Key.Ptr.BaseAddr.Uav, + load_lazy_sym: link.File.LazySymbol, + lea_lazy_sym: link.File.LazySymbol, + load_extern_func: Mir.NullTerminatedString, + lea_extern_func: Mir.NullTerminatedString, /// Supports integer_per_element abi elementwise_args: packed struct { regs: u3, frame_off: i29, frame_index: FrameIndex }, /// This indicates that we have already allocated a frame index for this instruction, @@ -319,11 +277,14 @@ pub const MCValue = union(enum) { .register_mask, .eflags, .register_overflow, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .lea_extern_func, + .load_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -333,11 +294,8 @@ pub const MCValue = union(enum) { .register_triple, .register_quadruple, .memory, - .load_symbol, - .load_pcrel, - .load_got, - .load_direct, .indirect, + .load_nav, => true, .load_frame => |frame_addr| !frame_addr.index.isNamed(), }; @@ -353,7 +311,14 @@ pub const MCValue = union(enum) { fn isMemory(mcv: MCValue) bool { return switch (mcv) { - .memory, .indirect, .load_frame, .load_symbol => true, + .memory, + .indirect, + .load_frame, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => true, else => false, }; } @@ -423,7 +388,7 @@ pub const MCValue = union(enum) { fn address(mcv: MCValue) MCValue { return switch (mcv) { - .none, + .none => .none, .unreach, .dead, .undef, @@ -436,11 +401,11 @@ pub const MCValue = union(enum) { .register_offset, .register_overflow, .register_mask, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -450,17 +415,17 @@ pub const MCValue = union(enum) { 0 => .{ .register = reg_off.reg }, else => .{ .register_offset = reg_off }, }, - .load_direct => |sym_index| .{ .lea_direct = sym_index }, - .load_got => |sym_index| .{ .lea_got = sym_index }, .load_frame => |frame_addr| .{ .lea_frame = frame_addr }, - .load_symbol => |sym_off| .{ .lea_symbol = sym_off }, - .load_pcrel => |sym_off| .{ .lea_pcrel = sym_off }, + .load_nav => |nav| .{ .lea_nav = nav }, + .load_uav => |uav| .{ .lea_uav = uav }, + .load_lazy_sym => |lazy_sym| .{ .lea_lazy_sym = lazy_sym }, + .load_extern_func => |extern_func| .{ .lea_extern_func = extern_func }, }; } fn deref(mcv: MCValue) MCValue { return switch (mcv) { - .none, + .none => .none, .unreach, .dead, .undef, @@ -472,11 +437,11 @@ pub const MCValue = union(enum) { .register_mask, .memory, .indirect, - .load_direct, - .load_got, .load_frame, - .load_symbol, - .load_pcrel, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -484,17 +449,17 @@ pub const MCValue = union(enum) { .immediate => |addr| .{ .memory = addr }, .register => |reg| .{ .indirect = .{ .reg = reg } }, .register_offset => |reg_off| .{ .indirect = reg_off }, - .lea_direct => |sym_index| .{ .load_direct = sym_index }, - .lea_got => |sym_index| .{ .load_got = sym_index }, .lea_frame => |frame_addr| .{ .load_frame = frame_addr }, - .lea_symbol => |sym_index| .{ .load_symbol = sym_index }, - .lea_pcrel => |sym_index| .{ .load_pcrel = sym_index }, + .lea_nav => |nav| .{ .load_nav = nav }, + .lea_uav => |uav| .{ .load_uav = uav }, + .lea_lazy_sym => |lazy_sym| .{ .load_lazy_sym = lazy_sym }, + .lea_extern_func => |extern_func| .{ .load_extern_func = extern_func }, }; } fn offset(mcv: MCValue, off: i32) MCValue { return switch (mcv) { - .none, + .none => .none, .unreach, .dead, .undef, @@ -510,15 +475,15 @@ pub const MCValue = union(enum) { .register_mask, .memory, .indirect, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .load_frame, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => switch (off) { 0 => mcv, else => unreachable, // not offsettable @@ -536,7 +501,7 @@ pub const MCValue = union(enum) { fn mem(mcv: MCValue, function: *CodeGen, mod_rm: Memory.Mod.Rm) !Memory { return switch (mcv) { - .none, + .none => .{ .mod = .{ .rm = mod_rm } }, .unreach, .dead, .undef, @@ -549,15 +514,13 @@ pub const MCValue = union(enum) { .register_offset, .register_overflow, .register_mask, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .lea_frame, .elementwise_args, .reserved_frame, - .lea_symbol, - .lea_pcrel, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, => unreachable, .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{ .base = .{ .reg = .ds }, @@ -586,30 +549,10 @@ pub const MCValue = union(enum) { .disp = frame_addr.off + mod_rm.disp, } }, }, - .load_symbol => |sym_off| { - assert(sym_off.off == 0); - return .{ - .base = .{ .reloc = sym_off.sym_index }, - .mod = .{ .rm = .{ - .size = mod_rm.size, - .index = mod_rm.index, - .scale = mod_rm.scale, - .disp = sym_off.off + mod_rm.disp, - } }, - }; - }, - .load_pcrel => |sym_off| { - assert(sym_off.off == 0); - return .{ - .base = .{ .pcrel = sym_off.sym_index }, - .mod = .{ .rm = .{ - .size = mod_rm.size, - .index = mod_rm.index, - .scale = mod_rm.scale, - .disp = sym_off.off + mod_rm.disp, - } }, - }; - }, + .load_nav => |nav| .{ .base = .{ .nav = nav }, .mod = .{ .rm = mod_rm } }, + .load_uav => |uav| .{ .base = .{ .uav = uav }, .mod = .{ .rm = mod_rm } }, + .load_lazy_sym => |lazy_sym| .{ .base = .{ .lazy_sym = lazy_sym }, .mod = .{ .rm = mod_rm } }, + .load_extern_func => |extern_func| .{ .base = .{ .extern_func = extern_func }, .mod = .{ .rm = mod_rm } }, .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm), }; } @@ -643,20 +586,20 @@ pub const MCValue = union(enum) { @as(u8, if (pl.info.inverted) '!' else ' '), @tagName(pl.reg), }), - .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }), - .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }), - .load_pcrel => |pl| try writer.print("[sym@pcrel:{} + 0x{x}]", .{ pl.sym_index, pl.off }), - .lea_pcrel => |pl| try writer.print("sym@pcrel:{} + 0x{x}", .{ pl.sym_index, pl.off }), .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), - .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), - .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), - .load_got => |pl| try writer.print("[got:{d}]", .{pl}), - .lea_got => |pl| try writer.print("got:{d}", .{pl}), .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }), + .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }), + .load_nav => |pl| try writer.print("[nav:{d}]", .{@intFromEnum(pl)}), + .lea_nav => |pl| try writer.print("nav:{d}", .{@intFromEnum(pl)}), + .load_uav => |pl| try writer.print("[uav:{d}]", .{@intFromEnum(pl.val)}), + .lea_uav => |pl| try writer.print("uav:{d}", .{@intFromEnum(pl.val)}), + .load_lazy_sym => |pl| try writer.print("[lazy:{s}:{d}]", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), + .lea_lazy_sym => |pl| try writer.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), + .load_extern_func => |pl| try writer.print("[extern:{d}]", .{@intFromEnum(pl)}), + .lea_extern_func => |pl| try writer.print("extern:{d}", .{@intFromEnum(pl)}), .elementwise_args => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{ pl.regs, pl.frame_index, pl.frame_off, }), - .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }), .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}), .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}), } @@ -676,16 +619,16 @@ const InstTracking = struct { .undef, .immediate, .memory, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .load_frame, .lea_frame, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => result, .dead, .elementwise_args, @@ -779,15 +722,15 @@ const InstTracking = struct { .undef, .immediate, .memory, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .lea_frame, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => assert(std.meta.eql(self.long, target.long)), .dead, .eflags, @@ -972,31 +915,28 @@ pub fn generate( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, - code: *std.ArrayListUnmanaged(u8), - debug_output: link.File.DebugInfoOutput, -) codegen.CodeGenError!void { + air: *const Air, + liveness: *const Air.Liveness, +) codegen.CodeGenError!Mir { + _ = bin_file; const zcu = pt.zcu; - const comp = zcu.comp; const gpa = zcu.gpa; const ip = &zcu.intern_pool; const func = zcu.funcInfo(func_index); + const func_zir = func.zir_body_inst.resolveFull(ip).?; + const file = zcu.fileByIndex(func_zir.file); const fn_type: Type = .fromInterned(func.ty); - const mod = zcu.navFileScope(func.owner_nav).mod.?; + const mod = file.mod.?; var function: CodeGen = .{ .gpa = gpa, .pt = pt, - .air = air, - .liveness = liveness, + .air = air.*, + .liveness = liveness.*, .target = &mod.resolved_target.result, .mod = mod, - .bin_file = bin_file, - .debug_output = debug_output, .owner = .{ .nav_index = func.owner_nav }, .inline_func = func_index, - .arg_index = undefined, .args = undefined, // populated after `resolveCallingConventionValues` .va_info = undefined, // populated after `resolveCallingConventionValues` .ret_mcv = undefined, // populated after `resolveCallingConventionValues` @@ -1016,6 +956,9 @@ pub fn generate( function.inst_tracking.deinit(gpa); function.epilogue_relocs.deinit(gpa); function.mir_instructions.deinit(gpa); + function.mir_string_bytes.deinit(gpa); + function.mir_strings.deinit(gpa); + function.mir_locals.deinit(gpa); function.mir_extra.deinit(gpa); function.mir_table.deinit(gpa); } @@ -1083,14 +1026,14 @@ pub fn generate( ); } - function.gen() catch |err| switch (err) { + function.gen(&file.zir.?, func_zir.inst, func.comptime_args, call_info.air_arg_count) catch |err| switch (err) { error.CodegenFail => return error.CodegenFail, error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}), else => |e| return e, }; // Drop them off at the rbrace. - if (debug_output != .none) _ = try function.addInst(.{ + if (!mod.strip) _ = try function.addInst(.{ .tag = .pseudo, .ops = .pseudo_dbg_line_line_column, .data = .{ .line_column = .{ @@ -1100,48 +1043,31 @@ pub fn generate( }); var mir: Mir = .{ - .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(gpa), - .table = try function.mir_table.toOwnedSlice(gpa), - .frame_locs = function.frame_locs.toOwnedSlice(), + .instructions = .empty, + .extra = &.{}, + .string_bytes = &.{}, + .locals = &.{}, + .table = &.{}, + .frame_locs = .empty, }; - defer mir.deinit(gpa); - - var emit: Emit = .{ - .air = function.air, - .lower = .{ - .bin_file = bin_file, - .target = function.target, - .allocator = gpa, - .mir = mir, - .cc = fn_info.cc, - .src_loc = src_loc, - .output_mode = comp.config.output_mode, - .link_mode = comp.config.link_mode, - .pic = mod.pic, - }, - .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) { - error.CodegenFail => return error.CodegenFail, - else => |e| return e, - }, - .debug_output = debug_output, - .code = code, - .prev_di_loc = .{ - .line = func.lbrace_line, - .column = func.lbrace_column, - .is_stmt = switch (debug_output) { - .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt, - .plan9 => undefined, - .none => undefined, - }, - }, - .prev_di_pc = 0, - }; - emit.emitMir() catch |err| switch (err) { - error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?), + errdefer mir.deinit(gpa); + mir.instructions = function.mir_instructions.toOwnedSlice(); + mir.extra = try function.mir_extra.toOwnedSlice(gpa); + mir.string_bytes = try function.mir_string_bytes.toOwnedSlice(gpa); + mir.locals = try function.mir_locals.toOwnedSlice(gpa); + mir.table = try function.mir_table.toOwnedSlice(gpa); + mir.frame_locs = function.frame_locs.toOwnedSlice(); + return mir; +} - error.InvalidInstruction, error.CannotEncode => |e| return function.fail("emit MIR failed: {s} (Zig compiler bug)", .{@errorName(e)}), - else => |e| return function.fail("emit MIR failed: {s}", .{@errorName(e)}), +pub fn getTmpMir(cg: *CodeGen) Mir { + return .{ + .instructions = cg.mir_instructions.slice(), + .extra = cg.mir_extra.items, + .string_bytes = cg.mir_string_bytes.items, + .locals = cg.mir_locals.items, + .table = cg.mir_table.items, + .frame_locs = cg.frame_locs.slice(), }; } @@ -1153,10 +1079,9 @@ pub fn generateLazy( code: *std.ArrayListUnmanaged(u8), debug_output: link.File.DebugInfoOutput, ) codegen.CodeGenError!void { - const comp = bin_file.comp; - const gpa = comp.gpa; + const gpa = pt.zcu.gpa; // This function is for generating global code, so we use the root module. - const mod = comp.root_mod; + const mod = pt.zcu.comp.root_mod; var function: CodeGen = .{ .gpa = gpa, .pt = pt, @@ -1164,11 +1089,8 @@ pub fn generateLazy( .liveness = undefined, .target = &mod.resolved_target.result, .mod = mod, - .bin_file = bin_file, - .debug_output = debug_output, .owner = .{ .lazy_sym = lazy_sym }, .inline_func = undefined, - .arg_index = undefined, .args = undefined, .va_info = undefined, .ret_mcv = undefined, @@ -1179,6 +1101,9 @@ pub fn generateLazy( defer { function.inst_tracking.deinit(gpa); function.mir_instructions.deinit(gpa); + function.mir_string_bytes.deinit(gpa); + function.mir_strings.deinit(gpa); + function.mir_locals.deinit(gpa); function.mir_extra.deinit(gpa); function.mir_table.deinit(gpa); } @@ -1194,42 +1119,7 @@ pub fn generateLazy( else => |e| return e, }; - var mir: Mir = .{ - .instructions = function.mir_instructions.toOwnedSlice(), - .extra = try function.mir_extra.toOwnedSlice(gpa), - .table = try function.mir_table.toOwnedSlice(gpa), - .frame_locs = function.frame_locs.toOwnedSlice(), - }; - defer mir.deinit(gpa); - - var emit: Emit = .{ - .air = function.air, - .lower = .{ - .bin_file = bin_file, - .target = function.target, - .allocator = gpa, - .mir = mir, - .cc = .auto, - .src_loc = src_loc, - .output_mode = comp.config.output_mode, - .link_mode = comp.config.link_mode, - .pic = mod.pic, - }, - .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) { - error.CodegenFail => return error.CodegenFail, - else => |e| return e, - }, - .debug_output = debug_output, - .code = code, - .prev_di_loc = undefined, // no debug info yet - .prev_di_pc = undefined, // no debug info yet - }; - emit.emitMir() catch |err| switch (err) { - error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?), - error.InvalidInstruction => return function.fail("failed to find a viable x86 instruction (Zig compiler bug)", .{}), - error.CannotEncode => return function.fail("failed to encode x86 instruction (Zig compiler bug)", .{}), - else => |e| return function.fail("failed to emit MIR: {s}", .{@errorName(e)}), - }; + try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, code, debug_output); } const FormatNavData = struct { @@ -1277,23 +1167,12 @@ 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, .target = data.self.target, .allocator = data.self.gpa, - .mir = .{ - .instructions = data.self.mir_instructions.slice(), - .extra = data.self.mir_extra.items, - .table = data.self.mir_table.items, - .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), - }, + .mir = data.self.getTmpMir(), .cc = .auto, .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) { @@ -1329,7 +1208,9 @@ fn formatWipMir( .pseudo_dbg_epilogue_begin_none, .pseudo_dbg_enter_block_none, .pseudo_dbg_leave_block_none, + .pseudo_dbg_arg_none, .pseudo_dbg_var_args_none, + .pseudo_dbg_var_none, .pseudo_dead_none, => {}, .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try writer.print( @@ -1337,57 +1218,40 @@ fn formatWipMir( mir_inst.data.line_column, ), .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try writer.print(" {}", .{ - ip.getNav(ip.indexToKey(mir_inst.data.func).func.owner_nav).name.fmt(ip), + ip.getNav(ip.indexToKey(mir_inst.data.ip_index).func.owner_nav).name.fmt(ip), }), - .pseudo_dbg_local_a => try writer.print(" {}", .{mir_inst.data.a.air_inst}), - .pseudo_dbg_local_ai_s => try writer.print(" {}, {d}", .{ - mir_inst.data.ai.air_inst, - @as(i32, @bitCast(mir_inst.data.ai.i)), + .pseudo_dbg_arg_i_s, .pseudo_dbg_var_i_s => try writer.print(" {d}", .{ + @as(i32, @bitCast(mir_inst.data.i.i)), }), - .pseudo_dbg_local_ai_u => try writer.print(" {}, {d}", .{ - mir_inst.data.ai.air_inst, - mir_inst.data.ai.i, + .pseudo_dbg_arg_i_u, .pseudo_dbg_var_i_u => try writer.print(" {d}", .{ + mir_inst.data.i.i, }), - .pseudo_dbg_local_ai_64 => try writer.print(" {}, {d}", .{ - mir_inst.data.ai.air_inst, - lower.mir.extraData(Mir.Imm64, mir_inst.data.ai.i).data.decode(), + .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => try writer.print(" {d}", .{ + mir_inst.data.i64, }), - .pseudo_dbg_local_as => { - const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ - .base = .{ .reloc = mir_inst.data.as.sym_index }, - }) }; - try writer.print(" {}, {}", .{ mir_inst.data.as.air_inst, mem_op.fmt(.m) }); - }, - .pseudo_dbg_local_aso => { - const sym_off = lower.mir.extraData(bits.SymbolOffset, mir_inst.data.ax.payload).data; + .pseudo_dbg_arg_ro, .pseudo_dbg_var_ro => { const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ - .base = .{ .reloc = sym_off.sym_index }, - .disp = sym_off.off, + .base = .{ .reg = mir_inst.data.ro.reg }, + .disp = mir_inst.data.ro.off, }) }; - try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) }); + try writer.print(" {}", .{mem_op.fmt(.m)}); }, - .pseudo_dbg_local_aro => { - const air_off = lower.mir.extraData(Mir.AirOffset, mir_inst.data.rx.payload).data; + .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => { const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ - .base = .{ .reg = mir_inst.data.rx.r1 }, - .disp = air_off.off, + .base = .{ .frame = mir_inst.data.fa.index }, + .disp = mir_inst.data.fa.off, }) }; - try writer.print(" {}, {}", .{ air_off.air_inst, mem_op.fmt(.m) }); + try writer.print(" {}", .{mem_op.fmt(.m)}); }, - .pseudo_dbg_local_af => { - const frame_addr = lower.mir.extraData(bits.FrameAddr, mir_inst.data.ax.payload).data; - const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{ - .base = .{ .frame = frame_addr.index }, - .disp = frame_addr.off, - }) }; - try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) }); - }, - .pseudo_dbg_local_am => { + .pseudo_dbg_arg_m, .pseudo_dbg_var_m => { const mem_op: encoder.Instruction.Operand = .{ - .mem = lower.mir.extraData(Mir.Memory, mir_inst.data.ax.payload).data.decode(), + .mem = lower.mir.extraData(Mir.Memory, mir_inst.data.x.payload).data.decode(), }; - try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) }); + try writer.print(" {}", .{mem_op.fmt(.m)}); }, + .pseudo_dbg_arg_val, .pseudo_dbg_var_val => try writer.print(" {}", .{ + Value.fromInterned(mir_inst.data.ip_index).fmtValue(data.self.pt), + }), } } } @@ -1440,6 +1304,22 @@ fn addExtraAssumeCapacity(self: *CodeGen, extra: anytype) u32 { return result; } +fn addString(cg: *CodeGen, string: []const u8) Allocator.Error!Mir.NullTerminatedString { + try cg.mir_string_bytes.ensureUnusedCapacity(cg.gpa, string.len + 1); + try cg.mir_strings.ensureUnusedCapacityContext(cg.gpa, 1, .{ .bytes = &cg.mir_string_bytes }); + + const mir_string_gop = cg.mir_strings.getOrPutAssumeCapacityAdapted( + string, + std.hash_map.StringIndexAdapter{ .bytes = &cg.mir_string_bytes }, + ); + if (!mir_string_gop.found_existing) { + mir_string_gop.key_ptr.* = @intCast(cg.mir_string_bytes.items.len); + cg.mir_string_bytes.appendSliceAssumeCapacity(string); + cg.mir_string_bytes.appendAssumeCapacity(0); + } + return @enumFromInt(mir_string_gop.key_ptr.*); +} + fn asmOps(self: *CodeGen, tag: Mir.Inst.FixedTag, ops: [4]Operand) !void { return switch (ops[0]) { .none => self.asmOpOnly(tag), @@ -1678,124 +1558,6 @@ fn asmPlaceholder(self: *CodeGen) !Mir.Inst.Index { }); } -const MirTagAir = enum { dbg_local }; - -fn asmAir(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index) !void { - _ = try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_a, - }, - .data = .{ .a = .{ .air_inst = inst } }, - }); -} - -fn asmAirImmediate(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void { - switch (imm) { - .signed => |s| _ = try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_ai_s, - }, - .data = .{ .ai = .{ - .air_inst = inst, - .i = @bitCast(s), - } }, - }), - .unsigned => |u| _ = if (std.math.cast(u32, u)) |small| try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_ai_u, - }, - .data = .{ .ai = .{ - .air_inst = inst, - .i = small, - } }, - }) else try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_ai_64, - }, - .data = .{ .ai = .{ - .air_inst = inst, - .i = try self.addExtra(Mir.Imm64.encode(u)), - } }, - }), - .reloc => |sym_off| _ = if (sym_off.off == 0) try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_as, - }, - .data = .{ .as = .{ - .air_inst = inst, - .sym_index = sym_off.sym_index, - } }, - }) else try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_aso, - }, - .data = .{ .ax = .{ - .air_inst = inst, - .payload = try self.addExtra(sym_off), - } }, - }), - } -} - -fn asmAirRegisterImmediate( - self: *CodeGen, - tag: MirTagAir, - inst: Air.Inst.Index, - reg: Register, - imm: Immediate, -) !void { - _ = try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_aro, - }, - .data = .{ .rx = .{ - .r1 = reg, - .payload = try self.addExtra(Mir.AirOffset{ - .air_inst = inst, - .off = imm.signed, - }), - } }, - }); -} - -fn asmAirFrameAddress( - self: *CodeGen, - tag: MirTagAir, - inst: Air.Inst.Index, - frame_addr: bits.FrameAddr, -) !void { - _ = try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_af, - }, - .data = .{ .ax = .{ - .air_inst = inst, - .payload = try self.addExtra(frame_addr), - } }, - }); -} - -fn asmAirMemory(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void { - _ = try self.addInst(.{ - .tag = .pseudo, - .ops = switch (tag) { - .dbg_local => .pseudo_dbg_local_am, - }, - .data = .{ .ax = .{ - .air_inst = inst, - .payload = try self.addExtra(Mir.Memory.encode(m)), - } }, - }); -} - fn asmOpOnly(self: *CodeGen, tag: Mir.Inst.FixedTag) !void { _ = try self.addInst(.{ .tag = tag[1], @@ -1873,21 +1635,36 @@ fn asmImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate) !void { .ops = switch (imm) { .signed => .i_s, .unsigned => .i_u, - .reloc => .rel, + .nav => .nav, + .uav => .uav, + .lazy_sym => .lazy_sym, + .extern_func => .extern_func, }, .data = switch (imm) { - .reloc => |sym_off| reloc: { - assert(tag[0] == ._); - break :reloc .{ .reloc = sym_off }; - }, .signed, .unsigned => .{ .i = .{ .fixes = tag[0], .i = switch (imm) { .signed => |s| @bitCast(s), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, } }, + .nav => |nav| switch (tag[0]) { + ._ => .{ .nav = nav }, + else => unreachable, + }, + .uav => |uav| switch (tag[0]) { + ._ => .{ .uav = uav }, + else => unreachable, + }, + .lazy_sym => |lazy_sym| switch (tag[0]) { + ._ => .{ .lazy_sym = lazy_sym }, + else => unreachable, + }, + .extern_func => |extern_func| switch (tag[0]) { + ._ => .{ .extern_func = extern_func }, + else => unreachable, + }, }, }); } @@ -1902,7 +1679,7 @@ fn asmImmediateRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate, .i = @as(u8, switch (imm) { .signed => |s| @bitCast(@as(i8, @intCast(s))), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }), } }, }); @@ -1917,12 +1694,12 @@ fn asmImmediateImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm1: Immediate .i1 = switch (imm1) { .signed => |s| @bitCast(@as(i16, @intCast(s))), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, .i2 = switch (imm2) { .signed => |s| @bitCast(@as(i8, @intCast(s))), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, } }, }); @@ -1947,7 +1724,7 @@ fn asmRegisterImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register, i .{ .ri_u, small } else .{ .ri_64, try self.addExtra(Mir.Imm64.encode(imm.unsigned)) }, - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }; _ = try self.addInst(.{ .tag = tag[1], @@ -2019,7 +1796,7 @@ fn asmRegisterRegisterRegisterImmediate( .i = switch (imm) { .signed => |s| @bitCast(@as(i8, @intCast(s))), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, } }, }); @@ -2037,7 +1814,7 @@ fn asmRegisterRegisterImmediate( .ops = switch (imm) { .signed => .rri_s, .unsigned => .rri_u, - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, .data = .{ .rri = .{ .fixes = tag[0], @@ -2046,7 +1823,7 @@ fn asmRegisterRegisterImmediate( .i = switch (imm) { .signed => |s| @bitCast(s), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, } }, }); @@ -2144,7 +1921,7 @@ fn asmRegisterMemoryImmediate( if (switch (imm) { .signed => |s| if (std.math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null, .unsigned => |u| std.math.cast(u16, u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }) |small_imm| { _ = try self.addInst(.{ .tag = tag[1], @@ -2160,7 +1937,7 @@ fn asmRegisterMemoryImmediate( const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { .signed => |s| @bitCast(s), .unsigned => |u| @as(u32, @intCast(u)), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, } }); assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); _ = try self.addInst(.{ @@ -2168,7 +1945,7 @@ fn asmRegisterMemoryImmediate( .ops = switch (imm) { .signed => .rmi_s, .unsigned => .rmi_u, - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, .data = .{ .rx = .{ .fixes = tag[0], @@ -2216,7 +1993,7 @@ fn asmMemoryImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory, imm: Im const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) { .signed => |s| @bitCast(s), .unsigned => |u| @intCast(u), - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, } }); assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m))); _ = try self.addInst(.{ @@ -2224,7 +2001,7 @@ fn asmMemoryImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory, imm: Im .ops = switch (imm) { .signed => .mi_s, .unsigned => .mi_u, - .reloc => unreachable, + .nav, .uav, .lazy_sym, .extern_func => unreachable, }, .data = .{ .x = .{ .fixes = tag[0], @@ -2271,7 +2048,13 @@ fn asmMemoryRegisterImmediate( }); } -fn gen(self: *CodeGen) InnerError!void { +fn gen( + self: *CodeGen, + zir: *const std.zig.Zir, + func_zir_inst: std.zig.Zir.Inst.Index, + comptime_args: InternPool.Index.Slice, + air_arg_count: u32, +) InnerError!void { const pt = self.pt; const zcu = pt.zcu; const fn_info = zcu.typeToFunc(self.fn_type).?; @@ -2339,9 +2122,9 @@ fn gen(self: *CodeGen) InnerError!void { else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}), }; - if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_prologue_end_none); + if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none); - try self.genBody(self.air.getMainBody()); + try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count); const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: { var last_inst: Mir.Inst.Index = @intCast(self.mir_instructions.len - 1); @@ -2356,7 +2139,7 @@ fn gen(self: *CodeGen) InnerError!void { } for (self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc); - if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); + if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); const backpatch_stack_dealloc = try self.asmPlaceholder(); const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); try self.asmRegister(.{ ._, .pop }, .rbp); @@ -2475,21 +2258,88 @@ fn gen(self: *CodeGen) InnerError!void { }); } } else { - if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_prologue_end_none); - try self.genBody(self.air.getMainBody()); - if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); + if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_prologue_end_none); + try self.genMainBody(zir, func_zir_inst, comptime_args, air_arg_count); + if (!self.mod.strip) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none); + } +} + +fn genMainBody( + cg: *CodeGen, + zir: *const std.zig.Zir, + func_zir_inst: std.zig.Zir.Inst.Index, + comptime_args: InternPool.Index.Slice, + air_arg_count: u32, +) InnerError!void { + const pt = cg.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + + const main_body = cg.air.getMainBody(); + const air_args_body = main_body[0..air_arg_count]; + try cg.genBody(air_args_body); + + if (!cg.mod.strip) { + var air_arg_index: usize = 0; + const fn_info = zcu.typeToFunc(cg.fn_type).?; + var fn_param_index: usize = 0; + var zir_param_index: usize = 0; + for (zir.getParamBody(func_zir_inst)) |zir_param_inst| { + const name = switch (zir.getParamName(zir_param_inst) orelse break) { + .empty => .none, + else => |zir_name| try cg.addString(zir.nullTerminatedString(zir_name)), + }; + defer zir_param_index += 1; + + if (comptime_args.len > 0) switch (comptime_args.get(ip)[zir_param_index]) { + .none => {}, + else => |comptime_arg| { + try cg.mir_locals.append(cg.gpa, .{ .name = name, .type = ip.typeOf(comptime_arg) }); + _ = try cg.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_arg_val, + .data = .{ .ip_index = comptime_arg }, + }); + continue; + }, + }; + + const arg_ty = fn_info.param_types.get(ip)[fn_param_index]; + try cg.mir_locals.append(cg.gpa, .{ .name = name, .type = arg_ty }); + fn_param_index += 1; + + if (air_arg_index == air_args_body.len) { + try cg.asmPseudo(.pseudo_dbg_arg_none); + continue; + } + const air_arg_inst = air_args_body[air_arg_index]; + const air_arg_data = cg.air.instructions.items(.data)[air_arg_index].arg; + if (air_arg_data.zir_param_index != zir_param_index) { + try cg.asmPseudo(.pseudo_dbg_arg_none); + continue; + } + air_arg_index += 1; + try cg.genLocalDebugInfo( + .arg, + .fromInterned(arg_ty), + cg.getResolvedInstValue(air_arg_inst).short, + ); + } + if (fn_info.is_var_args) try cg.asmPseudo(.pseudo_dbg_var_args_none); } + + try cg.genBody(main_body[air_arg_count..]); } -fn checkInvariantsAfterAirInst(self: *CodeGen) void { - assert(!self.register_manager.lockedRegsExist()); +fn checkInvariantsAfterAirInst(cg: *CodeGen) void { + assert(!cg.register_manager.lockedRegsExist()); if (std.debug.runtime_safety) { // check consistency of tracked registers - var it = self.register_manager.free_registers.iterator(.{ .kind = .unset }); + var it = cg.register_manager.free_registers.iterator(.{ .kind = .unset }); while (it.next()) |index| { - const tracked_inst = self.register_manager.registers[index]; - const tracking = self.getResolvedInstValue(tracked_inst); + const tracked_inst = cg.register_manager.registers[index]; + const tracking = cg.getResolvedInstValue(tracked_inst); for (tracking.getRegs()) |reg| { if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; } else unreachable; // tracked register not in use @@ -2497,10 +2347,10 @@ fn checkInvariantsAfterAirInst(self: *CodeGen) void { } } -fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void { - if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_enter_block_none); - try self.genBody(body); - if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_leave_block_none); +fn genBodyBlock(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { + if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_enter_block_none); + try cg.genBody(body); + if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_leave_block_none); } fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { @@ -2512,25 +2362,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { const air_datas = cg.air.instructions.items(.data); const use_old = cg.target.ofmt == .coff; - cg.arg_index = 0; - for (body) |inst| switch (air_tags[@intFromEnum(inst)]) { - .arg => { - wip_mir_log.debug("{}", .{cg.fmtAir(inst)}); - verbose_tracking_log.debug("{}", .{cg.fmtTracking()}); - - cg.reused_operands = .initEmpty(); - try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1); - - try cg.airArg(inst); - - try cg.resetTemps(@enumFromInt(0)); - cg.checkInvariantsAfterAirInst(); - }, - else => break, - }; - - if (cg.arg_index == 0) try cg.airDbgVarArgs(); - cg.arg_index = 0; for (body) |inst| { if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue; wip_mir_log.debug("{}", .{cg.fmtAir(inst)}); @@ -2544,20 +2375,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .shuffle_one, .shuffle_two => @panic("x86_64 TODO: shuffle_one/shuffle_two"), // zig fmt: on - .arg => if (cg.debug_output != .none) { - // skip zero-bit arguments as they don't have a corresponding arg instruction - var arg_index = cg.arg_index; - while (cg.args[arg_index] == .none) arg_index += 1; - cg.arg_index = arg_index + 1; - - const name = air_datas[@intFromEnum(inst)].arg.name; - if (name != .none) try cg.genLocalDebugInfo(inst, cg.getResolvedInstValue(inst).short); - if (cg.liveness.isUnused(inst)) try cg.processDeath(inst); - - for (cg.args[arg_index + 1 ..]) |arg| { - if (arg != .none) break; - } else try cg.airDbgVarArgs(); - }, + .arg => try cg.airArg(inst), .add, .add_optimized, .add_wrap => |air_tag| if (use_old) try cg.airBinOp(inst, switch (air_tag) { else => unreachable, .add, .add_optimized => .add, @@ -3577,7 +3395,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -3709,7 +3527,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -3745,7 +3563,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -3782,7 +3600,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -3822,7 +3640,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -4307,7 +4125,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -4339,7 +4157,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -4374,7 +4192,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -4409,7 +4227,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -14009,7 +13827,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subhf3" } }, .unused, .unused, .unused, @@ -14141,7 +13959,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subhf3" } }, .unused, .unused, .unused, @@ -14177,7 +13995,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subhf3" } }, .unused, .unused, .unused, @@ -14214,7 +14032,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subhf3" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -14254,7 +14072,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subhf3" } }, .unused, .unused, .unused, @@ -14756,7 +14574,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subtf3" } }, .unused, .unused, .unused, @@ -14788,7 +14606,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subtf3" } }, .unused, .unused, .unused, @@ -14823,7 +14641,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subtf3" } }, .unused, .unused, .unused, @@ -14858,7 +14676,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__subtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__subtf3" } }, .unused, .unused, .unused, @@ -23539,7 +23357,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -23671,7 +23489,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -23707,7 +23525,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -23744,7 +23562,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -23784,7 +23602,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -24269,7 +24087,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -24301,7 +24119,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -24336,7 +24154,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -24371,7 +24189,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -26231,7 +26049,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -26363,7 +26181,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -26399,7 +26217,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -26436,7 +26254,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -26476,7 +26294,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -26961,7 +26779,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -26993,7 +26811,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -27028,7 +26846,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -27063,7 +26881,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -32371,7 +32189,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, .unused, .unused, .unused, @@ -32503,7 +32321,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, .unused, .unused, .unused, @@ -32539,7 +32357,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, .unused, .unused, .unused, @@ -32576,7 +32394,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -32616,7 +32434,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, .unused, .unused, .unused, @@ -33119,7 +32937,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .unused, .unused, .unused, @@ -33151,7 +32969,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .unused, .unused, .unused, @@ -33186,7 +33004,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .unused, .unused, .unused, @@ -33221,7 +33039,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, .unused, .unused, .unused, @@ -33305,8 +33123,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunch" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunch" } }, .unused, .unused, .unused, @@ -33447,8 +33265,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunch" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunch" } }, .unused, .unused, .unused, @@ -33484,8 +33302,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunch" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunch" } }, .unused, .unused, .unused, @@ -33522,8 +33340,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunch" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunch" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -33563,8 +33381,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunch" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunch" } }, .unused, .unused, .unused, @@ -33632,7 +33450,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "truncf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf" } }, .unused, .unused, .unused, @@ -33696,7 +33514,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "truncf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncf" } }, .unused, .unused, .unused, @@ -33845,7 +33663,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "trunc" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "trunc" } }, .unused, .unused, .unused, @@ -33875,8 +33693,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divdf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "trunc" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divdf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "trunc" } }, .unused, .unused, .unused, @@ -34023,7 +33841,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "trunc" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "trunc" } }, .unused, .unused, .unused, @@ -34059,8 +33877,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divdf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "trunc" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divdf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "trunc" } }, .unused, .unused, .unused, @@ -34097,7 +33915,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f80, .kind = .{ .reg = .st6 } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncx" } }, .unused, .unused, .unused, @@ -34131,7 +33949,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f80, .kind = .{ .reg = .st6 } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncx" } }, .unused, .unused, .unused, @@ -34165,8 +33983,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "truncq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, .unused, .unused, .unused, @@ -34198,8 +34016,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "truncq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, .unused, .unused, .unused, @@ -34234,8 +34052,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "truncq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, .unused, .unused, .unused, @@ -34270,8 +34088,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "truncq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "truncq" } }, .unused, .unused, .unused, @@ -34361,12 +34179,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__trunch", .down => "__floorh", - } } } }, + } } }, .unused, .unused, .unused, @@ -34501,12 +34319,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__trunch", .down => "__floorh", - } } } }, + } } }, .unused, .unused, .unused, @@ -34542,12 +34360,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__trunch", .down => "__floorh", - } } } }, + } } }, .unused, .unused, .unused, @@ -34584,12 +34402,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__trunch", .down => "__floorh", - } } } }, + } } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -34629,12 +34447,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__trunch", .down => "__floorh", - } } } }, + } } }, .unused, .unused, .unused, @@ -34702,11 +34520,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "truncf", .down => "floorf", - } } } }, + } } }, .unused, .unused, .unused, @@ -34770,11 +34588,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "truncf", .down => "floorf", - } } } }, + } } }, .unused, .unused, .unused, @@ -34923,11 +34741,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "trunc", .down => "floor", - } } } }, + } } }, .unused, .unused, .unused, @@ -34957,12 +34775,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divdf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divdf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "trunc", .down => "floor", - } } } }, + } } }, .unused, .unused, .unused, @@ -35109,11 +34927,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "trunc", .down => "floor", - } } } }, + } } }, .unused, .unused, .unused, @@ -35149,12 +34967,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divdf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divdf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "trunc", .down => "floor", - } } } }, + } } }, .unused, .unused, .unused, @@ -35191,11 +35009,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f80, .kind = .{ .reg = .st6 } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__truncx", .down => "__floorx", - } } } }, + } } }, .unused, .unused, .unused, @@ -35227,11 +35045,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__truncx", .down => "__floorx", - } } } }, + } } }, .unused, .unused, .unused, @@ -35264,11 +35082,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__truncx", .down => "__floorx", - } } } }, + } } }, .unused, .unused, .unused, @@ -35302,11 +35120,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f80, .kind = .{ .reg = .st6 } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "__truncx", .down => "__floorx", - } } } }, + } } }, .unused, .unused, .unused, @@ -35340,12 +35158,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "truncq", .down => "floorq", - } } } }, + } } }, .unused, .unused, .unused, @@ -35377,12 +35195,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "truncq", .down => "floorq", - } } } }, + } } }, .unused, .unused, .unused, @@ -35417,12 +35235,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "truncq", .down => "floorq", - } } } }, + } } }, .unused, .unused, .unused, @@ -35457,12 +35275,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .zero => "truncq", .down => "floorq", - } } } }, + } } }, .unused, .unused, .unused, @@ -35649,9 +35467,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .i128, .kind = .{ .param_gpr_pair = .{ .cc = .ccc, .at = 0 } } }, .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modti3" } }, .{ .type = .i64, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divti3" } }, .unused, .unused, .unused, @@ -35700,9 +35518,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, .{ .type = .i32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divei4" } }, .{ .kind = .{ .mem_of_type = .dst0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modei4" } }, .unused, .unused, .unused, @@ -35781,8 +35599,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorh" } }, .unused, .unused, .unused, @@ -35923,8 +35741,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorh" } }, .unused, .unused, .unused, @@ -35960,8 +35778,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorh" } }, .unused, .unused, .unused, @@ -35998,8 +35816,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorh" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -36039,8 +35857,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divhf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divhf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorh" } }, .unused, .unused, .unused, @@ -36108,7 +35926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floorf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf" } }, .unused, .unused, .unused, @@ -36172,7 +35990,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floorf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorf" } }, .unused, .unused, .unused, @@ -36321,7 +36139,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floor" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "floor" } }, .unused, .unused, .unused, @@ -36351,8 +36169,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divdf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floor" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divdf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floor" } }, .unused, .unused, .unused, @@ -36499,7 +36317,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floor" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "floor" } }, .unused, .unused, .unused, @@ -36535,8 +36353,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divdf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floor" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divdf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floor" } }, .unused, .unused, .unused, @@ -36573,7 +36391,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f80, .kind = .{ .reg = .st6 } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorx" } }, .unused, .unused, .unused, @@ -36607,7 +36425,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f80, .kind = .{ .reg = .st6 } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floorx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floorx" } }, .unused, .unused, .unused, @@ -36641,8 +36459,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floorq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, .unused, .unused, .unused, @@ -36674,8 +36492,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floorq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, .unused, .unused, .unused, @@ -36710,8 +36528,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floorq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, .unused, .unused, .unused, @@ -36746,8 +36564,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divtf3" } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "floorq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divtf3" } }, + .{ .type = .usize, .kind = .{ .extern_func = "floorq" } }, .unused, .unused, .unused, @@ -36903,7 +36721,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modti3" } }, .unused, .unused, .unused, @@ -36932,7 +36750,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__umodti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__umodti3" } }, .unused, .unused, .unused, @@ -36965,7 +36783,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modei4" } }, .unused, .unused, .unused, @@ -36998,7 +36816,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__umodei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__umodei4" } }, .unused, .unused, .unused, @@ -37362,7 +37180,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modti3" } }, .{ .type = .u64, .kind = .{ .ret_gpr = .{ .cc = .ccc, .at = 0 } } }, .unused, .unused, @@ -37400,7 +37218,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__umodti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__umodti3" } }, .{ .type = .u64, .kind = .{ .ret_gpr = .{ .cc = .ccc, .at = 0 } } }, .unused, .unused, @@ -37438,7 +37256,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modei4" } }, .unused, .unused, .unused, @@ -37474,7 +37292,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__umodei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__umodei4" } }, .unused, .unused, .unused, @@ -37505,7 +37323,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .unused, .unused, .unused, @@ -37537,7 +37355,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .unused, .unused, .unused, @@ -37573,7 +37391,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .unused, .unused, .unused, @@ -37610,7 +37428,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -37650,7 +37468,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .unused, .unused, .unused, @@ -37686,7 +37504,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .unused, .unused, .unused, @@ -37718,7 +37536,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .unused, .unused, .unused, @@ -37753,7 +37571,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .unused, .unused, .unused, @@ -37785,7 +37603,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .unused, .unused, .unused, @@ -37817,7 +37635,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .unused, .unused, .unused, @@ -37852,7 +37670,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .unused, .unused, .unused, @@ -37887,7 +37705,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .unused, .unused, .unused, @@ -37923,7 +37741,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .unused, .unused, .unused, @@ -37956,7 +37774,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .unused, .unused, .unused, @@ -37989,7 +37807,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .unused, .unused, .unused, @@ -38023,7 +37841,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .unused, .unused, .unused, @@ -38061,7 +37879,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .unused, .unused, .unused, @@ -38099,7 +37917,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .unused, .unused, .unused, @@ -38134,7 +37952,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .unused, .unused, .unused, @@ -38166,7 +37984,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .unused, .unused, .unused, @@ -38201,7 +38019,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .unused, .unused, .unused, @@ -38236,7 +38054,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .unused, .unused, .unused, @@ -38571,7 +38389,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modti3" } }, .{ .type = .i64, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -38610,7 +38428,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modti3" } }, .unused, .unused, .unused, @@ -38650,7 +38468,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__umodti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__umodti3" } }, .unused, .unused, .unused, @@ -38684,7 +38502,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, .{ .type = .i64, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__modei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__modei4" } }, .unused, .unused, .unused, @@ -38741,7 +38559,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__umodei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__umodei4" } }, .unused, .unused, .unused, @@ -38771,7 +38589,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -38812,7 +38630,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -38853,10 +38671,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -38891,10 +38709,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -38929,10 +38747,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -38967,10 +38785,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39005,10 +38823,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f32, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39043,10 +38861,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f32, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39084,7 +38902,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -39132,7 +38950,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -39180,10 +38998,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39225,10 +39043,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39270,10 +39088,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39315,10 +39133,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39360,10 +39178,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39406,10 +39224,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f16, .kind = .{ .reg = .dx } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39453,9 +39271,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f32, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39502,9 +39320,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodh" } }, .{ .type = .f32, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -39547,7 +39365,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .{ .type = .f32, .kind = .{ .reg = .edx } }, .{ .type = .f32, .kind = .{ .reg = .eax } }, .unused, @@ -39585,7 +39403,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .{ .type = .f32, .kind = .{ .reg = .edx } }, .{ .type = .f32, .kind = .{ .reg = .eax } }, .unused, @@ -39623,7 +39441,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f32, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f32, .kind = .{ .reg = .eax } }, .unused, @@ -39663,7 +39481,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, .{ .type = .f32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .{ .type = .f32, .kind = .{ .reg = .edx } }, .{ .type = .f32, .kind = .{ .reg = .eax } }, .unused, @@ -39707,7 +39525,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, .{ .type = .f32, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .{ .type = .f32, .kind = .{ .reg = .edx } }, .{ .type = .f32, .kind = .{ .reg = .eax } }, .unused, @@ -39750,7 +39568,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodf" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f32, .kind = .{ .reg = .eax } }, .unused, @@ -39790,7 +39608,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f64, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .{ .type = .f64, .kind = .{ .reg = .rcx } }, .{ .type = .f64, .kind = .{ .reg = .rdx } }, .{ .type = .f64, .kind = .{ .reg = .rax } }, @@ -39829,7 +39647,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f64, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .{ .type = .f64, .kind = .{ .reg = .rcx } }, .{ .type = .f64, .kind = .{ .reg = .rdx } }, .{ .type = .f64, .kind = .{ .reg = .rax } }, @@ -39868,7 +39686,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f64, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .{ .type = .f64, .kind = .mem }, .{ .type = .f64, .kind = .{ .reg = .rdx } }, .{ .type = .f64, .kind = .{ .reg = .rax } }, @@ -39913,7 +39731,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, .{ .type = .f64, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .{ .type = .f64, .kind = .{ .reg = .rcx } }, .{ .type = .f64, .kind = .{ .reg = .rdx } }, .{ .type = .f64, .kind = .{ .reg = .rax } }, @@ -39958,7 +39776,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, .{ .type = .f64, .kind = .{ .rc = .general_purpose } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .{ .type = .f64, .kind = .{ .reg = .rcx } }, .{ .type = .f64, .kind = .{ .reg = .rdx } }, .{ .type = .f64, .kind = .{ .reg = .rax } }, @@ -40002,7 +39820,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmod" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmod" } }, .{ .type = .f64, .kind = .{ .reg = .rdx } }, .{ .type = .f64, .kind = .mem }, .{ .type = .f64, .kind = .{ .reg = .rax } }, @@ -40050,7 +39868,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40093,7 +39911,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40136,7 +39954,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40179,7 +39997,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40222,7 +40040,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40265,7 +40083,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40309,7 +40127,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40357,7 +40175,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40405,7 +40223,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40453,7 +40271,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40501,7 +40319,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40549,7 +40367,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmodx" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmodx" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .{ .type = .f80, .kind = .{ .reg = .rax } }, .unused, @@ -40595,11 +40413,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40636,11 +40454,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40677,11 +40495,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40719,11 +40537,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f128, .kind = .mem }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40761,11 +40579,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40807,11 +40625,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40853,11 +40671,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rcx } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -40900,11 +40718,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmodq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmodq" } }, .{ .type = .f128, .kind = .{ .reg = .rdx } }, .{ .type = .f128, .kind = .mem }, .{ .type = .f128, .kind = .{ .reg = .rax } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -43994,7 +43812,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -44132,7 +43950,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -44168,7 +43986,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -44205,7 +44023,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -44245,7 +44063,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -44660,7 +44478,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmax" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmax" } }, .unused, .unused, .unused, @@ -44915,7 +44733,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmax" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmax" } }, .unused, .unused, .unused, @@ -45204,7 +45022,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -45236,7 +45054,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -45271,7 +45089,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -45306,7 +45124,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -48153,7 +47971,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -48291,7 +48109,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -48327,7 +48145,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -48364,7 +48182,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -48404,7 +48222,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -48819,7 +48637,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmin" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmin" } }, .unused, .unused, .unused, @@ -49074,7 +48892,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmin" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmin" } }, .unused, .unused, .unused, @@ -49351,7 +49169,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -49383,7 +49201,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -49418,7 +49236,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -49453,7 +49271,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -64179,9 +63997,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .block => { const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; const block = cg.air.extraData(Air.Block, ty_pl.payload); - if (cg.debug_output != .none) try cg.asmPseudo(.pseudo_dbg_enter_block_none); + if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_enter_block_none); try cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[block.end..][0..block.data.body_len])); - if (cg.debug_output != .none) try cg.asmPseudo(.pseudo_dbg_leave_block_none); + if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_leave_block_none); }, .loop => if (use_old) try cg.airLoop(inst) else { const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; @@ -72393,7 +72211,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrth" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__sqrth" } }, .unused, .unused, .unused, @@ -72475,7 +72293,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrth" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__sqrth" } }, .unused, .unused, .unused, @@ -72506,7 +72324,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrth" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__sqrth" } }, .unused, .unused, .unused, @@ -72537,7 +72355,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrth" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__sqrth" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -72571,7 +72389,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__sqrth" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__sqrth" } }, .unused, .unused, .unused, @@ -72643,7 +72461,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf" } }, .unused, .unused, .unused, @@ -72759,7 +72577,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf" } }, .unused, .unused, .unused, @@ -72789,7 +72607,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtf" } }, .unused, .unused, .unused, @@ -72859,7 +72677,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrt" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrt" } }, .unused, .unused, .unused, @@ -72975,7 +72793,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrt" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrt" } }, .unused, .unused, .unused, @@ -73005,7 +72823,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrt" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrt" } }, .unused, .unused, .unused, @@ -73035,7 +72853,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrt" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrt" } }, .unused, .unused, .unused, @@ -73119,7 +72937,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, .unused, .unused, .unused, @@ -73146,7 +72964,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, .unused, .unused, .unused, @@ -73176,7 +72994,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, .unused, .unused, .unused, @@ -73206,7 +73024,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "sqrtq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "sqrtq" } }, .unused, .unused, .unused, @@ -73250,7 +73068,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "h" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "h" } }, .unused, .unused, .unused, @@ -73277,7 +73095,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "h" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "h" } }, .unused, .unused, .unused, @@ -73308,7 +73126,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "h" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "h" } }, .unused, .unused, .unused, @@ -73339,7 +73157,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "h" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "h" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -73373,7 +73191,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "h" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "h" } }, .unused, .unused, .unused, @@ -73403,7 +73221,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "f" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f" } }, .unused, .unused, .unused, @@ -73430,7 +73248,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "f" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f" } }, .unused, .unused, .unused, @@ -73460,7 +73278,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "f" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "f" } }, .unused, .unused, .unused, @@ -73488,7 +73306,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) } }, .unused, .unused, .unused, @@ -73515,7 +73333,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) } }, .unused, .unused, .unused, @@ -73545,7 +73363,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) } }, .unused, .unused, .unused, @@ -73575,7 +73393,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) } }, .unused, .unused, .unused, @@ -73606,7 +73424,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "x" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "x" } }, .unused, .unused, .unused, @@ -73633,7 +73451,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "x" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "x" } }, .unused, .unused, .unused, @@ -73660,7 +73478,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "x" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "x" } }, .unused, .unused, .unused, @@ -73688,7 +73506,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "x" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "x" } }, .unused, .unused, .unused, @@ -73720,7 +73538,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "x" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "x" } }, .unused, .unused, .unused, @@ -73752,7 +73570,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__" ++ @tagName(name) ++ "x" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__" ++ @tagName(name) ++ "x" } }, .unused, .unused, .unused, @@ -73781,7 +73599,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "q" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, .unused, .unused, .unused, @@ -73808,7 +73626,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "q" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, .unused, .unused, .unused, @@ -73838,7 +73656,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "q" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, .unused, .unused, .unused, @@ -73868,7 +73686,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(name) ++ "q" } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(name) ++ "q" } }, .unused, .unused, .unused, @@ -75486,12 +75304,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorh", .up => "__ceilh", .zero => "__trunch", - } } } }, + } } }, .unused, .unused, .unused, @@ -75573,12 +75391,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorh", .up => "__ceilh", .zero => "__trunch", - } } } }, + } } }, .unused, .unused, .unused, @@ -75609,12 +75427,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorh", .up => "__ceilh", .zero => "__trunch", - } } } }, + } } }, .unused, .unused, .unused, @@ -75645,12 +75463,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorh", .up => "__ceilh", .zero => "__trunch", - } } } }, + } } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -75684,12 +75502,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorh", .up => "__ceilh", .zero => "__trunch", - } } } }, + } } }, .unused, .unused, .unused, @@ -75761,12 +75579,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorf", .up => "ceilf", .zero => "truncf", - } } } }, + } } }, .unused, .unused, .unused, @@ -75888,12 +75706,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorf", .up => "ceilf", .zero => "truncf", - } } } }, + } } }, .unused, .unused, .unused, @@ -75923,12 +75741,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorf", .up => "ceilf", .zero => "truncf", - } } } }, + } } }, .unused, .unused, .unused, @@ -75998,12 +75816,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floor", .up => "ceil", .zero => "trunc", - } } } }, + } } }, .unused, .unused, .unused, @@ -76125,12 +75943,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floor", .up => "ceil", .zero => "trunc", - } } } }, + } } }, .unused, .unused, .unused, @@ -76160,12 +75978,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floor", .up => "ceil", .zero => "trunc", - } } } }, + } } }, .unused, .unused, .unused, @@ -76195,12 +76013,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floor", .up => "ceil", .zero => "trunc", - } } } }, + } } }, .unused, .unused, .unused, @@ -76231,12 +76049,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorx", .up => "__ceilx", .zero => "__truncx", - } } } }, + } } }, .unused, .unused, .unused, @@ -76263,12 +76081,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorx", .up => "__ceilx", .zero => "__truncx", - } } } }, + } } }, .unused, .unused, .unused, @@ -76295,12 +76113,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorx", .up => "__ceilx", .zero => "__truncx", - } } } }, + } } }, .unused, .unused, .unused, @@ -76328,12 +76146,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorx", .up => "__ceilx", .zero => "__truncx", - } } } }, + } } }, .unused, .unused, .unused, @@ -76365,12 +76183,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorx", .up => "__ceilx", .zero => "__truncx", - } } } }, + } } }, .unused, .unused, .unused, @@ -76402,12 +76220,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "__floorx", .up => "__ceilx", .zero => "__truncx", - } } } }, + } } }, .unused, .unused, .unused, @@ -76436,12 +76254,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorq", .up => "ceilq", .zero => "truncq", - } } } }, + } } }, .unused, .unused, .unused, @@ -76468,12 +76286,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorq", .up => "ceilq", .zero => "truncq", - } } } }, + } } }, .unused, .unused, .unused, @@ -76503,12 +76321,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorq", .up => "ceilq", .zero => "truncq", - } } } }, + } } }, .unused, .unused, .unused, @@ -76538,12 +76356,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (direction) { + .{ .type = .usize, .kind = .{ .extern_func = switch (direction) { else => unreachable, .down => "floorq", .up => "ceilq", .zero => "truncq", - } } } }, + } } }, .unused, .unused, .unused, @@ -77175,7 +76993,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -77518,7 +77336,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -77679,7 +77497,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -78046,7 +77864,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -78715,7 +78533,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -78759,7 +78577,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -78803,7 +78621,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -78848,7 +78666,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -78893,7 +78711,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -78940,7 +78758,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -78987,7 +78805,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -79040,7 +78858,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -79093,7 +78911,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -79147,7 +78965,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -79201,7 +79019,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -79257,7 +79075,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -80084,7 +79902,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -80128,7 +79946,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -80172,7 +79990,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -80216,7 +80034,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -80260,7 +80078,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -80304,7 +80122,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -80348,7 +80166,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -80401,7 +80219,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -80454,7 +80272,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -80507,7 +80325,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -80560,7 +80378,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -80613,7 +80431,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -83223,7 +83041,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -83267,7 +83085,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -83311,7 +83129,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -83356,7 +83174,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -83401,7 +83219,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -83448,7 +83266,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -83495,7 +83313,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -83548,7 +83366,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -83601,7 +83419,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -83655,7 +83473,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -83709,7 +83527,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -83765,7 +83583,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmphf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -84606,7 +84424,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -84650,7 +84468,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -84694,7 +84512,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -84738,7 +84556,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -84782,7 +84600,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -84826,7 +84644,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u32, .kind = .{ .reg = .edx } }, @@ -84870,7 +84688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -84923,7 +84741,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -84976,7 +84794,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -85029,7 +84847,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -85082,7 +84900,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -85135,7 +84953,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__cmptf2" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .u8, .kind = .{ .reg = .cl } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, @@ -85191,7 +85009,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .switch_dispatch => try cg.airSwitchDispatch(inst), .@"try", .try_cold => try cg.airTry(inst), .try_ptr, .try_ptr_cold => try cg.airTryPtr(inst), - .dbg_stmt => if (cg.debug_output != .none) { + .dbg_stmt => if (!cg.mod.strip) { const dbg_stmt = air_datas[@intFromEnum(inst)].dbg_stmt; _ = try cg.addInst(.{ .tag = .pseudo, @@ -85202,7 +85020,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }, }); }, - .dbg_empty_stmt => if (cg.debug_output != .none) { + .dbg_empty_stmt => if (!cg.mod.strip) { if (cg.mir_instructions.len > 0) { const prev_mir_op = &cg.mir_instructions.items(.ops)[cg.mir_instructions.len - 1]; if (prev_mir_op.* == .pseudo_dbg_line_line_column) @@ -85216,23 +85034,27 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { const old_inline_func = cg.inline_func; defer cg.inline_func = old_inline_func; cg.inline_func = dbg_inline_block.data.func; - if (cg.debug_output != .none) _ = try cg.addInst(.{ + if (!cg.mod.strip) _ = try cg.addInst(.{ .tag = .pseudo, .ops = .pseudo_dbg_enter_inline_func, - .data = .{ .func = dbg_inline_block.data.func }, + .data = .{ .ip_index = dbg_inline_block.data.func }, }); try cg.lowerBlock(inst, @ptrCast(cg.air.extra.items[dbg_inline_block.end..][0..dbg_inline_block.data.body_len])); - if (cg.debug_output != .none) _ = try cg.addInst(.{ + if (!cg.mod.strip) _ = try cg.addInst(.{ .tag = .pseudo, .ops = .pseudo_dbg_leave_inline_func, - .data = .{ .func = old_inline_func }, + .data = .{ .ip_index = old_inline_func }, }); }, - .dbg_var_ptr, - .dbg_var_val, - .dbg_arg_inline, - => if (use_old) try cg.airDbgVar(inst) else if (cg.debug_output != .none) { + .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => |air_tag| if (use_old) try cg.airDbgVar(inst) else if (!cg.mod.strip) { const pl_op = air_datas[@intFromEnum(inst)].pl_op; + const air_name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); + const op_ty = cg.typeOf(pl_op.operand); + const local_ty = switch (air_tag) { + else => unreachable, + .dbg_var_ptr => op_ty.childType(zcu), + .dbg_var_val, .dbg_arg_inline => op_ty, + }; var ops = try cg.tempsFromOperands(inst, .{pl_op.operand}); var mcv = ops[0].tracking(cg).short; switch (mcv) { @@ -85247,7 +85069,19 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, }, } - try cg.genLocalDebugInfo(inst, ops[0].tracking(cg).short); + + try cg.mir_locals.append(cg.gpa, .{ + .name = switch (air_name) { + .none => switch (air_tag) { + else => unreachable, + .dbg_arg_inline => .none, + }, + else => try cg.addString(air_name.toSlice(cg.air)), + }, + .type = local_ty.toIntern(), + }); + + try cg.genLocalDebugInfo(air_tag, local_ty, ops[0].tracking(cg).short); try ops[0].die(cg); }, .is_null => if (use_old) try cg.airIsNull(inst) else { @@ -85435,11 +85269,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .ret => try cg.airRet(inst, false), .ret_safe => try cg.airRet(inst, true), .ret_load => try cg.airRetLoad(inst), - .store, .store_safe => |air_tag| if (use_old) try cg.airStore(inst, switch (air_tag) { - else => unreachable, - .store => false, - .store_safe => true, - }) else fallback: { + .store, .store_safe => |air_tag| fallback: { const bin_op = air_datas[@intFromEnum(inst)].bin_op; const ptr_ty = cg.typeOf(bin_op.lhs); const ptr_info = ptr_ty.ptrInfo(zcu); @@ -85513,7 +85343,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncsfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncsfhf2" } }, .unused, .unused, .unused, @@ -85570,7 +85400,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncsfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncsfhf2" } }, .unused, .unused, .unused, @@ -85601,7 +85431,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncsfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncsfhf2" } }, .unused, .unused, .unused, @@ -85632,7 +85462,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncsfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncsfhf2" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -85664,7 +85494,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncsfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncsfhf2" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -85695,7 +85525,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncdfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncdfhf2" } }, .unused, .unused, .unused, @@ -85723,7 +85553,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncdfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncdfhf2" } }, .unused, .unused, .unused, @@ -85754,7 +85584,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncdfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncdfhf2" } }, .unused, .unused, .unused, @@ -85785,7 +85615,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncdfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncdfhf2" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -85817,7 +85647,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncdfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncdfhf2" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -86034,7 +85864,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .size = 16, .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .unused, .unused, .unused, @@ -86062,7 +85892,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .size = 16, .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .unused, .unused, .unused, @@ -86090,7 +85920,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .size = 16, .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .unused, .unused, .unused, @@ -86120,7 +85950,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .unused, .unused, .unused, @@ -86152,7 +85982,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .unused, .unused, .unused, @@ -86184,7 +86014,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -86217,7 +86047,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__truncxfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__truncxfhf2" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -86358,7 +86188,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfhf2" } }, .unused, .unused, .unused, @@ -86386,7 +86216,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfhf2" } }, .unused, .unused, .unused, @@ -86417,7 +86247,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfhf2" } }, .unused, .unused, .unused, @@ -86448,7 +86278,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfhf2" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -86480,7 +86310,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfhf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfhf2" } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, @@ -86511,7 +86341,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfsf2" } }, .unused, .unused, .unused, @@ -86539,7 +86369,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfsf2" } }, .unused, .unused, .unused, @@ -86570,7 +86400,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfsf2" } }, .unused, .unused, .unused, @@ -86601,7 +86431,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfsf2" } }, .unused, .unused, .unused, @@ -86630,7 +86460,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfdf2" } }, .unused, .unused, .unused, @@ -86658,7 +86488,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfdf2" } }, .unused, .unused, .unused, @@ -86689,7 +86519,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfdf2" } }, .unused, .unused, .unused, @@ -86720,7 +86550,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfdf2" } }, .unused, .unused, .unused, @@ -86749,7 +86579,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfxf2" } }, .unused, .unused, .unused, @@ -86777,7 +86607,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfxf2" } }, .unused, .unused, .unused, @@ -86809,7 +86639,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfxf2" } }, .unused, .unused, .unused, @@ -86841,7 +86671,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__trunctfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__trunctfxf2" } }, .unused, .unused, .unused, @@ -86921,7 +86751,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfsf2" } }, .unused, .unused, .unused, @@ -86978,7 +86808,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfsf2" } }, .unused, .unused, .unused, @@ -87010,7 +86840,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfsf2" } }, .unused, .unused, .unused, @@ -87044,7 +86874,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfsf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfsf2" } }, .unused, .unused, .unused, @@ -87141,7 +86971,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfdf2" } }, .unused, .unused, .unused, @@ -87202,7 +87032,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfdf2" } }, .unused, .unused, .unused, @@ -87234,7 +87064,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfdf2" } }, .unused, .unused, .unused, @@ -87268,7 +87098,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfdf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfdf2" } }, .unused, .unused, .unused, @@ -87324,7 +87154,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfxf2" } }, .unused, .unused, .unused, @@ -87352,7 +87182,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfxf2" } }, .unused, .unused, .unused, @@ -87385,7 +87215,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfxf2" } }, .unused, .unused, .unused, @@ -87420,7 +87250,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhfxf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhfxf2" } }, .unused, .unused, .unused, @@ -87450,7 +87280,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhftf2" } }, .unused, .unused, .unused, @@ -87478,7 +87308,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhftf2" } }, .unused, .unused, .unused, @@ -87510,7 +87340,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhftf2" } }, .unused, .unused, .unused, @@ -87544,7 +87374,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendhftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendhftf2" } }, .unused, .unused, .unused, @@ -87811,7 +87641,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendsftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendsftf2" } }, .unused, .unused, .unused, @@ -87839,7 +87669,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendsftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendsftf2" } }, .unused, .unused, .unused, @@ -87870,7 +87700,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendsftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendsftf2" } }, .unused, .unused, .unused, @@ -87901,7 +87731,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendsftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendsftf2" } }, .unused, .unused, .unused, @@ -87984,7 +87814,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extenddftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extenddftf2" } }, .unused, .unused, .unused, @@ -88012,7 +87842,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extenddftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extenddftf2" } }, .unused, .unused, .unused, @@ -88043,7 +87873,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extenddftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extenddftf2" } }, .unused, .unused, .unused, @@ -88074,7 +87904,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extenddftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extenddftf2" } }, .unused, .unused, .unused, @@ -88105,7 +87935,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .size = 16, .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendxftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendxftf2" } }, .unused, .unused, .unused, @@ -88133,7 +87963,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .size = 16, .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendxftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendxftf2" } }, .unused, .unused, .unused, @@ -88161,7 +87991,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .size = 16, .alignment = .@"16" }, .extra_temps = .{ .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendxftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendxftf2" } }, .unused, .unused, .unused, @@ -88191,7 +88021,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendxftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendxftf2" } }, .unused, .unused, .unused, @@ -88223,7 +88053,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendxftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendxftf2" } }, .unused, .unused, .unused, @@ -88255,7 +88085,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__extendxftf2" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__extendxftf2" } }, .unused, .unused, .unused, @@ -99006,9 +98836,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } }) catch |err| switch (err) { error.SelectFailed => { const elem_size = res_ty.abiSize(zcu); - const base = try cg.tempAllocReg(.usize, abi.RegisterClass.gp); + var base = try cg.tempAllocReg(.usize, abi.RegisterClass.gp); while (try ops[0].toBase(false, cg) or - try ops[1].toRegClass(true, .general_purpose, cg)) + try ops[1].toRegClass(true, .general_purpose, cg) or + try base.toRegClass(true, .general_purpose, cg)) {} const base_reg = base.tracking(cg).short.register.to64(); const rhs_reg = ops[1].tracking(cg).short.register.to64(); @@ -99449,7 +99280,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .unused, .unused, .unused, @@ -99475,7 +99306,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfsi" } }, .unused, .unused, .unused, @@ -99501,7 +99332,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfdi" } }, .unused, .unused, .unused, @@ -99527,7 +99358,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfdi" } }, .unused, .unused, .unused, @@ -99553,7 +99384,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfti" } }, .unused, .unused, .unused, @@ -99579,7 +99410,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfti" } }, .unused, .unused, .unused, @@ -99605,7 +99436,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .u32, .kind = .{ .reg = .ecx } }, @@ -99636,7 +99467,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .u32, .kind = .{ .reg = .ecx } }, @@ -99730,7 +99561,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -99762,7 +99593,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -99794,7 +99625,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -99826,7 +99657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -99860,7 +99691,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .unused, .unused, .unused, @@ -99893,7 +99724,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .unused, .unused, .unused, @@ -100014,7 +99845,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -100046,7 +99877,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -100080,7 +99911,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .unused, .unused, .unused, @@ -100173,7 +100004,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -100205,7 +100036,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -100237,7 +100068,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -100269,7 +100100,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -100303,7 +100134,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i32, .kind = .{ .reg = .eax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfsi" } }, .unused, .unused, .unused, @@ -100336,7 +100167,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u32, .kind = .{ .reg = .eax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfsi" } }, .unused, .unused, .unused, @@ -100399,7 +100230,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -100431,7 +100262,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -100463,7 +100294,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -100495,7 +100326,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -100529,7 +100360,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfdi" } }, .unused, .unused, .unused, @@ -100562,7 +100393,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfdi" } }, .unused, .unused, .unused, @@ -100593,7 +100424,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -100626,7 +100457,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -100659,7 +100490,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -100692,7 +100523,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -100727,7 +100558,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfti" } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, .unused, @@ -100761,7 +100592,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfti" } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, .unused, @@ -100796,7 +100627,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfei" } }, .unused, .unused, .unused, @@ -100831,7 +100662,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfei" } }, .unused, .unused, .unused, @@ -100866,7 +100697,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfei" } }, .unused, .unused, .unused, @@ -100901,7 +100732,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfei" } }, .unused, .unused, .unused, @@ -100937,7 +100768,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixhfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixhfei" } }, .unused, .unused, .unused, @@ -100973,7 +100804,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunshfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunshfei" } }, .unused, .unused, .unused, @@ -101115,7 +100946,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfti" } }, .unused, .unused, .unused, @@ -101141,7 +100972,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .unused, .unused, .unused, @@ -101170,7 +101001,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i64, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .vector_4_f32, .kind = .{ .smax_mem = .{} } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .u32, .kind = .{ .reg = .ecx } }, @@ -101211,7 +101042,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .i64, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .vector_4_f32, .kind = .{ .smax_mem = .{} } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .u32, .kind = .{ .reg = .ecx } }, @@ -101252,7 +101083,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .vector_4_f32, .kind = .{ .smax_mem = .{} } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .{ .type = .u32, .kind = .{ .reg = .ecx } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, @@ -101290,7 +101121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, @@ -101500,7 +101331,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101531,7 +101362,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101562,7 +101393,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101593,7 +101424,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101796,7 +101627,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101827,7 +101658,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101940,7 +101771,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -101971,7 +101802,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -102002,7 +101833,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -102033,7 +101864,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -102122,7 +101953,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -102153,7 +101984,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -102184,7 +102015,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -102215,7 +102046,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -102246,7 +102077,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -102278,7 +102109,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -102310,7 +102141,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -102342,7 +102173,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -102377,7 +102208,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfei" } }, .unused, .unused, .unused, @@ -102411,7 +102242,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfei" } }, .unused, .unused, .unused, @@ -102445,7 +102276,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfei" } }, .unused, .unused, .unused, @@ -102479,7 +102310,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunssfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunssfei" } }, .unused, .unused, .unused, @@ -102818,7 +102649,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfti" } }, .unused, .unused, .unused, @@ -102844,7 +102675,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfti" } }, .unused, .unused, .unused, @@ -102872,7 +102703,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfei" } }, .unused, .unused, .unused, @@ -102900,7 +102731,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfei" } }, .unused, .unused, .unused, @@ -103205,7 +103036,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103236,7 +103067,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103267,7 +103098,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103298,7 +103129,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103329,7 +103160,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103361,7 +103192,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixsfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixsfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103692,7 +103523,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103723,7 +103554,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103754,7 +103585,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103952,7 +103783,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -103983,7 +103814,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -104014,7 +103845,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -104045,7 +103876,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -104076,7 +103907,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -104108,7 +103939,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -104233,7 +104064,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -104264,7 +104095,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -104295,7 +104126,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -104326,7 +104157,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -104357,7 +104188,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -104389,7 +104220,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -104421,7 +104252,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -104453,7 +104284,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -104485,7 +104316,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -104517,7 +104348,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -104549,7 +104380,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -104582,7 +104413,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -104618,7 +104449,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfei" } }, .unused, .unused, .unused, @@ -104652,7 +104483,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfei" } }, .unused, .unused, .unused, @@ -104686,7 +104517,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfei" } }, .unused, .unused, .unused, @@ -104720,7 +104551,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfei" } }, .unused, .unused, .unused, @@ -104754,7 +104585,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixdfei" } }, .unused, .unused, .unused, @@ -104789,7 +104620,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsdfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsdfei" } }, .unused, .unused, .unused, @@ -105810,7 +105641,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -105842,7 +105673,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -105874,7 +105705,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -105905,7 +105736,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfti" } }, .unused, .unused, .unused, @@ -105933,7 +105764,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .unused, .unused, .unused, @@ -105961,7 +105792,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfti" } }, .unused, .unused, .unused, @@ -105989,7 +105820,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .unused, .unused, .unused, @@ -106017,7 +105848,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfti" } }, .unused, .unused, .unused, @@ -106045,7 +105876,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .unused, .unused, .unused, @@ -106074,7 +105905,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -106107,7 +105938,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -106140,7 +105971,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -106173,7 +106004,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -106206,7 +106037,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -106239,7 +106070,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -106273,7 +106104,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfei" } }, .unused, .unused, .unused, @@ -106303,7 +106134,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfei" } }, .unused, .unused, .unused, @@ -106333,7 +106164,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfei" } }, .unused, .unused, .unused, @@ -106363,7 +106194,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfei" } }, .unused, .unused, .unused, @@ -106393,7 +106224,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfei" } }, .unused, .unused, .unused, @@ -106423,7 +106254,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfei" } }, .unused, .unused, .unused, @@ -106455,7 +106286,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfei" } }, .unused, .unused, .unused, @@ -106490,7 +106321,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfei" } }, .unused, .unused, .unused, @@ -106525,7 +106356,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfei" } }, .unused, .unused, .unused, @@ -106560,7 +106391,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfei" } }, .unused, .unused, .unused, @@ -106595,7 +106426,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixxfei" } }, .unused, .unused, .unused, @@ -106630,7 +106461,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunsxfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunsxfei" } }, .unused, .unused, .unused, @@ -106662,7 +106493,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106695,7 +106526,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106728,7 +106559,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106761,7 +106592,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106794,7 +106625,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106827,7 +106658,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106859,7 +106690,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106890,7 +106721,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106921,7 +106752,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -106950,7 +106781,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .unused, .unused, .unused, @@ -106976,7 +106807,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfsi" } }, .unused, .unused, .unused, @@ -107004,7 +106835,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -107035,7 +106866,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -107066,7 +106897,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -107097,7 +106928,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -107128,7 +106959,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfsi" } }, .{ .type = .i32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -107159,7 +106990,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfsi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfsi" } }, .{ .type = .u32, .kind = .{ .reg = .eax } }, .unused, .unused, @@ -107188,7 +107019,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfdi" } }, .unused, .unused, .unused, @@ -107214,7 +107045,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfdi" } }, .unused, .unused, .unused, @@ -107242,7 +107073,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -107273,7 +107104,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -107304,7 +107135,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -107335,7 +107166,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -107366,7 +107197,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfdi" } }, .{ .type = .i64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -107397,7 +107228,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfdi" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfdi" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .unused, .unused, @@ -107426,7 +107257,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfti" } }, .unused, .unused, .unused, @@ -107452,7 +107283,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfti" } }, .unused, .unused, .unused, @@ -107480,7 +107311,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -107512,7 +107343,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -107544,7 +107375,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -107576,7 +107407,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -107608,7 +107439,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .i64, .kind = .{ .reg = .rdx } }, .unused, @@ -107640,7 +107471,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfti" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfti" } }, .{ .type = .u64, .kind = .{ .reg = .rax } }, .{ .type = .u64, .kind = .{ .reg = .rdx } }, .unused, @@ -107672,7 +107503,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfei" } }, .unused, .unused, .unused, @@ -107700,7 +107531,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfei" } }, .unused, .unused, .unused, @@ -107731,7 +107562,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfei" } }, .unused, .unused, .unused, @@ -107765,7 +107596,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfei" } }, .unused, .unused, .unused, @@ -107799,7 +107630,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfei" } }, .unused, .unused, .unused, @@ -107833,7 +107664,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfei" } }, .unused, .unused, .unused, @@ -107867,7 +107698,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixtfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixtfei" } }, .unused, .unused, .unused, @@ -107901,7 +107732,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fixunstfei" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fixunstfei" } }, .unused, .unused, .unused, @@ -108149,7 +107980,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .unused, .unused, .unused, @@ -108176,7 +108007,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .unused, .unused, .unused, @@ -108203,7 +108034,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .unused, .unused, .unused, @@ -108230,7 +108061,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .unused, .unused, .unused, @@ -108257,7 +108088,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .unused, .unused, .unused, @@ -108283,7 +108114,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .unused, .unused, .unused, @@ -108309,7 +108140,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdihf" } }, .unused, .unused, .unused, @@ -108335,7 +108166,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundihf" } }, .unused, .unused, .unused, @@ -108361,7 +108192,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattihf" } }, .unused, .unused, .unused, @@ -108387,7 +108218,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntihf" } }, .unused, .unused, .unused, @@ -108415,7 +108246,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateihf" } }, .unused, .unused, .unused, @@ -108443,7 +108274,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneihf" } }, .unused, .unused, .unused, @@ -108647,7 +108478,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108678,7 +108509,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108709,7 +108540,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108740,7 +108571,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108771,7 +108602,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108803,7 +108634,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108835,7 +108666,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -108868,7 +108699,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -108901,7 +108732,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108932,7 +108763,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108963,7 +108794,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -108994,7 +108825,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109025,7 +108856,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109057,7 +108888,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109089,7 +108920,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -109122,7 +108953,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -109331,7 +109162,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109362,7 +109193,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109393,7 +109224,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109425,7 +109256,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -109458,7 +109289,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109489,7 +109320,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109520,7 +109351,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109552,7 +109383,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -109669,7 +109500,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109700,7 +109531,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109731,7 +109562,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109763,7 +109594,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -109796,7 +109627,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109827,7 +109658,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109858,7 +109689,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109890,7 +109721,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -109954,7 +109785,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -109985,7 +109816,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110016,7 +109847,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110048,7 +109879,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -110081,7 +109912,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110112,7 +109943,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110143,7 +109974,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110175,7 +110006,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -110209,7 +110040,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110241,7 +110072,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110273,7 +110104,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110306,7 +110137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -110340,7 +110171,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110372,7 +110203,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110404,7 +110235,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110437,7 +110268,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -110472,7 +110303,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110506,7 +110337,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110540,7 +110371,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110575,7 +110406,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -110611,7 +110442,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110645,7 +110476,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110679,7 +110510,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -110714,7 +110545,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneihf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneihf" } }, .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .mem }, .unused, @@ -111138,7 +110969,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattisf" } }, .unused, .unused, .unused, @@ -111164,7 +110995,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntisf" } }, .unused, .unused, .unused, @@ -111192,7 +111023,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateisf" } }, .unused, .unused, .unused, @@ -111220,7 +111051,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneisf" } }, .unused, .unused, .unused, @@ -111506,7 +111337,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111537,7 +111368,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111568,7 +111399,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111599,7 +111430,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111630,7 +111461,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111661,7 +111492,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111692,7 +111523,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -111723,7 +111554,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112012,7 +111843,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112043,7 +111874,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112074,7 +111905,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112105,7 +111936,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112288,7 +112119,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112319,7 +112150,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112350,7 +112181,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112381,7 +112212,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112472,7 +112303,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112503,7 +112334,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112534,7 +112365,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112565,7 +112396,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112597,7 +112428,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112629,7 +112460,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112661,7 +112492,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112693,7 +112524,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112726,7 +112557,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112760,7 +112591,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112794,7 +112625,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -112828,7 +112659,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneisf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneisf" } }, .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -113468,7 +113299,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattidf" } }, .unused, .unused, .unused, @@ -113494,7 +113325,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntidf" } }, .unused, .unused, .unused, @@ -113522,7 +113353,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateidf" } }, .unused, .unused, .unused, @@ -113550,7 +113381,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneidf" } }, .unused, .unused, .unused, @@ -113844,7 +113675,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -113875,7 +113706,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -113906,7 +113737,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -113937,7 +113768,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -113968,7 +113799,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -113999,7 +113830,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114030,7 +113861,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114061,7 +113892,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114092,7 +113923,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114123,7 +113954,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114154,7 +113985,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114185,7 +114016,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114478,7 +114309,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114509,7 +114340,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114540,7 +114371,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114571,7 +114402,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114602,7 +114433,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114633,7 +114464,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114787,7 +114618,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114818,7 +114649,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114849,7 +114680,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114880,7 +114711,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114911,7 +114742,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -114942,7 +114773,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115033,7 +114864,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115064,7 +114895,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115095,7 +114926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115126,7 +114957,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115157,7 +114988,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115188,7 +115019,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115220,7 +115051,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115252,7 +115083,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115284,7 +115115,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115316,7 +115147,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115348,7 +115179,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115380,7 +115211,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115413,7 +115244,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115447,7 +115278,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115481,7 +115312,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115515,7 +115346,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115549,7 +115380,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115583,7 +115414,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneidf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneidf" } }, .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -115830,7 +115661,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattixf" } }, .unused, .unused, .unused, @@ -115856,7 +115687,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntixf" } }, .unused, .unused, .unused, @@ -115884,7 +115715,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateixf" } }, .unused, .unused, .unused, @@ -115912,7 +115743,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneixf" } }, .unused, .unused, .unused, @@ -116073,7 +115904,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116107,7 +115938,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116141,7 +115972,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116175,7 +116006,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116237,7 +116068,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116269,7 +116100,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116330,7 +116161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116362,7 +116193,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116423,7 +116254,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatdixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatdixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116455,7 +116286,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatundixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatundixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116488,7 +116319,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116521,7 +116352,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116555,7 +116386,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116590,7 +116421,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneixf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneixf" } }, .{ .type = .f80, .kind = .{ .reg = .st7 } }, .unused, .unused, @@ -116623,7 +116454,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .unused, .unused, .unused, @@ -116651,7 +116482,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .unused, .unused, .unused, @@ -116679,7 +116510,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .unused, .unused, .unused, @@ -116707,7 +116538,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .unused, .unused, .unused, @@ -116733,7 +116564,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .unused, .unused, .unused, @@ -116759,7 +116590,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .unused, .unused, .unused, @@ -116785,7 +116616,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatditf" } }, .unused, .unused, .unused, @@ -116811,7 +116642,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunditf" } }, .unused, .unused, .unused, @@ -116837,7 +116668,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattitf" } }, .unused, .unused, .unused, @@ -116863,7 +116694,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, .unused, .unused, .unused, @@ -116891,7 +116722,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateitf" } }, .unused, .unused, .unused, @@ -116919,7 +116750,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneitf" } }, .unused, .unused, .unused, @@ -116948,7 +116779,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -116981,7 +116812,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117014,7 +116845,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117047,7 +116878,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117080,7 +116911,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117113,7 +116944,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117146,7 +116977,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117179,7 +117010,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117212,7 +117043,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117245,7 +117076,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117278,7 +117109,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117311,7 +117142,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117343,7 +117174,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117374,7 +117205,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117405,7 +117236,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117436,7 +117267,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117467,7 +117298,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117498,7 +117329,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117529,7 +117360,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117560,7 +117391,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117591,7 +117422,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117622,7 +117453,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117653,7 +117484,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117684,7 +117515,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u32, .kind = .{ .reg = .edi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunsitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunsitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117715,7 +117546,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatditf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117746,7 +117577,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatditf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117777,7 +117608,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .i64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatditf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117808,7 +117639,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunditf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117839,7 +117670,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunditf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117870,7 +117701,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatunditf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatunditf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117902,7 +117733,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117934,7 +117765,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117966,7 +117797,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .i64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floattitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floattitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -117998,7 +117829,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118030,7 +117861,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118062,7 +117893,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .reg = .rdi } }, .{ .type = .u64, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuntitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuntitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118095,7 +117926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118129,7 +117960,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118163,7 +117994,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floateitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floateitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118197,7 +118028,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118231,7 +118062,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -118265,7 +118096,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .usize, .kind = .{ .reg = .rdi } }, .{ .type = .usize, .kind = .{ .reg = .rsi } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__floatuneitf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__floatuneitf" } }, .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .unused, .unused, @@ -131980,7 +131811,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -132013,7 +131844,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -132048,7 +131879,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -133648,7 +133479,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -133679,7 +133510,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -133710,7 +133541,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -142100,7 +141931,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -142133,7 +141964,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -142168,7 +141999,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -143776,7 +143607,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -143807,7 +143638,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -143838,7 +143669,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -147771,7 +147602,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -147804,7 +147635,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -147839,7 +147670,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -148356,7 +148187,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -148387,7 +148218,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -148418,7 +148249,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -151430,7 +151261,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -151463,7 +151294,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -151498,7 +151329,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -151895,7 +151726,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -151926,7 +151757,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -151957,7 +151788,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -152469,7 +152300,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -152502,7 +152333,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -152537,7 +152368,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fminh" } }, .unused, .unused, .unused, @@ -153617,7 +153448,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -153648,7 +153479,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -153679,7 +153510,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fminq" } }, .unused, .unused, .unused, @@ -154161,7 +153992,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -154194,7 +154025,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -154229,7 +154060,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmaxh" } }, .unused, .unused, .unused, @@ -155309,7 +155140,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -155340,7 +155171,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -155371,7 +155202,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaxq" } }, .unused, .unused, .unused, @@ -156102,7 +155933,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -156135,7 +155966,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -156170,7 +156001,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addhf3" } }, .unused, .unused, .unused, @@ -157568,7 +157399,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -157599,7 +157430,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -157630,7 +157461,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__addtf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__addtf3" } }, .unused, .unused, .unused, @@ -158112,7 +157943,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -158145,7 +157976,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -158180,7 +158011,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .ax } }, .{ .type = .f32, .kind = .mem }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__mulhf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__mulhf3" } }, .unused, .unused, .unused, @@ -159111,7 +158942,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -159142,7 +158973,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -159173,7 +159004,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .u32, .kind = .{ .rc = .general_purpose } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__multf3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__multf3" } }, .unused, .unused, .unused, @@ -161054,7 +160885,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = @tagName(symbol) } } }, + .{ .type = .usize, .kind = .{ .extern_func = @tagName(symbol) } }, .unused, .unused, .unused, @@ -161103,7 +160934,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"32" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src0 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src0 } } }, .unused, .unused, .unused, @@ -161129,7 +160960,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src0 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src0 } } }, .unused, .unused, .unused, @@ -161154,7 +160985,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"8" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src0 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src0 } } }, .unused, .unused, .unused, @@ -161194,7 +161025,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"32" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src0 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src0 } } }, .unused, .unused, .unused, @@ -161219,7 +161050,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src0 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src0 } } }, .unused, .unused, .unused, @@ -161243,7 +161074,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"8" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src0 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src0 } } }, .unused, .unused, .unused, @@ -161282,7 +161113,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_gpr, .none, .none } }, }, .extra_temps = .{ - .{ .type = .anyerror, .kind = .{ .lazy_symbol = .{ .kind = .const_data } } }, + .{ .type = .anyerror, .kind = .{ .lazy_sym = .{ .kind = .const_data } } }, .{ .type = .u32, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } } }, .unused, .unused, @@ -161311,7 +161142,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_gpr, .none, .none } }, }, .extra_temps = .{ - .{ .type = .anyerror, .kind = .{ .lazy_symbol = .{ .kind = .const_data } } }, + .{ .type = .anyerror, .kind = .{ .lazy_sym = .{ .kind = .const_data } } }, .{ .type = .u32, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } } }, .unused, .unused, @@ -161340,7 +161171,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_gpr, .none, .none } }, }, .extra_temps = .{ - .{ .type = .anyerror, .kind = .{ .lazy_symbol = .{ .kind = .const_data } } }, + .{ .type = .anyerror, .kind = .{ .lazy_sym = .{ .kind = .const_data } } }, .{ .type = .u32, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } } }, .unused, .unused, @@ -161391,7 +161222,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"32" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src1 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src1 } } }, .unused, .unused, .unused, @@ -161417,7 +161248,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src1 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src1 } } }, .unused, .unused, .unused, @@ -161442,7 +161273,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"8" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .lazy_symbol = .{ .kind = .code, .ref = .src1 } } }, + .{ .type = .usize, .kind = .{ .lazy_sym = .{ .kind = .code, .ref = .src1 } } }, .unused, .unused, .unused, @@ -161638,7 +161469,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmah" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmah" } }, .unused, .unused, .unused, @@ -161781,7 +161612,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, .{ .type = .f16, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmah" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmah" } }, .unused, .unused, .unused, @@ -161818,7 +161649,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, .{ .type = .f16, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmah" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmah" } }, .unused, .unused, .unused, @@ -161857,7 +161688,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, .{ .type = .f16, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmah" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmah" } }, .{ .type = .f16, .kind = .{ .reg = .ax } }, .unused, .unused, @@ -161899,7 +161730,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f16, .kind = .{ .reg = .xmm0 } }, .{ .type = .f16, .kind = .{ .reg = .xmm1 } }, .{ .type = .f16, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmah" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmah" } }, .unused, .unused, .unused, @@ -161987,7 +161818,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf" } }, .unused, .unused, .unused, @@ -162153,7 +161984,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, .{ .type = .f32, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf" } }, .unused, .unused, .unused, @@ -162189,7 +162020,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f32, .kind = .{ .reg = .xmm0 } }, .{ .type = .f32, .kind = .{ .reg = .xmm1 } }, .{ .type = .f32, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaf" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaf" } }, .unused, .unused, .unused, @@ -162271,7 +162102,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fma" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fma" } }, .unused, .unused, .unused, @@ -162437,7 +162268,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, .{ .type = .f64, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fma" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fma" } }, .unused, .unused, .unused, @@ -162473,7 +162304,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, .{ .type = .f64, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fma" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fma" } }, .unused, .unused, .unused, @@ -162509,7 +162340,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f64, .kind = .{ .reg = .xmm0 } }, .{ .type = .f64, .kind = .{ .reg = .xmm1 } }, .{ .type = .f64, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fma" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fma" } }, .unused, .unused, .unused, @@ -162546,7 +162377,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmax" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmax" } }, .unused, .unused, .unused, @@ -162582,7 +162413,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, .{ .type = .f80, .kind = .{ .reg = .xmm0 } }, .{ .type = .f80, .kind = .{ .frame = .call_frame } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmax" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__fmax" } }, .unused, .unused, .unused, @@ -162619,7 +162450,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, .unused, .unused, .unused, @@ -162652,7 +162483,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .f128, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, .unused, .unused, .unused, @@ -162688,7 +162519,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .f128, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, .unused, .unused, .unused, @@ -162724,7 +162555,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .type = .f128, .kind = .{ .reg = .xmm0 } }, .{ .type = .f128, .kind = .{ .reg = .xmm1 } }, .{ .type = .f128, .kind = .{ .reg = .xmm2 } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaq" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "fmaq" } }, .unused, .unused, .unused, @@ -162778,7 +162609,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_gpr, .none, .none } }, }, .extra_temps = .{ - .{ .type = .anyerror, .kind = .{ .lazy_symbol = .{ .kind = .const_data } } }, + .{ .type = .anyerror, .kind = .{ .lazy_sym = .{ .kind = .const_data } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -162802,7 +162633,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_gpr, .none, .none } }, }, .extra_temps = .{ - .{ .type = .anyerror, .kind = .{ .lazy_symbol = .{ .kind = .const_data } } }, + .{ .type = .anyerror, .kind = .{ .lazy_sym = .{ .kind = .const_data } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -162826,7 +162657,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_gpr, .none, .none } }, }, .extra_temps = .{ - .{ .type = .anyerror, .kind = .{ .lazy_symbol = .{ .kind = .const_data } } }, + .{ .type = .anyerror, .kind = .{ .lazy_sym = .{ .kind = .const_data } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -163517,65 +163348,18 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; for (ops) |op| try op.die(cg); }, - .runtime_nav_ptr => switch (cg.bin_file.tag) { - .elf, .macho => { - const ty_nav = air_datas[@intFromEnum(inst)].ty_nav; - - const nav = ip.getNav(ty_nav.nav); - const sym_index, const relocation = sym: { - if (cg.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - if (nav.getExtern(ip)) |e| { - const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); - linkage: switch (e.linkage) { - .internal => {}, - .strong => switch (e.visibility) { - .default => zo.symbol(sym).flags.is_extern_ptr = true, - .hidden, .protected => {}, - }, - .weak => { - zo.symbol(sym).flags.weak = true; - continue :linkage .strong; - }, - .link_once => unreachable, - } - break :sym .{ sym, e.relocation }; - } else break :sym .{ try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav), .any }; - } else if (cg.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - if (nav.getExtern(ip)) |e| { - const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip)); - linkage: switch (e.linkage) { - .internal => {}, - .strong => switch (e.visibility) { - .default => zo.symbols.items[sym].flags.is_extern_ptr = true, - .hidden, .protected => {}, - }, - .weak => { - zo.symbols.items[sym].flags.weak = true; - continue :linkage .strong; - }, - .link_once => unreachable, - } - break :sym .{ sym, e.relocation }; - } else break :sym .{ try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav), .any }; - } else unreachable; - }; - - if (cg.mod.pic) { - try cg.spillRegisters(&.{ .rdi, .rax }); - } else { - try cg.spillRegisters(&.{.rax}); - } - - var slot = try cg.tempInit(.usize, switch (relocation) { - .any => .{ .lea_symbol = .{ .sym_index = sym_index } }, - .pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } }, - }); - while (try slot.toRegClass(true, .general_purpose, cg)) {} - try slot.finish(inst, &.{}, &.{}, cg); - }, - else => return cg.fail("TODO implement runtime_nav_ptr on {}", .{cg.bin_file.tag}), + .runtime_nav_ptr => { + const ty_nav = air_datas[@intFromEnum(inst)].ty_nav; + const nav = ip.getNav(ty_nav.nav); + const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip); + if (is_threadlocal) if (cg.mod.pic) { + try cg.spillRegisters(&.{ .rdi, .rax }); + } else { + try cg.spillRegisters(&.{.rax}); + }; + var res = try cg.tempInit(.fromInterned(ty_nav.ty), .{ .lea_nav = ty_nav.nav }); + if (is_threadlocal) while (try res.toRegClass(true, .general_purpose, cg)) {}; + try res.finish(inst, &.{}, &.{}, cg); }, .c_va_arg => try cg.airVaArg(inst), .c_va_copy => try cg.airVaCopy(inst), @@ -164231,11 +164015,11 @@ fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void { }, else => unreachable, }) { - var callee_buf: ["__trunc?f?f2".len]u8 = undefined; - break :result try self.genCall(.{ .lib = .{ + var sym_buf: ["__trunc?f?f2".len]u8 = undefined; + break :result try self.genCall(.{ .extern_func = .{ .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(), .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "__trunc{c}f{c}f2", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__trunc{c}f{c}f2", .{ floatCompilerRtAbiName(src_bits), floatCompilerRtAbiName(dst_bits), }) catch unreachable, @@ -164335,11 +164119,11 @@ fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void { else => unreachable, }) { if (dst_ty.isVector(zcu)) break :result null; - var callee_buf: ["__extend?f?f2".len]u8 = undefined; - break :result try self.genCall(.{ .lib = .{ + var sym_buf: ["__extend?f?f2".len]u8 = undefined; + break :result try self.genCall(.{ .extern_func = .{ .return_type = self.floatCompilerRtAbiType(dst_scalar_ty, src_scalar_ty).toIntern(), .param_types = &.{self.floatCompilerRtAbiType(src_scalar_ty, dst_scalar_ty).toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "__extend{c}f{c}f2", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__extend{c}f{c}f2", .{ floatCompilerRtAbiName(src_bits), floatCompilerRtAbiName(dst_bits), }) catch unreachable, @@ -164776,7 +164560,7 @@ fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void { .storage = .{ .repeated_elem = mask_val.ip_index }, } }); - const splat_mcv = try self.genTypedValue(.fromInterned(splat_val)); + const splat_mcv = try self.lowerValue(.fromInterned(splat_val)); const splat_addr_mcv: MCValue = switch (splat_mcv) { .memory, .indirect, .load_frame => splat_mcv.address(), else => .{ .register = try self.copyToTmpRegister(.usize, splat_mcv.address()) }, @@ -164975,7 +164759,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void .mul, .mul_wrap => {}, .div_trunc, .div_floor, .div_exact, .rem, .mod => { const signed = dst_ty.isSignedInt(zcu); - var callee_buf: ["__udiv?i3".len]u8 = undefined; + var sym_buf: ["__udiv?i3".len]u8 = undefined; const signed_div_floor_state: struct { frame_index: FrameIndex, state: State, @@ -164994,7 +164778,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void const lhs_mcv = try self.resolveInst(bin_op.lhs); const mat_lhs_mcv = switch (lhs_mcv) { - .load_symbol => mat_lhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_lhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -165018,7 +164802,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void const rhs_mcv = try self.resolveInst(bin_op.rhs); const mat_rhs_mcv = switch (rhs_mcv) { - .load_symbol => mat_rhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_rhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -165045,10 +164829,10 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void break :state .{ .frame_index = frame_index, .state = state, .reloc = reloc }; } else undefined; const call_mcv = try self.genCall( - .{ .lib = .{ + .{ .extern_func = .{ .return_type = dst_ty.toIntern(), .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() }, - .callee = std.fmt.bufPrint(&callee_buf, "__{s}{s}{c}i3", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__{s}{s}{c}i3", .{ if (signed) "" else "u", switch (tag) { .div_trunc, .div_exact => "div", @@ -165082,10 +164866,10 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void }); self.performReloc(signed_div_floor_state.reloc); const dst_mcv = try self.genCall( - .{ .lib = .{ + .{ .extern_func = .{ .return_type = dst_ty.toIntern(), .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() }, - .callee = std.fmt.bufPrint(&callee_buf, "__div{c}i3", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__div{c}i3", .{ intCompilerRtAbiName(@intCast(dst_ty.bitSize(zcu))), }) catch unreachable, } }, @@ -165119,7 +164903,7 @@ fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void const rhs_mcv = try self.resolveInst(bin_op.rhs); const mat_rhs_mcv = switch (rhs_mcv) { - .load_symbol => mat_rhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_rhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -165333,10 +165117,10 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void { const ptr_c_int = try pt.singleMutPtrType(.c_int); const overflow = try self.allocTempRegOrMem(.c_int, false); - const dst_mcv = try self.genCall(.{ .lib = .{ + const dst_mcv = try self.genCall(.{ .extern_func = .{ .return_type = .i128_type, .param_types = &.{ .i128_type, .i128_type, ptr_c_int.toIntern() }, - .callee = "__muloti4", + .sym = "__muloti4", } }, &.{ .i128, .i128, ptr_c_int }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs }, @@ -165351,7 +165135,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void { const lhs_mcv = try self.resolveInst(bin_op.lhs); const mat_lhs_mcv = switch (lhs_mcv) { - .load_symbol => mat_lhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_lhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -165375,7 +165159,7 @@ fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void { const rhs_mcv = try self.resolveInst(bin_op.rhs); const mat_rhs_mcv = switch (rhs_mcv) { - .load_symbol => mat_rhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_rhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -165849,10 +165633,10 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { .signed => { const ptr_c_int = try pt.singleMutPtrType(.c_int); const overflow = try self.allocTempRegOrMem(.c_int, false); - const result = try self.genCall(.{ .lib = .{ + const result = try self.genCall(.{ .extern_func = .{ .return_type = .i128_type, .param_types = &.{ .i128_type, .i128_type, ptr_c_int.toIntern() }, - .callee = "__muloti4", + .sym = "__muloti4", } }, &.{ .i128, .i128, ptr_c_int }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs }, @@ -165906,7 +165690,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { break :mat_lhs_mcv mat_lhs_mcv; }, }, - .load_symbol => { + .load_nav, .load_uav, .load_lazy_sym => { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -165930,7 +165714,7 @@ fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void { break :mat_rhs_mcv mat_rhs_mcv; }, }, - .load_symbol => { + .load_nav, .load_uav, .load_lazy_sym => { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -166406,7 +166190,7 @@ fn airShlShrBinOp(self: *CodeGen, inst: Air.Inst.Index) !void { defer self.register_manager.unlockReg(shift_lock); const mask_ty = try pt.vectorType(.{ .len = 16, .child = .u8_type }); - const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ + const mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = mask_ty.toIntern(), .storage = .{ .elems = &([1]InternPool.Index{ (try rhs_ty.childType(zcu).maxIntScalar(pt, .u8)).toIntern(), @@ -166547,7 +166331,7 @@ fn airShlSat(self: *CodeGen, inst: Air.Inst.Index) !void { // if lhs is negative, it is min switch (lhs_ty.intInfo(zcu).signedness) { .unsigned => { - const bound_mcv = try self.genTypedValue(try lhs_ty.maxIntScalar(self.pt, lhs_ty)); + const bound_mcv = try self.lowerValue(try lhs_ty.maxIntScalar(self.pt, lhs_ty)); try self.genCopy(lhs_ty, dst_mcv, bound_mcv, .{}); }, .signed => { @@ -166556,7 +166340,7 @@ fn airShlSat(self: *CodeGen, inst: Air.Inst.Index) !void { // we only need the highest bit so shifting the highest part of lhs_mcv // is enough to check the signedness. other parts can be skipped here. var lhs_temp2 = try self.tempInit(lhs_ty, lhs_mcv); - var zero_temp = try self.tempInit(lhs_ty, try self.genTypedValue(try self.pt.intValue(lhs_ty, 0))); + var zero_temp = try self.tempInit(lhs_ty, try self.lowerValue(try self.pt.intValue(lhs_ty, 0))); const sign_cc_temp = lhs_temp2.cmpInts(.lt, &zero_temp, self) catch |err| switch (err) { error.SelectFailed => unreachable, else => |e| return e, @@ -166567,13 +166351,13 @@ fn airShlSat(self: *CodeGen, inst: Air.Inst.Index) !void { try sign_cc_temp.die(self); // if it is negative - const min_mcv = try self.genTypedValue(try lhs_ty.minIntScalar(self.pt, lhs_ty)); + const min_mcv = try self.lowerValue(try lhs_ty.minIntScalar(self.pt, lhs_ty)); try self.genCopy(lhs_ty, dst_mcv, min_mcv, .{}); const sign_reloc_br = try self.asmJmpReloc(undefined); self.performReloc(sign_reloc_condbr); // if it is positive - const max_mcv = try self.genTypedValue(try lhs_ty.maxIntScalar(self.pt, lhs_ty)); + const max_mcv = try self.lowerValue(try lhs_ty.maxIntScalar(self.pt, lhs_ty)); try self.genCopy(lhs_ty, dst_mcv, max_mcv, .{}); self.performReloc(sign_reloc_br); }, @@ -167294,7 +167078,12 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { }.to64(), ), }, - .memory, .load_symbol, .load_direct, .load_got => switch (index_mcv) { + .memory, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => switch (index_mcv) { .immediate => |index_imm| try self.asmMemoryImmediate( .{ ._, .bt }, .{ @@ -167356,11 +167145,15 @@ fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void { }, ), .memory, - .load_symbol, - .load_direct, - .load_got, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}), - .lea_symbol, .lea_direct => unreachable, else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{ @tagName(array_mcv), array_ty.fmt(pt), }), @@ -168461,7 +168254,7 @@ fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: A .child = (try pt.intType(.signed, scalar_bits)).ip_index, }); - const sign_mcv = try self.genTypedValue(switch (tag) { + const sign_mcv = try self.lowerValue(switch (tag) { .neg => try vec_ty.minInt(pt, vec_ty), .abs => try vec_ty.maxInt(pt, vec_ty), else => unreachable, @@ -168603,11 +168396,11 @@ fn genRoundLibcall(self: *CodeGen, ty: Type, src_mcv: MCValue, mode: bits.RoundM if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement genRound for {}", .{ty.fmt(pt)}); - var callee_buf: ["__trunc?".len]u8 = undefined; - return try self.genCall(.{ .lib = .{ + var sym_buf: ["__trunc?".len]u8 = undefined; + return try self.genCall(.{ .extern_func = .{ .return_type = ty.toIntern(), .param_types = &.{ty.toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "{s}{s}{s}", .{ + .sym = std.fmt.bufPrint(&sym_buf, "{s}{s}{s}", .{ floatLibcAbiPrefix(ty), switch (mode.direction) { .down => "floor", @@ -168880,11 +168673,11 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void { 80, 128 => true, else => unreachable, }) { - var callee_buf: ["__sqrt?".len]u8 = undefined; - break :result try self.genCall(.{ .lib = .{ + var sym_buf: ["__sqrt?".len]u8 = undefined; + break :result try self.genCall(.{ .extern_func = .{ .return_type = ty.toIntern(), .param_types = &.{ty.toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "{s}sqrt{s}", .{ + .sym = std.fmt.bufPrint(&sym_buf, "{s}sqrt{s}", .{ floatLibcAbiPrefix(ty), floatLibcAbiSuffix(ty), }) catch unreachable, @@ -169033,11 +168826,11 @@ fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void { fn airUnaryMath(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ty = self.typeOf(un_op); - var callee_buf: ["__round?".len]u8 = undefined; - const result = try self.genCall(.{ .lib = .{ + var sym_buf: ["__round?".len]u8 = undefined; + const result = try self.genCall(.{ .extern_func = .{ .return_type = ty.toIntern(), .param_types = &.{ty.toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "{s}{s}{s}", .{ + .sym = std.fmt.bufPrint(&sym_buf, "{s}{s}{s}", .{ floatLibcAbiPrefix(ty), switch (tag) { .sin, @@ -169237,19 +169030,19 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE .immediate, .register, .register_offset, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref(), .{}), .memory, .indirect, - .load_symbol, - .load_pcrel, - .load_direct, - .load_got, .load_frame, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, => { const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); @@ -169457,19 +169250,19 @@ fn store( .immediate, .register, .register_offset, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv, opts), .memory, .indirect, - .load_symbol, - .load_pcrel, - .load_direct, - .load_got, .load_frame, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, => { const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv); const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); @@ -169935,18 +169728,18 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: .eflags, .register_overflow, .register_mask, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, => unreachable, // unmodifiable destination .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented - .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => { + .memory, .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => { const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); defer self.register_manager.unlockReg(addr_reg_lock); @@ -170706,7 +170499,7 @@ fn genMulDivBinOp( defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); const mat_lhs_mcv = switch (lhs_mcv) { - .load_symbol => mat_lhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_lhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address()); break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -170719,7 +170512,7 @@ fn genMulDivBinOp( }; defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock); const mat_rhs_mcv = switch (rhs_mcv) { - .load_symbol => mat_rhs_mcv: { + .load_nav, .load_uav, .load_lazy_sym => mat_rhs_mcv: { // TODO clean this up! const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address()); break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } }; @@ -170887,7 +170680,7 @@ fn genMulDivBinOp( .is_const = true, }, }); - _ = try self.genCall(.{ .lib = .{ + _ = try self.genCall(.{ .extern_func = .{ .return_type = .void_type, .param_types = &.{ manyptr_u32_ty.toIntern(), @@ -170895,7 +170688,7 @@ fn genMulDivBinOp( manyptr_const_u32_ty.toIntern(), .usize_type, }, - .callee = switch (tag) { + .sym = switch (tag) { .div_trunc, .div_floor, .div_exact, @@ -171118,8 +170911,8 @@ fn genBinOp( .rem, .mod => {}, else => if (!type_needs_libcall) break :libcall, } - var callee_buf: ["__mod?f3".len]u8 = undefined; - const callee = switch (air_tag) { + var sym_buf: ["__mod?f3".len]u8 = undefined; + const sym = switch (air_tag) { .add, .sub, .mul, @@ -171127,11 +170920,11 @@ fn genBinOp( .div_trunc, .div_floor, .div_exact, - => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{ + => std.fmt.bufPrint(&sym_buf, "__{s}{c}f3", .{ @tagName(air_tag)[0..3], floatCompilerRtAbiName(float_bits), }), - .rem, .mod, .min, .max => std.fmt.bufPrint(&callee_buf, "{s}f{s}{s}", .{ + .rem, .mod, .min, .max => std.fmt.bufPrint(&sym_buf, "{s}f{s}{s}", .{ floatLibcAbiPrefix(lhs_ty), switch (air_tag) { .rem, .mod => "mod", @@ -171145,22 +170938,22 @@ fn genBinOp( @tagName(air_tag), lhs_ty.fmt(pt), }), } catch unreachable; - const result = try self.genCall(.{ .lib = .{ + const result = try self.genCall(.{ .extern_func = .{ .return_type = lhs_ty.toIntern(), .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, - .callee = callee, + .sym = sym, } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }, .{}); return switch (air_tag) { .mod => result: { const adjusted: MCValue = if (type_needs_libcall) adjusted: { - var add_callee_buf: ["__add?f3".len]u8 = undefined; - break :adjusted try self.genCall(.{ .lib = .{ + var add_sym_buf: ["__add?f3".len]u8 = undefined; + break :adjusted try self.genCall(.{ .extern_func = .{ .return_type = lhs_ty.toIntern(), .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern(), }, - .callee = std.fmt.bufPrint(&add_callee_buf, "__add{c}f3", .{ + .sym = std.fmt.bufPrint(&add_sym_buf, "__add{c}f3", .{ floatCompilerRtAbiName(float_bits), }) catch unreachable, } }, &.{ lhs_ty, rhs_ty }, &.{ result, .{ .air_ref = rhs_air } }, .{}); @@ -171259,10 +171052,10 @@ fn genBinOp( }), else => unreachable, }; - break :result try self.genCall(.{ .lib = .{ + break :result try self.genCall(.{ .extern_func = .{ .return_type = lhs_ty.toIntern(), .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() }, - .callee = callee, + .sym = sym, } }, &.{ lhs_ty, rhs_ty }, &.{ adjusted, .{ .air_ref = rhs_air } }, .{}); }, .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{ @@ -171545,13 +171338,15 @@ fn genBinOp( .immediate, .eflags, .register_offset, - .load_symbol, - .lea_symbol, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .lea_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => true, .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null, else => false, @@ -171604,15 +171399,15 @@ fn genBinOp( .register_offset, .register_overflow, .register_mask, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .lea_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -172710,7 +172505,7 @@ fn genBinOp( .cmp_neq, => { const unsigned_ty = try lhs_ty.toUnsigned(pt); - const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(pt, unsigned_ty)); + const not_mcv = try self.lowerValue(try unsigned_ty.maxInt(pt, unsigned_ty)); const not_mem: Memory = if (not_mcv.isBase()) try not_mcv.mem(self, .{ .size = .fromSize(abi_size) }) else @@ -172792,11 +172587,11 @@ fn genBinOpMir( .eflags, .register_overflow, .register_mask, - .lea_direct, - .lea_got, .lea_frame, - .lea_symbol, - .lea_pcrel, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -172886,16 +172681,16 @@ fn genBinOpMir( .register_offset, .memory, .indirect, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .load_frame, .lea_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => { direct: { try self.asmRegisterMemory(mir_limb_tag, dst_alias, switch (src_mcv) { @@ -172928,10 +172723,11 @@ fn genBinOpMir( switch (src_mcv) { .eflags, .register_offset, - .lea_symbol, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, => { assert(off == 0); const reg = try self.copyToTmpRegister(ty, src_mcv); @@ -172943,9 +172739,10 @@ fn genBinOpMir( ); }, .memory, - .load_symbol, - .load_direct, - .load_got, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, => { const ptr_ty = try pt.singleConstPtrType(ty); const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); @@ -172965,13 +172762,20 @@ fn genBinOpMir( } } }, - .memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => { + .memory, + .indirect, + .load_frame, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => { const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock }; const limb_abi_size: u32 = @min(abi_size, 8); const dst_info: OpInfo = switch (dst_mcv) { else => unreachable, - .memory, .load_symbol, .load_got, .load_direct => dst: { + .memory, .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => dst: { const dst_addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg); @@ -173007,19 +172811,24 @@ fn genBinOpMir( .register_quadruple, .register_offset, .indirect, - .lea_direct, - .lea_got, .load_frame, .lea_frame, - .lea_symbol, - .lea_pcrel, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, => null, - .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: { + .memory, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => src: { switch (resolved_src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null) break :src null, - .load_symbol, .load_got, .load_direct => {}, + .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => {}, else => unreachable, } @@ -173059,9 +172868,10 @@ fn genBinOpMir( }; const dst_limb_mem: Memory = switch (dst_mcv) { .memory, - .load_symbol, - .load_got, - .load_direct, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, => .{ .base = .{ .reg = dst_info.?.addr_reg }, .mod = .{ .rm = .{ @@ -173151,16 +172961,16 @@ fn genBinOpMir( .eflags, .memory, .indirect, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .load_frame, .lea_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => { const src_limb_mcv: MCValue = if (src_info) |info| .{ .indirect = .{ .reg = info.addr_reg, .off = off }, @@ -173170,10 +172980,11 @@ fn genBinOpMir( }, .eflags, .register_offset, - .lea_symbol, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, => switch (limb_i) { 0 => resolved_src_mcv, else => .{ .immediate = 0 }, @@ -173221,11 +173032,11 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv .register_offset, .register_overflow, .register_mask, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -173283,15 +173094,15 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv }, .register_offset, .eflags, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .lea_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => { const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv); switch (abi_size) { @@ -173346,7 +173157,14 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv } }, .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented - .memory, .indirect, .load_symbol, .load_pcrel, .load_direct, .load_got, .load_frame => { + .memory, + .indirect, + .load_frame, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => { const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); const tmp_mcv = MCValue{ .register = tmp_reg }; const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); @@ -173359,16 +173177,14 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv } fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void { - const pt = self.pt; - const zcu = pt.zcu; - // 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; - self.arg_index = arg_index + 1; - - const result: MCValue = if (self.debug_output == .none and self.liveness.isUnused(inst)) .unreach else result: { + const zcu = self.pt.zcu; + const arg_index = for (self.args, 0..) |arg, arg_index| { + if (arg != .none) break arg_index; + } else unreachable; + const src_mcv = self.args[arg_index]; + self.args = self.args[arg_index + 1 ..]; + const result: MCValue = if (self.mod.strip and self.liveness.isUnused(inst)) .unreach else result: { const arg_ty = self.typeOfIndex(inst); - const src_mcv = self.args[arg_index]; switch (src_mcv) { .register, .register_pair, .load_frame => { for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst); @@ -173467,68 +173283,115 @@ fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ .none, .none, .none }); } -fn airDbgVarArgs(self: *CodeGen) !void { - if (self.debug_output == .none) return; - if (!self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args) return; - try self.asmPseudo(.pseudo_dbg_var_args_none); -} - -fn genLocalDebugInfo( - self: *CodeGen, - inst: Air.Inst.Index, - mcv: MCValue, -) !void { - if (self.debug_output == .none) return; - switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) { +fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue) !void { + assert(!cg.mod.strip); + _ = switch (air_tag) { else => unreachable, - .arg, .dbg_arg_inline, .dbg_var_val => |tag| { - switch (mcv) { - .none => try self.asmAir(.dbg_local, inst), - .unreach, .dead, .elementwise_args, .reserved_frame, .air_ref => unreachable, - .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, .u(imm)), - .lea_frame => |frame_addr| try self.asmAirFrameAddress(.dbg_local, inst, frame_addr), - .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, .rel(sym_off)), - else => { - const ty = switch (tag) { - else => unreachable, - .arg => self.typeOfIndex(inst), - .dbg_arg_inline, .dbg_var_val => self.typeOf( - self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op.operand, - ), - }; - const frame_index = try self.allocFrameIndex(.initSpill(ty, self.pt.zcu)); - try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{}); - try self.asmAirMemory(.dbg_local, inst, .{ - .base = .{ .frame = frame_index }, - .mod = .{ .rm = .{ .size = .qword } }, - }); + .arg, .dbg_var_val, .dbg_arg_inline => switch (mcv) { + .none, .unreach, .dead, .elementwise_args, .reserved_frame, .air_ref => unreachable, + .immediate => |imm| if (std.math.cast(u32, imm)) |small| try cg.addInst(.{ + .tag = .pseudo, + .ops = switch (air_tag) { + else => unreachable, + .arg, .dbg_arg_inline => .pseudo_dbg_arg_i_u, + .dbg_var_val => .pseudo_dbg_var_i_u, }, - } + .data = .{ .i = .{ .i = small } }, + }) else try cg.addInst(.{ + .tag = .pseudo, + .ops = switch (air_tag) { + else => unreachable, + .arg, .dbg_arg_inline => .pseudo_dbg_arg_i_64, + .dbg_var_val => .pseudo_dbg_var_i_64, + }, + .data = .{ .i64 = imm }, + }), + .lea_frame => |frame_addr| try cg.addInst(.{ + .tag = .pseudo, + .ops = switch (air_tag) { + else => unreachable, + .arg, .dbg_arg_inline => .pseudo_dbg_arg_fa, + .dbg_var_val => .pseudo_dbg_var_fa, + }, + .data = .{ .fa = frame_addr }, + }), + else => { + const frame_index = try cg.allocFrameIndex(.initSpill(ty, cg.pt.zcu)); + try cg.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{}); + _ = try cg.addInst(.{ + .tag = .pseudo, + .ops = switch (air_tag) { + else => unreachable, + .arg, .dbg_arg_inline => .pseudo_dbg_arg_m, + .dbg_var_val => .pseudo_dbg_var_m, + }, + .data = .{ .x = .{ + .payload = try cg.addExtra(Mir.Memory.encode(.{ + .base = .{ .frame = frame_index }, + .mod = .{ .rm = .{ .size = .qword } }, + })), + } }, + }); + }, }, .dbg_var_ptr => switch (mcv) { else => unreachable, - .unreach, .dead, .elementwise_args, .reserved_frame, .air_ref => unreachable, - .lea_frame => |frame_addr| try self.asmAirMemory(.dbg_local, inst, .{ - .base = .{ .frame = frame_addr.index }, - .mod = .{ .rm = .{ - .size = .qword, - .disp = frame_addr.off, + .none, .unreach, .dead, .elementwise_args, .reserved_frame, .air_ref => unreachable, + .lea_frame => |frame_addr| try cg.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_var_m, + .data = .{ .x = .{ + .payload = try cg.addExtra(Mir.Memory.encode(.{ + .base = .{ .frame = frame_addr.index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = frame_addr.off, + } }, + })), } }, }), - // debug info should explicitly ignore pcrel requirements - .lea_symbol, .lea_pcrel => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{ - .base = .{ .reloc = sym_off.sym_index }, - .mod = .{ .rm = .{ - .size = .qword, - .disp = sym_off.off, + .lea_nav => |nav| try cg.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_var_m, + .data = .{ .x = .{ + .payload = try cg.addExtra(Mir.Memory.encode(.{ + .base = .{ .nav = nav }, + .mod = .{ .rm = .{ .size = .qword } }, + })), + } }, + }), + .lea_uav => |uav| try cg.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_var_m, + .data = .{ .x = .{ + .payload = try cg.addExtra(Mir.Memory.encode(.{ + .base = .{ .uav = uav }, + .mod = .{ .rm = .{ .size = .qword } }, + })), } }, }), - .lea_direct, .lea_got => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{ - .base = .{ .reloc = sym_index }, - .mod = .{ .rm = .{ .size = .qword } }, + .lea_lazy_sym => |lazy_sym| try cg.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_var_m, + .data = .{ .x = .{ + .payload = try cg.addExtra(Mir.Memory.encode(.{ + .base = .{ .lazy_sym = lazy_sym }, + .mod = .{ .rm = .{ .size = .qword } }, + })), + } }, + }), + .lea_extern_func => |extern_func| try cg.addInst(.{ + .tag = .pseudo, + .ops = .pseudo_dbg_var_m, + .data = .{ .x = .{ + .payload = try cg.addExtra(Mir.Memory.encode(.{ + .base = .{ .extern_func = extern_func }, + .mod = .{ .rm = .{ .size = .qword } }, + })), + } }, }), }, - } + }; } fn airRetAddr(self: *CodeGen, inst: Air.Inst.Index) !void { @@ -173552,8 +173415,8 @@ fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif @ptrCast(self.air.extra.items[extra.end..][0..extra.data.args_len]); const ExpectedContents = extern struct { - tys: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), - vals: [16][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)), + tys: [32][@sizeOf(Type)]u8 align(@alignOf(Type)), + vals: [32][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)), }; var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); @@ -173579,11 +173442,10 @@ fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif fn genCall(self: *CodeGen, info: union(enum) { air: Air.Inst.Ref, - lib: struct { + extern_func: struct { return_type: InternPool.Index, param_types: []const InternPool.Index, - lib: ?[]const u8 = null, - callee: []const u8, + sym: []const u8, }, }, arg_types: []const Type, args: []const MCValue, opts: CopyOptions) !MCValue { const pt = self.pt; @@ -173599,18 +173461,18 @@ fn genCall(self: *CodeGen, info: union(enum) { else => unreachable, }; }, - .lib => |lib| try pt.funcType(.{ - .param_types = lib.param_types, - .return_type = lib.return_type, + .extern_func => |extern_func| try pt.funcType(.{ + .param_types = extern_func.param_types, + .return_type = extern_func.return_type, .cc = self.target.cCallingConvention().?, }), }; const fn_info = zcu.typeToFunc(fn_ty).?; const ExpectedContents = extern struct { - var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), - frame_indices: [16]FrameIndex, - reg_locks: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), + var_args: [32][@sizeOf(Type)]u8 align(@alignOf(Type)), + frame_indices: [32]FrameIndex, + reg_locks: [32][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), }; var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); @@ -173830,52 +173692,9 @@ fn genCall(self: *CodeGen, info: union(enum) { else => func_key, } else func_key, }) { - .func => |func| { - if (self.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - const sym_index = try zo.getOrCreateMetadataForNav(zcu, func.owner_nav); - try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym_index })); - } else if (self.bin_file.cast(.coff)) |coff_file| { - const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav); - const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; - const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); - try self.genSetReg(scratch_reg, .usize, .{ .lea_got = sym_index }, .{}); - try self.asmRegister(.{ ._, .call }, scratch_reg); - } else if (self.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav); - const sym = zo.symbols.items[sym_index]; - try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym.nlist_idx })); - } else if (self.bin_file.cast(.plan9)) |p9| { - const atom_index = try p9.seeNav(pt, func.owner_nav); - const atom = p9.getAtom(atom_index); - try self.asmMemory(.{ ._, .call }, .{ - .base = .{ .reg = .ds }, - .mod = .{ .rm = .{ - .size = .qword, - .disp = @intCast(atom.getOffsetTableAddress(p9)), - } }, - }); - } else unreachable; - }, - .@"extern" => |@"extern"| if (self.bin_file.cast(.elf)) |elf_file| { - const target_sym_index = try elf_file.getGlobalSymbol( - @"extern".name.toSlice(ip), - @"extern".lib_name.toSlice(ip), - ); - try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); - } else if (self.bin_file.cast(.macho)) |macho_file| { - const target_sym_index = try macho_file.getGlobalSymbol( - @"extern".name.toSlice(ip), - @"extern".lib_name.toSlice(ip), - ); - try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); - } else try self.genExternSymbolRef( - .call, - @"extern".lib_name.toSlice(ip), - @"extern".name.toSlice(ip), - ), - else => return self.fail("TODO implement calling bitcasted functions", .{}), + else => unreachable, + .func => |func| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = func.owner_nav } }), + .@"extern" => |@"extern"| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = @"extern".owner_nav } }), } } else { assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer); @@ -173883,13 +173702,7 @@ fn genCall(self: *CodeGen, info: union(enum) { try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{}); try self.asmRegister(.{ ._, .call }, scratch_reg); }, - .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| { - const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib); - try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); - } else if (self.bin_file.cast(.macho)) |macho_file| { - const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib); - try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index })); - } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), + .extern_func => |extern_func| try self.asmImmediate(.{ ._, .call }, .{ .extern_func = try self.addString(extern_func.sym) }), } return call_info.return_value.short; } @@ -174023,11 +173836,11 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v 80, 128 => false, else => unreachable, }) { - var callee_buf: ["__???f2".len]u8 = undefined; - const ret = try self.genCall(.{ .lib = .{ + var sym_buf: ["__???f2".len]u8 = undefined; + const ret = try self.genCall(.{ .extern_func = .{ .return_type = .i32_type, .param_types = &.{ ty.toIntern(), ty.toIntern() }, - .callee = std.fmt.bufPrint(&callee_buf, "__{s}{c}f2", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__{s}{c}f2", .{ switch (op) { .eq => "eq", .neq => "ne", @@ -174170,17 +173983,27 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .register_overflow, .register_mask, .indirect, - .lea_direct, - .lea_got, .lea_frame, - .lea_symbol, - .lea_pcrel, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, => unreachable, - .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null, - .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => dst: { + .register, + .register_pair, + .register_triple, + .register_quadruple, + .load_frame, + => null, + .memory, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => dst: { switch (resolved_dst_mcv) { .memory => |addr| if (std.math.cast( i32, @@ -174189,7 +174012,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :dst null, - .load_symbol, .load_pcrel, .load_got, .load_direct => {}, + .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => {}, else => unreachable, } @@ -174226,17 +174049,26 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v .register_overflow, .register_mask, .indirect, - .lea_symbol, - .lea_pcrel, - .lea_direct, - .lea_got, .lea_frame, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, => unreachable, - .register_pair, .register_triple, .register_quadruple, .load_frame => null, - .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: { + .register_pair, + .register_triple, + .register_quadruple, + .load_frame, + => null, + .memory, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => src: { switch (resolved_src_mcv) { .memory => |addr| if (std.math.cast( i32, @@ -174245,7 +174077,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v i32, @as(i64, @bitCast(addr)) + abi_size - 8, ) != null) break :src null, - .load_symbol, .load_pcrel, .load_got, .load_direct => {}, + .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => {}, else => unreachable, } @@ -174526,10 +174358,31 @@ fn genTry( return result; } -fn airDbgVar(self: *CodeGen, inst: Air.Inst.Index) !void { - const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - try self.genLocalDebugInfo(inst, try self.resolveInst(pl_op.operand)); - return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); +fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { + if (cg.mod.strip) return; + const air_tag = cg.air.instructions.items(.tag)[@intFromEnum(inst)]; + const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; + const air_name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); + const op_ty = cg.typeOf(pl_op.operand); + const local_ty = switch (air_tag) { + else => unreachable, + .dbg_var_ptr => op_ty.childType(cg.pt.zcu), + .dbg_var_val, .dbg_arg_inline => op_ty, + }; + + try cg.mir_locals.append(cg.gpa, .{ + .name = switch (air_name) { + .none => switch (air_tag) { + else => unreachable, + .dbg_arg_inline => .none, + }, + else => try cg.addString(air_name.toSlice(cg.air)), + }, + .type = local_ty.toIntern(), + }); + + try cg.genLocalDebugInfo(air_tag, local_ty, try cg.resolveInst(pl_op.operand)); + return cg.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none }); } fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index { @@ -174633,10 +174486,10 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) .register_offset, .register_overflow, .register_mask, - .lea_direct, - .lea_got, - .lea_symbol, - .lea_pcrel, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -174684,10 +174537,10 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) }, .memory, - .load_symbol, - .load_pcrel, - .load_got, - .load_direct, + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, => { const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); @@ -175721,7 +175574,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_| break :arg input_mcv, .indirect, .load_frame => break :arg input_mcv, - .load_symbol, .load_direct, .load_got => {}, + .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => {}, else => { const temp_mcv = try self.allocTempRegOrMem(ty, false); try self.genCopy(ty, temp_mcv, input_mcv, .{}); @@ -176000,12 +175853,20 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { } } else return self.fail("invalid modifier: '{s}'", .{modifier}), - .lea_got => |sym_index| if (std.mem.eql(u8, modifier, "P")) - .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_got = sym_index }) } + .lea_nav => |nav| if (std.mem.eql(u8, modifier, "P")) + .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_nav = nav }) } + else + return self.fail("invalid modifier: '{s}'", .{modifier}), + .lea_uav => |uav| if (std.mem.eql(u8, modifier, "P")) + .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_uav = uav }) } + else + return self.fail("invalid modifier: '{s}'", .{modifier}), + .lea_lazy_sym => |lazy_sym| if (std.mem.eql(u8, modifier, "P")) + .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_lazy_sym = lazy_sym }) } else return self.fail("invalid modifier: '{s}'", .{modifier}), - .lea_symbol => |sym_off| if (std.mem.eql(u8, modifier, "P")) - .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_symbol = sym_off }) } + .lea_extern_func => |extern_func| if (std.mem.eql(u8, modifier, "P")) + .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_extern_func = extern_func }) } else return self.fail("invalid modifier: '{s}'", .{modifier}), else => return self.fail("invalid constraint: '{s}'", .{op_str}), @@ -176689,11 +176550,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C .eflags, .register_overflow, .register_mask, - .lea_direct, - .lea_got, .lea_frame, - .lea_symbol, - .lea_pcrel, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -176788,7 +176649,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C } return; }, - .load_symbol, .load_pcrel, .load_direct, .load_got => { + .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => { const src_addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64(); const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg); @@ -176821,7 +176682,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef, dst_tag => |src_regs| .{ .register = src_regs[part_i] }, .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(), - .load_symbol, .load_pcrel, .load_direct, .load_got => .{ .indirect = .{ + .load_nav, + .load_uav, + .load_lazy_sym, + .load_extern_func, + => .{ .indirect = .{ .reg = src_info.?.addr_reg, .off = part_disp, } }, @@ -176842,11 +176707,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C src_mcv, opts, ), - .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => { + .memory => { switch (dst_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts), - .load_symbol, .load_pcrel, .load_direct, .load_got => {}, + .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => {}, else => unreachable, } @@ -176863,6 +176728,10 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C src_mcv, opts, ), + .load_nav => |nav| try self.genSetMem(.{ .nav = nav }, 0, ty, src_mcv, opts), + .load_uav => |uav| try self.genSetMem(.{ .uav = uav }, 0, ty, src_mcv, opts), + .load_lazy_sym => |lazy_sym| try self.genSetMem(.{ .lazy_sym = lazy_sym }, 0, ty, src_mcv, opts), + .load_extern_func => |extern_func| try self.genSetMem(.{ .extern_func = extern_func }, 0, ty, src_mcv, opts), } } @@ -176907,14 +176776,14 @@ fn genSetReg( .len = self.vectorSize(.float), .child = .u8_type, }); - try self.genSetReg(dst_reg, full_ty, try self.genTypedValue( + try self.genSetReg(dst_reg, full_ty, try self.lowerValue( .fromInterned(try pt.intern(.{ .aggregate = .{ .ty = full_ty.toIntern(), .storage = .{ .repeated_elem = (try pt.intValue(.u8, 0xaa)).toIntern() }, } })), ), opts); }, - .x87 => try self.genSetReg(dst_reg, .f80, try self.genTypedValue( + .x87 => try self.genSetReg(dst_reg, .f80, try self.lowerValue( try pt.floatValue(.f80, @as(f80, @bitCast(@as(u80, 0xaaaaaaaaaaaaaaaaaaaa)))), ), opts), .ip, .cr, .dr => unreachable, @@ -176944,12 +176813,24 @@ fn genSetReg( } }, .register => |src_reg| if (dst_reg.id() != src_reg.id()) switch (dst_reg.class()) { - .general_purpose, .gphi => switch (src_reg.class()) { - .general_purpose, .gphi => try self.asmRegisterRegister( + .general_purpose => switch (src_reg.class()) { + .general_purpose => try self.asmRegisterRegister( .{ ._, .mov }, dst_alias, registerAlias(src_reg, abi_size), ), + .gphi => if (dst_reg.isClass(.gphi)) try self.asmRegisterRegister( + .{ ._, .mov }, + dst_alias, + registerAlias(src_reg, abi_size), + ) else { + const src_lock = self.register_manager.lockReg(src_reg); + defer if (src_lock) |lock| self.register_manager.unlockReg(lock); + const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gphi); + + try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg.to8(), src_reg); + try self.asmRegisterRegister(.{ ._, .mov }, dst_alias, tmp_reg.to8()); + }, .segment => try self.asmRegisterRegister( .{ ._, .mov }, dst_alias, @@ -176985,6 +176866,26 @@ fn genSetReg( }); }, }, + .gphi => switch (src_reg.class()) { + .general_purpose => if (src_reg.isClass(.gphi)) try self.asmRegisterRegister( + .{ ._, .mov }, + dst_alias, + registerAlias(src_reg, abi_size), + ) else { + const dst_lock = self.register_manager.lockReg(dst_reg); + defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); + const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gphi); + + try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg.to8(), src_reg.to8()); + try self.asmRegisterRegister(.{ ._, .mov }, dst_reg, tmp_reg.to8()); + }, + .gphi => try self.asmRegisterRegister( + .{ ._, .mov }, + dst_alias, + registerAlias(src_reg, abi_size), + ), + .segment, .x87, .mmx, .ip, .cr, .dr, .sse => unreachable, + }, .segment => try self.asmRegisterRegister( .{ ._, .mov }, dst_reg, @@ -177303,7 +177204,7 @@ fn genSetReg( if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size)); try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{}); }, - .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => { + .memory, .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => { switch (src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| return (try self.moveStrategy( @@ -177317,52 +177218,50 @@ fn genSetReg( .disp = small_addr, } }, }), - .load_symbol => |sym_off| switch (dst_reg.class()) { + .load_nav => |nav| switch (dst_reg.class()) { .general_purpose, .gphi => { - assert(sym_off.off == 0); try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ - .base = .{ .reloc = sym_off.sym_index }, - .mod = .{ .rm = .{ - .size = self.memSize(ty), - .disp = sym_off.off, - } }, + .base = .{ .nav = nav }, + .mod = .{ .rm = .{ .size = self.memSize(ty) } }, }); return; }, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_pcrel => |sym_off| switch (dst_reg.class()) { + .load_uav => |uav| switch (dst_reg.class()) { .general_purpose, .gphi => { - assert(sym_off.off == 0); try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ - .base = .{ .pcrel = sym_off.sym_index }, - .mod = .{ .rm = .{ - .size = self.memSize(ty), - .disp = sym_off.off, - } }, + .base = .{ .uav = uav }, + .mod = .{ .rm = .{ .size = self.memSize(ty) } }, }); return; }, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_direct => |sym_index| switch (dst_reg.class()) { + .load_lazy_sym => |lazy_sym| switch (dst_reg.class()) { .general_purpose, .gphi => { - _ = try self.addInst(.{ - .tag = .mov, - .ops = .direct_reloc, - .data = .{ .rx = .{ - .r1 = dst_alias, - .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), - } }, + try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + .base = .{ .lazy_sym = lazy_sym }, + .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + }); + return; + }, + .segment, .mmx, .ip, .cr, .dr => unreachable, + .x87, .sse => {}, + }, + .load_extern_func => |extern_func| switch (dst_reg.class()) { + .general_purpose, .gphi => { + try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + .base = .{ .extern_func = extern_func }, + .mod = .{ .rm = .{ .size = self.memSize(ty) } }, }); return; }, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_got => {}, else => unreachable, } @@ -177375,65 +177274,17 @@ fn genSetReg( .mod = .{ .rm = .{ .size = self.memSize(ty) } }, }); }, - .lea_symbol => |sym_off| switch (self.bin_file.tag) { - .elf, .macho => { - try self.asmRegisterMemory( - .{ ._, .lea }, - dst_reg.to64(), - .{ - .base = .{ .reloc = sym_off.sym_index }, - }, - ); - if (sym_off.off != 0) try self.asmRegisterMemory( - .{ ._, .lea }, - dst_reg.to64(), - .{ - .base = .{ .reg = dst_reg.to64() }, - .mod = .{ .rm = .{ .disp = sym_off.off } }, - }, - ); - }, - else => return self.fail("TODO emit symbol sequence on {s}", .{ - @tagName(self.bin_file.tag), - }), - }, - .lea_pcrel => |sym_off| switch (self.bin_file.tag) { - .elf, .macho => { - try self.asmRegisterMemory( - .{ ._, .lea }, - dst_reg.to64(), - .{ - .base = .{ .pcrel = sym_off.sym_index }, - }, - ); - if (sym_off.off != 0) try self.asmRegisterMemory( - .{ ._, .lea }, - dst_reg.to64(), - .{ - .base = .{ .reg = dst_reg.to64() }, - .mod = .{ .rm = .{ .disp = sym_off.off } }, - }, - ); - }, - else => return self.fail("TODO emit symbol sequence on {s}", .{ - @tagName(self.bin_file.tag), - }), - }, - .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{ - .tag = switch (src_mcv) { - .lea_direct => .lea, - .lea_got => .mov, - else => unreachable, - }, - .ops = switch (src_mcv) { - .lea_direct => .direct_reloc, - .lea_got => .got_reloc, - else => unreachable, - }, - .data = .{ .rx = .{ - .r1 = dst_reg.to64(), - .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }), - } }, + .lea_nav => |nav| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .base = .{ .nav = nav }, + }), + .lea_uav => |uav| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .base = .{ .uav = uav }, + }), + .lea_lazy_sym => |lazy_sym| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .base = .{ .lazy_sym = lazy_sym }, + }), + .lea_extern_func => |lazy_sym| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .base = .{ .extern_func = lazy_sym }, }), .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts), } @@ -177454,9 +177305,10 @@ fn genSetMem( .none => .{ .immediate = @bitCast(@as(i64, disp)) }, .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } }, - .table, .rip_inst => unreachable, - .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } }, - .pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } }, + .table, .rip_inst, .lazy_sym => unreachable, + .nav => |nav| .{ .lea_nav = nav }, + .uav => |uav| .{ .lea_uav = uav }, + .extern_func => |extern_func| .{ .lea_extern_func = extern_func }, }; switch (src_mcv) { .none, @@ -177519,6 +177371,7 @@ fn genSetMem( .rm = .{ .size = .byte, .disp = disp }, } }), .register => |src_reg| { + const ip = &zcu.intern_pool; const mem_size = switch (base) { .frame => |base_fi| mem_size: { assert(disp >= 0); @@ -177572,8 +177425,9 @@ fn genSetMem( .index = frame_index, .off = disp, }).compare(.gte, src_align), - .table, .rip_inst => unreachable, - .reloc, .pcrel => false, + .table, .rip_inst, .lazy_sym, .extern_func => unreachable, + .nav => |nav| ip.getNav(nav).getAlignment().compare(.gte, src_align), + .uav => |uav| Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).compare(.gte, src_align), })).write( self, .{ .base = base, .mod = .{ .rm = .{ @@ -177656,16 +177510,16 @@ fn genSetMem( }, .memory, .indirect, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .load_frame, .lea_frame, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => switch (abi_size) { 0 => {}, 1, 2, 4, 8 => { @@ -177759,119 +177613,19 @@ fn genInlineMemset( try self.asmOpOnly(.{ .@"rep _sb", .sto }); } -fn genExternSymbolRef( - self: *CodeGen, - comptime tag: Mir.Inst.Tag, - lib: ?[]const u8, - callee: []const u8, -) InnerError!void { - if (self.bin_file.cast(.coff)) |coff_file| { - const global_index = try coff_file.getGlobalSymbol(callee, lib); - const scratch_reg = abi.getCAbiLinkerScratchReg(self.target.cCallingConvention().?); - _ = try self.addInst(.{ - .tag = .mov, - .ops = .import_reloc, - .data = .{ .rx = .{ - .r1 = scratch_reg, - .payload = try self.addExtra(bits.SymbolOffset{ - .sym_index = link.File.Coff.global_symbol_bit | global_index, - }), - } }, - }); - switch (tag) { - .mov => {}, - .call => try self.asmRegister(.{ ._, .call }, scratch_reg), - else => unreachable, - } - } else return self.fail("TODO implement calling extern functions", .{}); -} - fn genLazySymbolRef( self: *CodeGen, comptime tag: Mir.Inst.Tag, reg: Register, lazy_sym: link.File.LazySymbol, ) InnerError!void { - const pt = self.pt; - if (self.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - if (self.mod.pic) { - switch (tag) { - .lea, .call => try self.genSetReg(reg, .usize, .{ - .lea_symbol = .{ .sym_index = sym_index }, - }, .{}), - .mov => try self.genSetReg(reg, .usize, .{ - .load_symbol = .{ .sym_index = sym_index }, - }, .{}), - else => unreachable, - } - switch (tag) { - .lea, .mov => {}, - .call => try self.asmRegister(.{ ._, .call }, reg), - else => unreachable, - } - } else switch (tag) { - .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ - .base = .{ .reloc = sym_index }, - .mod = .{ .rm = .{ .size = .qword } }, - }), - .call => try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym_index })), - else => unreachable, - } - } else if (self.bin_file.cast(.plan9)) |p9_file| { - const atom_index = p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - var atom = p9_file.getAtom(atom_index); - _ = atom.getOrCreateOffsetTableEntry(p9_file); - const got_addr = atom.getOffsetTableAddress(p9_file); - const got_mem: Memory = .{ - .base = .{ .reg = .ds }, - .mod = .{ .rm = .{ - .size = .qword, - .disp = @intCast(got_addr), - } }, - }; - switch (tag) { - .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem), - .call => try self.asmMemory(.{ ._, .call }, got_mem), - else => unreachable, - } - switch (tag) { - .lea, .call => {}, - .mov => try self.asmRegisterMemory( - .{ ._, tag }, - reg.to64(), - .initSib(.qword, .{ .base = .{ .reg = reg.to64() } }), - ), - else => unreachable, - } - } else if (self.bin_file.cast(.coff)) |coff_file| { - const atom_index = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - switch (tag) { - .lea, .call => try self.genSetReg(reg, .usize, .{ .lea_got = sym_index }, .{}), - .mov => try self.genSetReg(reg, .usize, .{ .load_got = sym_index }, .{}), - else => unreachable, - } - switch (tag) { - .lea, .mov => {}, - .call => try self.asmRegister(.{ ._, .call }, reg), - else => unreachable, - } - } else if (self.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - const sym_index = zo.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err| - return self.fail("{s} creating lazy symbol", .{@errorName(err)}); - const sym = zo.symbols.items[sym_index]; + if (self.mod.pic) { switch (tag) { .lea, .call => try self.genSetReg(reg, .usize, .{ - .lea_symbol = .{ .sym_index = sym.nlist_idx }, + .lea_lazy_sym = lazy_sym, }, .{}), .mov => try self.genSetReg(reg, .usize, .{ - .load_symbol = .{ .sym_index = sym.nlist_idx }, + .lea_lazy_sym = lazy_sym, }, .{}), else => unreachable, } @@ -177880,8 +177634,13 @@ fn genLazySymbolRef( .call => try self.asmRegister(.{ ._, .call }, reg), else => unreachable, } - } else { - return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)}); + } else switch (tag) { + .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{ + .base = .{ .lazy_sym = lazy_sym }, + .mod = .{ .rm = .{ .size = .qword } }, + }), + .call => try self.asmImmediate(.{ ._, .call }, .{ .lazy_sym = lazy_sym }), + else => unreachable, } } @@ -178034,11 +177793,11 @@ fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void { src_ty.fmt(pt), dst_ty.fmt(pt), }); - var callee_buf: ["__floatun?i?f".len]u8 = undefined; - break :result try self.genCall(.{ .lib = .{ + var sym_buf: ["__floatun?i?f".len]u8 = undefined; + break :result try self.genCall(.{ .extern_func = .{ .return_type = dst_ty.toIntern(), .param_types = &.{src_ty.toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "__float{s}{c}i{c}f", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__float{s}{c}i{c}f", .{ switch (src_signedness) { .signed => "", .unsigned => "un", @@ -178114,11 +177873,11 @@ fn airIntFromFloat(self: *CodeGen, inst: Air.Inst.Index) !void { src_ty.fmt(pt), dst_ty.fmt(pt), }); - var callee_buf: ["__fixuns?f?i".len]u8 = undefined; - break :result try self.genCall(.{ .lib = .{ + var sym_buf: ["__fixuns?f?i".len]u8 = undefined; + break :result try self.genCall(.{ .extern_func = .{ .return_type = dst_ty.toIntern(), .param_types = &.{src_ty.toIntern()}, - .callee = std.fmt.bufPrint(&callee_buf, "__fix{s}{c}f{c}i", .{ + .sym = std.fmt.bufPrint(&sym_buf, "__fix{s}{c}f{c}i", .{ switch (dst_signedness) { .signed => "", .unsigned => "uns", @@ -178219,9 +177978,9 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void { .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), } const ptr_lock = switch (ptr_mem.base) { - .none, .frame, .reloc, .pcrel => null, + .none, .frame, .nav, .uav => null, .reg => |reg| self.register_manager.lockReg(reg), - .table, .rip_inst => unreachable, + .table, .rip_inst, .lazy_sym, .extern_func => unreachable, }; defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); @@ -178302,9 +178061,9 @@ fn atomicOp( .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), } const mem_lock = switch (ptr_mem.base) { - .none, .frame, .reloc, .pcrel => null, + .none, .frame, .nav, .uav => null, .reg => |reg| self.register_manager.lockReg(reg), - .table, .rip_inst => unreachable, + .table, .rip_inst, .lazy_sym, .extern_func => unreachable, }; defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); @@ -179693,7 +179452,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { var mask_elems_buf: [32]u8 = undefined; const mask_elems = mask_elems_buf[0..mask_len]; for (mask_elems, 0..) |*elem, bit| elem.* = @intCast(bit / elem_bits); - const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ + const mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = mask_ty.toIntern(), .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, pt.tid, mask_elems, .maybe_embedded_nulls) }, } }))); @@ -179721,7 +179480,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { mask_elem_ty, @as(u8, 1) << @truncate(bit), )).toIntern(); - const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ + const mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = mask_ty.toIntern(), .storage = .{ .elems = mask_elems }, } }))); @@ -180452,7 +180211,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void { else try select_mask_elem_ty.minIntScalar(pt, select_mask_elem_ty)).toIntern(); } - const select_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ + const select_mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = select_mask_ty.toIntern(), .storage = .{ .elems = select_mask_elems[0..mask_elems.len] }, } }))); @@ -180597,7 +180356,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void { })).toIntern(); } const lhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type }); - const lhs_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ + const lhs_mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = lhs_mask_ty.toIntern(), .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] }, } }))); @@ -180628,7 +180387,7 @@ fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void { })).toIntern(); } const rhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type }); - const rhs_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{ + const rhs_mask_mcv = try self.lowerValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = rhs_mask_ty.toIntern(), .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] }, } }))); @@ -180962,7 +180721,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { .{ .frame = frame_index }, @intCast(elem_size * elements.len), elem_ty, - try self.genTypedValue(sentinel), + try self.lowerValue(sentinel), .{}, ); break :result .{ .load_frame = .{ .index = frame_index } }; @@ -181046,11 +180805,11 @@ fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void { ty.fmt(pt), }); - var callee_buf: ["__fma?".len]u8 = undefined; - break :result try self.genCall(.{ .lib = .{ + var sym_buf: ["__fma?".len]u8 = undefined; + break :result try self.genCall(.{ .extern_func = .{ .return_type = ty.toIntern(), .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() }, - .callee = std.fmt.bufPrint(&callee_buf, "{s}fma{s}", .{ + .sym = std.fmt.bufPrint(&sym_buf, "{s}fma{s}", .{ floatLibcAbiPrefix(ty), floatLibcAbiSuffix(ty), }) catch unreachable, @@ -181450,7 +181209,7 @@ fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue { const mcv: MCValue = if (ref.toIndex()) |inst| mcv: { break :mcv self.inst_tracking.getPtr(inst).?.short; } else mcv: { - break :mcv try self.genTypedValue(.fromInterned(ref.toInterned().?)); + break :mcv try self.lowerValue(.fromInterned(ref.toInterned().?)); }; switch (mcv) { @@ -181488,33 +181247,20 @@ fn limitImmediateType(self: *CodeGen, operand: Air.Inst.Ref, comptime T: type) ! return mcv; } -fn genResult(self: *CodeGen, res: codegen.GenResult) InnerError!MCValue { - return switch (res) { - .mcv => |mcv| switch (mcv) { - .none => .none, - .undef => .undef, - .immediate => |imm| .{ .immediate = imm }, - .memory => |addr| .{ .memory = addr }, - .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } }, - .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } }, - .load_direct => |sym_index| .{ .load_direct = sym_index }, - .lea_direct => |sym_index| .{ .lea_direct = sym_index }, - .load_got => |sym_index| .{ .lea_got = sym_index }, - }, - .fail => |msg| return self.failMsg(msg), +fn lowerValue(cg: *CodeGen, val: Value) Allocator.Error!MCValue { + return switch (try codegen.lowerValue(cg.pt, val, cg.target)) { + .none => .none, + .undef => .undef, + .immediate => |imm| .{ .immediate = imm }, + .lea_nav => |nav| .{ .lea_nav = nav }, + .lea_uav => |uav| .{ .lea_uav = uav }, + .load_uav => |uav| .{ .load_uav = uav }, }; } -fn genTypedValue(self: *CodeGen, val: Value) InnerError!MCValue { - return self.genResult(try codegen.genTypedValue(self.bin_file, self.pt, self.src_loc, val, self.target.*)); -} - -fn lowerUav(self: *CodeGen, val: Value, alignment: InternPool.Alignment) InnerError!MCValue { - return self.genResult(try self.bin_file.lowerUav(self.pt, val.toIntern(), alignment, self.src_loc)); -} - const CallMCValues = struct { args: []MCValue, + air_arg_count: u32, return_value: InstTracking, stack_byte_count: u31, stack_align: InternPool.Alignment, @@ -181550,13 +181296,14 @@ fn resolveCallingConventionValues( const param_types = try allocator.alloc(Type, fn_info.param_types.len + var_args.len); defer allocator.free(param_types); - for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src| - dest.* = .fromInterned(src); + for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*param_ty, arg_ty| + param_ty.* = .fromInterned(arg_ty); for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty| param_ty.* = self.promoteVarArg(arg_ty); var result: CallMCValues = .{ .args = try self.gpa.alloc(MCValue, param_types.len), + .air_arg_count = 0, // These undefined values must be populated before returning from this function. .return_value = undefined, .stack_byte_count = 0, @@ -181678,6 +181425,7 @@ fn resolveCallingConventionValues( // Input params for (param_types, result.args) |ty, *arg| { assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); + result.air_arg_count += 1; switch (cc) { .x86_64_sysv => {}, .x86_64_win => { @@ -181850,6 +181598,7 @@ fn resolveCallingConventionValues( arg.* = .none; continue; } + result.air_arg_count += 1; const param_size: u31 = @intCast(param_ty.abiSize(zcu)); if (abi.zigcc.params_in_regs) switch (self.regClassForType(param_ty)) { .general_purpose, .gphi => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (self.target.cpu.arch) { @@ -182373,16 +182122,16 @@ const Temp = struct { .register_offset, .register_mask, .memory, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, .indirect, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .lea_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .lea_extern_func, + .load_extern_func, .elementwise_args, .reserved_frame, .air_ref, @@ -182425,15 +182174,11 @@ const Temp = struct { .mod = .{ .rm = .{ .disp = reg_off.off + off } }, }); }, - .load_symbol, .load_frame => { + .load_frame, .load_nav, .lea_nav, .load_uav, .lea_uav, .load_lazy_sym, .lea_lazy_sym => { const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); new_temp_index.tracking(cg).* = .init(.{ .register_offset = .{ .reg = new_reg, .off = off } }); try cg.genSetReg(new_reg, .usize, mcv, .{}); }, - .lea_symbol => |sym_off| new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = .{ - .sym_index = sym_off.sym_index, - .off = sym_off.off + off, - } }), .lea_frame => |frame_addr| new_temp_index.tracking(cg).* = .init(.{ .lea_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off, @@ -182466,14 +182211,6 @@ const Temp = struct { } }); return; }, - .lea_symbol => |sym_off| { - assert(std.meta.eql(temp_tracking.long.lea_symbol, sym_off)); - temp_tracking.* = .init(.{ .lea_symbol = .{ - .sym_index = sym_off.sym_index, - .off = sym_off.off + off, - } }); - return; - }, .lea_frame => |frame_addr| { assert(std.meta.eql(temp_tracking.long.lea_frame, frame_addr)); temp_tracking.* = .init(.{ .lea_frame = .{ @@ -182522,53 +182259,85 @@ const Temp = struct { .mod = .{ .rm = .{ .disp = reg_off.off + @as(u31, limb_index) * 8 } }, }); }, - .load_symbol => |sym_off| { + .load_frame => |frame_addr| { + const new_reg = + try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); + new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); + try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ + .base = .{ .frame = frame_addr.index }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = frame_addr.off + @as(u31, limb_index) * 8, + } }, + }); + }, + .lea_frame => |frame_addr| { + assert(limb_index == 0); + new_temp_index.tracking(cg).* = .init(.{ .lea_frame = frame_addr }); + }, + .load_nav => |nav| { const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ - .base = .{ .reloc = sym_off.sym_index }, + .base = .{ .nav = nav }, .mod = .{ .rm = .{ .size = .qword, - .disp = sym_off.off + @as(u31, limb_index) * 8, + .disp = @as(u31, limb_index) * 8, } }, }); }, - .lea_symbol => |sym_off| { + .lea_nav => |nav| { assert(limb_index == 0); - new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off }); + new_temp_index.tracking(cg).* = .init(.{ .lea_nav = nav }); }, - .load_pcrel => |sym_off| { + .load_uav => |uav| { const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ - .base = .{ .pcrel = sym_off.sym_index }, + .base = .{ .uav = uav }, .mod = .{ .rm = .{ .size = .qword, - .disp = sym_off.off + @as(u31, limb_index) * 8, + .disp = @as(u31, limb_index) * 8, } }, }); }, - .lea_pcrel => |sym_off| { + .lea_uav => |uav| { assert(limb_index == 0); - new_temp_index.tracking(cg).* = .init(.{ .lea_pcrel = sym_off }); + new_temp_index.tracking(cg).* = .init(.{ .lea_uav = uav }); }, - .load_frame => |frame_addr| { + .load_lazy_sym => |lazy_sym| { const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ - .base = .{ .frame = frame_addr.index }, + .base = .{ .lazy_sym = lazy_sym }, .mod = .{ .rm = .{ .size = .qword, - .disp = frame_addr.off + @as(u31, limb_index) * 8, + .disp = @as(u31, limb_index) * 8, } }, }); }, - .lea_frame => |frame_addr| { + .lea_lazy_sym => |lazy_sym| { assert(limb_index == 0); - new_temp_index.tracking(cg).* = .init(.{ .lea_frame = frame_addr }); + new_temp_index.tracking(cg).* = .init(.{ .lea_lazy_sym = lazy_sym }); + }, + .load_extern_func => |extern_func| { + const new_reg = + try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp); + new_temp_index.tracking(cg).* = .init(.{ .register = new_reg }); + try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{ + .base = .{ .extern_func = extern_func }, + .mod = .{ .rm = .{ + .size = .qword, + .disp = @as(u31, limb_index) * 8, + } }, + }); + }, + .lea_extern_func => |extern_func| { + assert(limb_index == 0); + new_temp_index.tracking(cg).* = .init(.{ .lea_extern_func = extern_func }); }, } cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1); @@ -182625,7 +182394,7 @@ const Temp = struct { const temp_tracking = temp_index.tracking(cg); switch (temp_tracking.short) { else => {}, - .register, .lea_symbol, .lea_frame => { + .register, .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym => { assert(limb_index == 0); cg.temp_type[@intFromEnum(temp_index)] = limb_ty; return; @@ -182642,15 +182411,6 @@ const Temp = struct { cg.temp_type[@intFromEnum(temp_index)] = limb_ty; return; }, - .load_symbol => |sym_off| { - assert(std.meta.eql(temp_tracking.long.load_symbol, sym_off)); - temp_tracking.* = .init(.{ .load_symbol = .{ - .sym_index = sym_off.sym_index, - .off = sym_off.off + @as(u31, limb_index) * 8, - } }); - cg.temp_type[@intFromEnum(temp_index)] = limb_ty; - return; - }, .load_frame => |frame_addr| if (!frame_addr.index.isNamed()) { assert(std.meta.eql(temp_tracking.long.load_frame, frame_addr)); temp_tracking.* = .init(.{ .load_frame = .{ @@ -182841,27 +182601,20 @@ const Temp = struct { .immediate, .register, .register_offset, - .lea_direct, - .lea_got, .lea_frame, => return false, .memory, .indirect, - .load_symbol, - .load_pcrel, - .load_direct, - .load_got, .load_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => return temp.toRegClass(true, .general_purpose, cg), - .lea_symbol, .lea_pcrel => |sym_off| { - const off = sym_off.off; - // hack around linker relocation bugs - if (false and off == 0) return false; - try temp.toOffset(-off, cg); - while (try temp.toRegClass(true, .general_purpose, cg)) {} - try temp.toOffset(off, cg); - return true; - }, } } @@ -182928,7 +182681,7 @@ const Temp = struct { ), cg), else => unreachable, }, - .memory, .indirect, .load_frame, .load_symbol => { + .memory, .indirect, .load_frame, .load_nav, .load_uav, .load_lazy_sym => { var val_ptr = try cg.tempInit(.usize, val_mcv.address()); var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); try val_ptr.memcpy(ptr, &len, cg); @@ -182966,7 +182719,11 @@ const Temp = struct { // hack around linker relocation bugs switch (ptr.tracking(cg).short) { else => {}, - .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, + => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, } try cg.asmMemoryImmediate( .{ ._, .mov }, @@ -182980,7 +182737,11 @@ const Temp = struct { // hack around linker relocation bugs switch (ptr.tracking(cg).short) { else => {}, - .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, + .lea_nav, + .lea_uav, + .lea_lazy_sym, + .lea_extern_func, + => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, } try cg.asmSetccMemory( cc, @@ -183024,8 +182785,8 @@ const Temp = struct { try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }), ); }, - .lea_frame, .lea_symbol => continue :val_to_gpr, - .memory, .indirect, .load_frame, .load_symbol => { + .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym => continue :val_to_gpr, + .memory, .indirect, .load_frame, .load_nav, .load_uav, .load_lazy_sym => { var val_ptr = try cg.tempInit(.usize, val_mcv.address()); var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) }); try ptr.memcpy(&val_ptr, &len, cg); @@ -183065,7 +182826,7 @@ const Temp = struct { ), cg), else => unreachable, }, - .memory, .indirect, .load_frame, .load_symbol => { + .memory, .indirect, .load_frame, .load_nav, .load_uav, .load_lazy_sym => { var val_ptr = try cg.tempInit(.usize, val_mcv.address()); var src_ptr = try cg.tempInit(.usize, src.tracking(cg).short.address().offset(opts.disp)); @@ -183159,8 +182920,8 @@ const Temp = struct { }), ); }, - .lea_frame, .lea_symbol => continue :val_to_gpr, - .memory, .indirect, .load_frame, .load_symbol => { + .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym => continue :val_to_gpr, + .memory, .indirect, .load_frame, .load_nav, .load_uav, .load_lazy_sym => { var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp)); var val_ptr = try cg.tempInit(.usize, val_mcv.address()); @@ -183181,7 +182942,7 @@ const Temp = struct { // hack around linker relocation bugs switch (ptr.tracking(cg).short) { else => {}, - .lea_symbol => |sym_off| if (dst_rc != .general_purpose or sym_off.off != 0) + .lea_nav, .lea_uav, .lea_lazy_sym => if (dst_rc != .general_purpose) while (try ptr.toRegClass(false, .general_purpose, cg)) {}, } try strat.read(cg, dst_reg, try ptr.tracking(cg).short.deref().mem(cg, .{ @@ -183201,7 +182962,7 @@ const Temp = struct { // hack around linker relocation bugs switch (ptr.tracking(cg).short) { else => {}, - .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, + .lea_nav, .lea_uav, .lea_lazy_sym => while (try ptr.toRegClass(false, .general_purpose, cg)) {}, } const strat = try cg.moveStrategy(src_ty, src_rc, false); try strat.write(cg, try ptr.tracking(cg).short.deref().mem(cg, .{ @@ -186964,7 +186725,7 @@ const Temp = struct { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divti3" } }, .unused, .unused, .unused, @@ -186993,7 +186754,7 @@ const Temp = struct { }, .call_frame = .{ .alignment = .@"16" }, .extra_temps = .{ - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__udivti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__udivti3" } }, .unused, .unused, .unused, @@ -187026,7 +186787,7 @@ const Temp = struct { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divei4" } }, .unused, .unused, .unused, @@ -187059,7 +186820,7 @@ const Temp = struct { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__udivei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__udivei4" } }, .unused, .unused, .unused, @@ -187423,7 +187184,7 @@ const Temp = struct { .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .i64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divti3" } }, .{ .type = .u64, .kind = .{ .ret_gpr = .{ .cc = .ccc, .at = 0 } } }, .unused, .unused, @@ -187461,7 +187222,7 @@ const Temp = struct { .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .u64, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__udivti3" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__udivti3" } }, .{ .type = .u64, .kind = .{ .ret_gpr = .{ .cc = .ccc, .at = 0 } } }, .unused, .unused, @@ -187499,7 +187260,7 @@ const Temp = struct { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__divei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__divei4" } }, .unused, .unused, .unused, @@ -187535,7 +187296,7 @@ const Temp = struct { .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 1 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 2 } } }, .{ .type = .usize, .kind = .{ .param_gpr = .{ .cc = .ccc, .at = 3 } } }, - .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__udivei4" } } }, + .{ .type = .usize, .kind = .{ .extern_func = "__udivei4" } }, .unused, .unused, .unused, @@ -187590,16 +187351,16 @@ const Temp = struct { .register_overflow, .register_mask, .memory, - .load_symbol, - .lea_symbol, - .load_pcrel, - .lea_pcrel, .indirect, - .load_direct, - .lea_direct, - .load_got, - .lea_got, .load_frame, + .load_nav, + .lea_nav, + .load_uav, + .lea_uav, + .load_lazy_sym, + .lea_lazy_sym, + .load_extern_func, + .lea_extern_func, => { const result = try cg.allocRegOrMem(inst, true); try cg.genCopy(cg.typeOfIndex(inst), result, temp_mcv, .{}); @@ -187776,7 +187537,7 @@ fn tempInit(cg: *CodeGen, ty: Type, value: MCValue) InnerError!Temp { } fn tempFromValue(cg: *CodeGen, value: Value) InnerError!Temp { - return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.genTypedValue(value)); + return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.lowerValue(value)); } fn tempMemFromValue(cg: *CodeGen, value: Value) InnerError!Temp { @@ -187784,13 +187545,20 @@ fn tempMemFromValue(cg: *CodeGen, value: Value) InnerError!Temp { } fn tempMemFromAlignedValue(cg: *CodeGen, alignment: InternPool.Alignment, value: Value) InnerError!Temp { - return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.lowerUav(value, alignment)); + const ty = value.typeOf(cg.pt.zcu); + return cg.tempInit(ty, .{ .load_uav = .{ + .val = value.toIntern(), + .orig_ty = (try cg.pt.ptrType(.{ + .child = ty.toIntern(), + .flags = .{ + .is_const = true, + .alignment = alignment, + }, + })).toIntern(), + } }); } fn tempFromOperand(cg: *CodeGen, op_ref: Air.Inst.Ref, op_dies: bool) InnerError!Temp { - const zcu = cg.pt.zcu; - const ip = &zcu.intern_pool; - if (op_dies) { const temp_index = cg.next_temp_index; const temp: Temp = .{ .index = temp_index.toIndex() }; @@ -187804,8 +187572,7 @@ fn tempFromOperand(cg: *CodeGen, op_ref: Air.Inst.Ref, op_dies: bool) InnerError } if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst }; - const val = op_ref.toInterned().?; - return cg.tempInit(.fromInterned(ip.typeOf(val)), try cg.genTypedValue(.fromInterned(val))); + return cg.tempFromValue(.fromInterned(op_ref.toInterned().?)); } fn tempsFromOperandsInner( @@ -188640,8 +188407,8 @@ const Select = struct { splat_int_mem: struct { ref: Select.Operand.Ref, inside: enum { umin, smin, smax } = .umin, outside: enum { smin, smax } }, splat_float_mem: struct { ref: Select.Operand.Ref, inside: enum { zero } = .zero, outside: f16 }, frame: FrameIndex, - lazy_symbol: struct { kind: link.File.LazySymbol.Kind, ref: Select.Operand.Ref = .none }, - symbol: *const struct { lib: ?[]const u8 = null, name: []const u8 }, + lazy_sym: struct { kind: link.File.LazySymbol.Kind, ref: Select.Operand.Ref = .none }, + extern_func: [*:0]const u8, const ConstSpec = struct { ref: Select.Operand.Ref = .none, @@ -189072,43 +188839,21 @@ const Select = struct { } }))), true }; }, .frame => |frame_index| .{ try cg.tempInit(spec.type, .{ .load_frame = .{ .index = frame_index } }), true }, - .lazy_symbol => |lazy_symbol_spec| { + .lazy_sym => |lazy_symbol_spec| { const ip = &pt.zcu.intern_pool; const ty = if (lazy_symbol_spec.ref == .none) spec.type else lazy_symbol_spec.ref.typeOf(s); - const lazy_symbol: link.File.LazySymbol = .{ + return .{ try cg.tempInit(.usize, .{ .lea_lazy_sym = .{ .kind = lazy_symbol_spec.kind, .ty = switch (ip.indexToKey(ty.toIntern())) { .inferred_error_set_type => |func_index| switch (ip.funcIesResolvedUnordered(func_index)) { - .none => unreachable, // unresolved inferred error set + .none => unreachable, else => |ty_index| ty_index, }, else => ty.toIntern(), }, - }; - return .{ try cg.tempInit(.usize, .{ .lea_symbol = .{ - .sym_index = if (cg.bin_file.cast(.elf)) |elf_file| - elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_symbol) catch |err| - return cg.fail("{s} creating lazy symbol", .{@errorName(err)}) - else if (cg.bin_file.cast(.macho)) |macho_file| - macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_symbol) catch |err| - return cg.fail("{s} creating lazy symbol", .{@errorName(err)}) - else if (cg.bin_file.cast(.coff)) |coff_file| - coff_file.getAtom(coff_file.getOrCreateAtomForLazySymbol(pt, lazy_symbol) catch |err| - return cg.fail("{s} creating lazy symbol", .{@errorName(err)})).getSymbolIndex().? - else - return cg.fail("external symbols unimplemented for {s}", .{@tagName(cg.bin_file.tag)}), } }), true }; }, - .symbol => |symbol_spec| .{ try cg.tempInit(spec.type, .{ .lea_symbol = .{ - .sym_index = if (cg.bin_file.cast(.elf)) |elf_file| - try elf_file.getGlobalSymbol(symbol_spec.name, symbol_spec.lib) - else if (cg.bin_file.cast(.macho)) |macho_file| - try macho_file.getGlobalSymbol(symbol_spec.name, symbol_spec.lib) - else if (cg.bin_file.cast(.coff)) |coff_file| - link.File.Coff.global_symbol_bit | try coff_file.getGlobalSymbol(symbol_spec.name, symbol_spec.lib) - else - return cg.fail("external symbols unimplemented for {s}", .{@tagName(cg.bin_file.tag)}), - } }), true }, + .extern_func => |extern_func_spec| .{ try cg.tempInit(spec.type, .{ .lea_extern_func = try cg.addString(std.mem.span(extern_func_spec)) }), true }, }; } @@ -190151,9 +189896,12 @@ const Select = struct { .register => |reg| .{ .reg = s.lowerReg(reg.toSize(op.flags.base.size, s.cg.target)) }, .register_pair, .register_triple, .register_quadruple, .register_offset, .register_overflow => unreachable, .register_mask => |reg_mask| .{ .reg = s.lowerReg(reg_mask.reg.toSize(op.flags.base.size, s.cg.target)) }, + .lea_nav => |nav| .{ .imm = .{ .nav = .{ .index = nav } } }, + .lea_uav => |uav| .{ .imm = .{ .uav = uav } }, + .lea_lazy_sym => |lazy_sym| .{ .imm = .{ .lazy_sym = lazy_sym } }, + .lea_extern_func => |extern_func| .{ .imm = .{ .extern_func = extern_func } }, else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.flags.base.size }) }, - .lea_symbol => |sym_off| .{ .imm = .rel(sym_off) }, - .load_direct, .lea_direct, .load_got, .lea_got, .lea_frame, .elementwise_args, .reserved_frame, .air_ref => unreachable, + .lea_frame, .elementwise_args, .reserved_frame, .air_ref => unreachable, }, 1...2 => |imm| switch (op.flags.base.ref.valueOf(s)) { inline .register_pair, .register_triple, .register_quadruple => |regs| .{ @@ -190167,37 +189915,20 @@ const Select = struct { }, .simm => .{ .imm = .s(op.adjustedImm(i32, s)) }, .uimm => .{ .imm = .u(@bitCast(op.adjustedImm(i64, s))) }, - .lea => .{ .mem = .{ - .base = switch (op.flags.base.ref.valueOf(s)) { + .lea => .{ .mem = try op.flags.base.ref.valueOf(s).deref().mem(s.cg, .{ + .size = op.flags.base.size, + .index = switch (op.flags.index.ref.valueOf(s)) { else => unreachable, .none => .none, - .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) }, - .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) }, - .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index }, - .lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index }, + .register => |index_reg| index_reg.toSize(.ptr, s.cg.target), }, - .mod = .{ .rm = .{ - .size = op.flags.base.size, - .index = switch (op.flags.index.ref.valueOf(s)) { - else => unreachable, - .none => .none, - .register => |index_reg| index_reg.toSize(.ptr, s.cg.target), - .register_offset => |index_reg_off| index_reg_off.reg.toSize(.ptr, s.cg.target), - }, - .scale = op.flags.index.scale, - .disp = op.adjustedImm(i32, s) + switch (op.flags.base.ref.valueOf(s)) { - else => unreachable, - .none, .register => 0, - .register_offset => |base_reg_off| base_reg_off.off, - .lea_symbol => |base_sym_off| base_sym_off.off, - } + switch (op.flags.index.ref.valueOf(s)) { - else => unreachable, - .none, .register => 0, - .register_offset => |base_reg_off| base_reg_off.off, - .lea_symbol => |base_sym_off| base_sym_off.off, - }, - } }, - } }, + .scale = op.flags.index.scale, + .disp = op.adjustedImm(i32, s) + switch (op.flags.index.ref.valueOf(s)) { + else => unreachable, + .none, .register, .lea_nav, .lea_uav, .lea_lazy_sym, .lea_extern_func => 0, + .register_offset => |base_reg_off| base_reg_off.off, + }, + }) }, .mem => .{ .mem = try op.flags.base.ref.valueOf(s).mem(s.cg, .{ .size = op.flags.base.size, .index = switch (op.flags.index.ref.valueOf(s)) { diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index d4116974cf77..e6b4ac26bbfa 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -1,7 +1,9 @@ //! This file contains the functionality for emitting x86_64 MIR as machine code -air: Air, lower: Lower, +bin_file: *link.File, +pt: Zcu.PerThread, +pic: bool, atom_index: u32, debug_output: link.File.DebugInfoOutput, code: *std.ArrayListUnmanaged(u8), @@ -10,26 +12,29 @@ prev_di_loc: Loc, /// Relative to the beginning of `code`. prev_di_pc: usize, +code_offset_mapping: std.ArrayListUnmanaged(u32), +relocs: std.ArrayListUnmanaged(Reloc), +table_relocs: std.ArrayListUnmanaged(TableReloc), + pub const Error = Lower.Error || error{ EmitFail, } || link.File.UpdateDebugInfoError; pub fn emitMir(emit: *Emit) Error!void { - const gpa = emit.lower.bin_file.comp.gpa; - const code_offset_mapping = try emit.lower.allocator.alloc(u32, emit.lower.mir.instructions.len); - defer emit.lower.allocator.free(code_offset_mapping); - var relocs: std.ArrayListUnmanaged(Reloc) = .empty; - defer relocs.deinit(emit.lower.allocator); - var table_relocs: std.ArrayListUnmanaged(TableReloc) = .empty; - defer table_relocs.deinit(emit.lower.allocator); + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + try emit.code_offset_mapping.resize(gpa, emit.lower.mir.instructions.len); + emit.relocs.clearRetainingCapacity(); + emit.table_relocs.clearRetainingCapacity(); + var local_index: usize = 0; for (0..emit.lower.mir.instructions.len) |mir_i| { const mir_index: Mir.Inst.Index = @intCast(mir_i); - code_offset_mapping[mir_index] = @intCast(emit.code.items.len); + emit.code_offset_mapping.items[mir_index] = @intCast(emit.code.items.len); const lowered = try emit.lower.lowerMir(mir_index); var lowered_relocs = lowered.relocs; - for (lowered.insts, 0..) |lowered_inst, lowered_index| { - const start_offset: u32 = @intCast(emit.code.items.len); + lowered_inst: for (lowered.insts, 0..) |lowered_inst, lowered_index| { if (lowered_inst.prefix == .directive) { + const start_offset: u32 = @intCast(emit.code.items.len); switch (emit.debug_output) { .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) { .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{ @@ -82,204 +87,327 @@ pub fn emitMir(emit: *Emit) Error!void { } continue; } - try lowered_inst.encode(emit.code.writer(gpa), .{}); - const end_offset: u32 = @intCast(emit.code.items.len); + var reloc_info_buf: [2]RelocInfo = undefined; + var reloc_info_index: usize = 0; while (lowered_relocs.len > 0 and lowered_relocs[0].lowered_inst_index == lowered_index) : ({ lowered_relocs = lowered_relocs[1..]; - }) switch (lowered_relocs[0].target) { - .inst => |target| { - const inst_length: u4 = @intCast(end_offset - start_offset); - const reloc_offset, const reloc_length = reloc_offset_length: { - var reloc_offset = inst_length; - var op_index: usize = lowered_inst.ops.len; - while (true) { - op_index -= 1; - const op = lowered_inst.encoding.data.ops[op_index]; - if (op == .none) continue; - const is_mem = op.isMemory(); - const enc_length: u4 = if (is_mem) switch (lowered_inst.ops[op_index].mem.sib.base) { - .rip_inst => 4, - else => unreachable, - } else @intCast(std.math.divCeil(u7, @intCast(op.immBitSize()), 8) catch unreachable); - reloc_offset -= enc_length; - if (op_index == lowered_relocs[0].op_index) break :reloc_offset_length .{ reloc_offset, enc_length }; - std.debug.assert(!is_mem); - } - }; - try relocs.append(emit.lower.allocator, .{ - .inst_offset = start_offset, - .inst_length = inst_length, - .source_offset = reloc_offset, - .source_length = reloc_length, - .target = target, - .target_offset = lowered_relocs[0].off, - }); - }, - .table => try table_relocs.append(emit.lower.allocator, .{ - .source_offset = end_offset - 4, - .target_offset = lowered_relocs[0].off, - }), - .linker_extern_fn => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { - // Add relocation to the decl. - const zo = elf_file.zigObjectPtr().?; - const atom_ptr = zo.symbol(emit.atom_index).atom(elf_file).?; - const r_type = @intFromEnum(std.elf.R_X86_64.PLT32); - try atom_ptr.addReloc(gpa, .{ - .r_offset = end_offset - 4, - .r_info = @as(u64, sym_index) << 32 | r_type, - .r_addend = lowered_relocs[0].off - 4, - }, zo); - } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { - // Add relocation to the decl. - const zo = macho_file.getZigObject().?; - const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; - try atom.addReloc(macho_file, .{ - .tag = .@"extern", - .offset = end_offset - 4, - .target = sym_index, - .addend = lowered_relocs[0].off, - .type = .branch, - .meta = .{ - .pcrel = true, - .has_subtractor = false, - .length = 2, - .symbolnum = @intCast(sym_index), + reloc_info_index += 1; + }) reloc_info_buf[reloc_info_index] = .{ + .op_index = lowered_relocs[0].op_index, + .off = lowered_relocs[0].off, + .target = target: switch (lowered_relocs[0].target) { + .inst => |inst| .{ .index = inst, .is_extern = false, .type = .inst }, + .table => .{ .index = undefined, .is_extern = false, .type = .table }, + .nav => |nav| { + const sym_index = switch (try codegen.genNavRef( + emit.bin_file, + emit.pt, + emit.lower.src_loc, + nav, + emit.lower.target.*, + )) { + .mcv => |mcv| mcv.lea_symbol, + .fail => |em| { + assert(emit.lower.err_msg == null); + emit.lower.err_msg = em; + return error.EmitFail; + }, + }; + const ip = &emit.pt.zcu.intern_pool; + break :target switch (ip.getNav(nav).status) { + .unresolved => unreachable, + .type_resolved => |type_resolved| .{ + .index = sym_index, + .is_extern = false, + .type = if (type_resolved.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol, + }, + .fully_resolved => |fully_resolved| switch (ip.indexToKey(fully_resolved.val)) { + .@"extern" => |@"extern"| .{ + .index = sym_index, + .is_extern = switch (@"extern".visibility) { + .default => true, + .hidden, .protected => false, + }, + .type = if (@"extern".is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol, + .force_pcrel_direct = switch (@"extern".relocation) { + .any => false, + .pcrel => true, + }, + }, + .variable => |variable| .{ + .index = sym_index, + .is_extern = false, + .type = if (variable.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol, + }, + else => .{ .index = sym_index, .is_extern = false, .type = .symbol }, + }, + }; + }, + .uav => |uav| .{ + .index = switch (try emit.bin_file.lowerUav( + emit.pt, + uav.val, + Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu), + emit.lower.src_loc, + )) { + .mcv => |mcv| mcv.load_symbol, + .fail => |em| { + assert(emit.lower.err_msg == null); + emit.lower.err_msg = em; + return error.EmitFail; + }, }, - }); - } else if (emit.lower.bin_file.cast(.coff)) |coff_file| { - // Add relocation to the decl. - const atom_index = coff_file.getAtomIndexForSymbol( - .{ .sym_index = emit.atom_index, .file = null }, - ).?; - const target = if (link.File.Coff.global_symbol_bit & sym_index != 0) - coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index) - else - link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null }; - try coff_file.addRelocation(atom_index, .{ - .type = .direct, - .target = target, - .offset = end_offset - 4, - .addend = @intCast(lowered_relocs[0].off), - .pcrel = true, - .length = 2, - }); - } else return emit.fail("TODO implement extern reloc for {s}", .{ - @tagName(emit.lower.bin_file.tag), - }), - .linker_tlsld => |sym_index| { - const elf_file = emit.lower.bin_file.cast(.elf).?; - const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(emit.atom_index).atom(elf_file).?; - const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD); - try atom.addReloc(gpa, .{ - .r_offset = end_offset - 4, - .r_info = @as(u64, sym_index) << 32 | r_type, - .r_addend = lowered_relocs[0].off - 4, - }, zo); - }, - .linker_dtpoff => |sym_index| { - const elf_file = emit.lower.bin_file.cast(.elf).?; - const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(emit.atom_index).atom(elf_file).?; - const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32); - try atom.addReloc(gpa, .{ - .r_offset = end_offset - 4, - .r_info = @as(u64, sym_index) << 32 | r_type, - .r_addend = lowered_relocs[0].off, - }, zo); - }, - .linker_reloc, .linker_pcrel => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - const atom = zo.symbol(emit.atom_index).atom(elf_file).?; - const sym = zo.symbol(sym_index); - if (emit.lower.pic) { - const r_type: u32 = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel) - @intFromEnum(std.elf.R_X86_64.GOTPCREL) + .is_extern = false, + .type = .symbol, + }, + .lazy_sym => |lazy_sym| .{ + .index = if (emit.bin_file.cast(.elf)) |elf_file| + elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err| + return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) + else if (emit.bin_file.cast(.macho)) |macho_file| + macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| + return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) + else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: { + const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| + return emit.fail("{s} creating lazy symbol", .{@errorName(err)}); + break :sym_index coff_file.getAtom(atom).getSymbolIndex().?; + } else if (emit.bin_file.cast(.plan9)) |p9_file| + p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| + return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) else - @intFromEnum(std.elf.R_X86_64.PC32); - try atom.addReloc(gpa, .{ - .r_offset = end_offset - 4, - .r_info = @as(u64, sym_index) << 32 | r_type, - .r_addend = lowered_relocs[0].off - 4, - }, zo); - } else { - const r_type: u32 = if (sym.flags.is_tls) - @intFromEnum(std.elf.R_X86_64.TPOFF32) + return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), + .is_extern = false, + .type = .symbol, + }, + .extern_func => |extern_func| .{ + .index = if (emit.bin_file.cast(.elf)) |elf_file| + try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) + else if (emit.bin_file.cast(.macho)) |macho_file| + try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) + else if (emit.bin_file.cast(.coff)) |coff_file| + link.File.Coff.global_symbol_bit | try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) else - @intFromEnum(std.elf.R_X86_64.@"32"); - try atom.addReloc(gpa, .{ - .r_offset = end_offset - 4, - .r_info = @as(u64, sym_index) << 32 | r_type, - .r_addend = lowered_relocs[0].off, - }, zo); - } - } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; - const sym = &zo.symbols.items[sym_index]; - const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel) - .got_load - else if (sym.flags.tlv) - .tlv - else - .signed; - try atom.addReloc(macho_file, .{ - .tag = .@"extern", - .offset = @intCast(end_offset - 4), - .target = sym_index, - .addend = lowered_relocs[0].off, - .type = @"type", - .meta = .{ - .pcrel = true, - .has_subtractor = false, - .length = 2, - .symbolnum = @intCast(sym_index), + return emit.fail("external symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), + .is_extern = true, + .type = .symbol, + }, + }, + }; + const reloc_info = reloc_info_buf[0..reloc_info_index]; + for (reloc_info) |*reloc| switch (reloc.target.type) { + .inst, .table => {}, + .symbol => { + switch (lowered_inst.encoding.mnemonic) { + .call => { + reloc.target.type = .branch; + if (emit.bin_file.cast(.coff)) |_| try emit.encodeInst(try .new(.none, .call, &.{ + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info) else try emit.encodeInst(lowered_inst, reloc_info); + continue :lowered_inst; }, + else => {}, + } + if (emit.bin_file.cast(.elf)) |_| { + if (!emit.pic) switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .imm = .s(0) }, + }, emit.lower.target), reloc_info), + .mov => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ + .base = .{ .reg = .ds }, + }) }, + }, emit.lower.target), reloc_info), + else => unreachable, + } else if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info), + .mov => { + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ .base = .{ + .reg = lowered_inst.ops[0].reg.to64(), + } }) }, + }, emit.lower.target), &.{}); + }, + else => unreachable, + } else switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .lea, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.none, 0) }, + }, emit.lower.target), reloc_info), + .mov => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, 0) }, + }, emit.lower.target), reloc_info), + else => unreachable, + } + } else if (emit.bin_file.cast(.macho)) |_| { + if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info), + .mov => { + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ .base = .{ + .reg = lowered_inst.ops[0].reg.to64(), + } }) }, + }, emit.lower.target), &.{}); + }, + else => unreachable, + } else switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .lea, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.none, 0) }, + }, emit.lower.target), reloc_info), + .mov => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, 0) }, + }, emit.lower.target), reloc_info), + else => unreachable, + } + } else if (emit.bin_file.cast(.coff)) |_| { + if (reloc.target.is_extern) switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info), + .mov => { + const dst_reg = lowered_inst.ops[0].reg.to64(); + try emit.encodeInst(try .new(.none, .mov, &.{ + .{ .reg = dst_reg }, + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ .base = .{ + .reg = dst_reg, + } }) }, + }, emit.lower.target), &.{}); + }, + else => unreachable, + } else switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .lea, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.none, 0) }, + }, emit.lower.target), reloc_info), + .mov => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, 0) }, + }, emit.lower.target), reloc_info), + else => unreachable, + } + } else return emit.fail("TODO implement relocs for {s}", .{ + @tagName(emit.bin_file.tag), }); - } else unreachable, - .linker_got, - .linker_direct, - .linker_import, - => |sym_index| if (emit.lower.bin_file.cast(.elf)) |_| { - unreachable; - } else if (emit.lower.bin_file.cast(.macho)) |_| { - unreachable; - } else if (emit.lower.bin_file.cast(.coff)) |coff_file| { - const atom_index = coff_file.getAtomIndexForSymbol(.{ - .sym_index = emit.atom_index, - .file = null, - }).?; - const target = if (link.File.Coff.global_symbol_bit & sym_index != 0) - coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & sym_index) - else - link.File.Coff.SymbolWithLoc{ .sym_index = sym_index, .file = null }; - try coff_file.addRelocation(atom_index, .{ - .type = switch (lowered_relocs[0].target) { - .linker_got => .got, - .linker_direct => .direct, - .linker_import => .import, + continue :lowered_inst; + }, + .branch, .tls => unreachable, + .tlv => { + if (emit.bin_file.cast(.elf)) |elf_file| { + // TODO handle extern TLS vars, i.e., emit GD model + if (emit.pic) switch (lowered_inst.encoding.mnemonic) { + .lea, .mov => { + // Here, we currently assume local dynamic TLS vars, and so + // we emit LD model. + try emit.encodeInst(try .new(.none, .lea, &.{ + .{ .reg = .rdi }, + .{ .mem = .initRip(.none, 0) }, + }, emit.lower.target), &.{.{ + .op_index = 1, + .target = .{ + .index = reloc.target.index, + .is_extern = false, + .type = .tls, + }, + }}); + try emit.encodeInst(try .new(.none, .call, &.{ + .{ .imm = .s(0) }, + }, emit.lower.target), &.{.{ + .op_index = 0, + .target = .{ + .index = try elf_file.getGlobalSymbol("__tls_get_addr", null), + .is_extern = true, + .type = .branch, + }, + }}); + try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(.none, .{ + .base = .{ .reg = .rax }, + .disp = std.math.minInt(i32), + }) }, + }, emit.lower.target), reloc_info); + }, + else => unreachable, + } else switch (lowered_inst.encoding.mnemonic) { + .lea, .mov => { + // Since we are linking statically, we emit LE model directly. + try emit.encodeInst(try .new(.none, .mov, &.{ + .{ .reg = .rax }, + .{ .mem = .initSib(.qword, .{ .base = .{ .reg = .fs } }) }, + }, emit.lower.target), &.{}); + try emit.encodeInst(try .new(.none, lowered_inst.encoding.mnemonic, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(.none, .{ + .base = .{ .reg = .rax }, + .disp = std.math.minInt(i32), + }) }, + }, emit.lower.target), reloc_info); + }, else => unreachable, + } + } else if (emit.bin_file.cast(.macho)) |_| switch (lowered_inst.encoding.mnemonic) { + .lea => { + try emit.encodeInst(try .new(.none, .mov, &.{ + .{ .reg = .rdi }, + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + try emit.encodeInst(try .new(.none, .call, &.{ + .{ .mem = .initSib(.qword, .{ .base = .{ .reg = .rdi } }) }, + }, emit.lower.target), &.{}); + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .reg = .rax }, + }, emit.lower.target), &.{}); }, - .target = target, - .offset = @intCast(end_offset - 4), - .addend = @intCast(lowered_relocs[0].off), - .pcrel = true, - .length = 2, - }); - } else if (emit.lower.bin_file.cast(.plan9)) |p9_file| { - try p9_file.addReloc(emit.atom_index, .{ // TODO we may need to add a .type field to the relocs if they are .linker_got instead of just .linker_direct - .target = sym_index, // we set sym_index to just be the atom index - .offset = @intCast(end_offset - 4), - .addend = @intCast(lowered_relocs[0].off), - .type = .pcrel, + .mov => { + try emit.encodeInst(try .new(.none, .mov, &.{ + .{ .reg = .rdi }, + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + try emit.encodeInst(try .new(.none, .call, &.{ + .{ .mem = .initSib(.qword, .{ .base = .{ .reg = .rdi } }) }, + }, emit.lower.target), &.{}); + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(.qword, .{ .base = .{ .reg = .rax } }) }, + }, emit.lower.target), &.{}); + }, + else => unreachable, + } else return emit.fail("TODO implement relocs for {s}", .{ + @tagName(emit.bin_file.tag), }); - } else return emit.fail("TODO implement linker reloc for {s}", .{ - @tagName(emit.lower.bin_file.tag), - }), + continue :lowered_inst; + }, }; + try emit.encodeInst(lowered_inst, reloc_info); } - std.debug.assert(lowered_relocs.len == 0); + assert(lowered_relocs.len == 0); if (lowered.insts.len == 0) { const mir_inst = emit.lower.mir.instructions.get(mir_index); @@ -338,7 +466,7 @@ pub fn emitMir(emit: *Emit) Error!void { log.debug("mirDbgEnterInline (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column, }); - try dwarf.enterInlineFunc(mir_inst.data.func, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column); + try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column); }, .plan9 => {}, .none => {}, @@ -348,77 +476,49 @@ pub fn emitMir(emit: *Emit) Error!void { log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ emit.prev_di_loc.line, emit.prev_di_loc.column, }); - try dwarf.leaveInlineFunc(mir_inst.data.func, emit.code.items.len); + try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.code.items.len); }, .plan9 => {}, .none => {}, }, - .pseudo_dbg_local_a, - .pseudo_dbg_local_ai_s, - .pseudo_dbg_local_ai_u, - .pseudo_dbg_local_ai_64, - .pseudo_dbg_local_as, - .pseudo_dbg_local_aso, - .pseudo_dbg_local_aro, - .pseudo_dbg_local_af, - .pseudo_dbg_local_am, + .pseudo_dbg_arg_none, + .pseudo_dbg_arg_i_s, + .pseudo_dbg_arg_i_u, + .pseudo_dbg_arg_i_64, + .pseudo_dbg_arg_ro, + .pseudo_dbg_arg_fa, + .pseudo_dbg_arg_m, + .pseudo_dbg_var_none, + .pseudo_dbg_var_i_s, + .pseudo_dbg_var_i_u, + .pseudo_dbg_var_i_64, + .pseudo_dbg_var_ro, + .pseudo_dbg_var_fa, + .pseudo_dbg_var_m, => switch (emit.debug_output) { .dwarf => |dwarf| { var loc_buf: [2]link.File.Dwarf.Loc = undefined; - const air_inst_index, const loc: link.File.Dwarf.Loc = switch (mir_inst.ops) { + const loc: link.File.Dwarf.Loc = loc: switch (mir_inst.ops) { else => unreachable, - .pseudo_dbg_local_a => .{ mir_inst.data.a.air_inst, .empty }, - .pseudo_dbg_local_ai_s, - .pseudo_dbg_local_ai_u, - .pseudo_dbg_local_ai_64, - => .{ mir_inst.data.ai.air_inst, .{ .stack_value = stack_value: { - loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.ai.i)) { + .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty, + .pseudo_dbg_arg_i_s, + .pseudo_dbg_arg_i_u, + .pseudo_dbg_var_i_s, + .pseudo_dbg_var_i_u, + => .{ .stack_value = stack_value: { + loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) { .signed => |s| .{ .consts = s }, .unsigned => |u| .{ .constu = u }, }; break :stack_value &loc_buf[0]; - } } }, - .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ - .addr_reloc = mir_inst.data.as.sym_index, } }, - .pseudo_dbg_local_aso => loc: { - const sym_off = emit.lower.mir.extraData( - bits.SymbolOffset, - mir_inst.data.ax.payload, - ).data; - break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ - sym: { - loc_buf[0] = .{ .addr_reloc = sym_off.sym_index }; - break :sym &loc_buf[0]; - }, - off: { - loc_buf[1] = .{ .consts = sym_off.off }; - break :off &loc_buf[1]; - }, - } } }; - }, - .pseudo_dbg_local_aro => loc: { - const air_off = emit.lower.mir.extraData( - Mir.AirOffset, - mir_inst.data.rx.payload, - ).data; - break :loc .{ air_off.air_inst, .{ .plus = .{ - reg: { - loc_buf[0] = .{ .breg = mir_inst.data.rx.r1.dwarfNum() }; - break :reg &loc_buf[0]; - }, - off: { - loc_buf[1] = .{ .consts = air_off.off }; - break :off &loc_buf[1]; - }, - } } }; - }, - .pseudo_dbg_local_af => loc: { - const reg_off = emit.lower.mir.resolveFrameAddr(emit.lower.mir.extraData( - bits.FrameAddr, - mir_inst.data.ax.payload, - ).data); - break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: { + loc_buf[0] = .{ .constu = mir_inst.data.i64 }; + break :stack_value &loc_buf[0]; + } }, + .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => { + const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa); + break :loc .{ .plus = .{ reg: { loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; break :reg &loc_buf[0]; @@ -427,18 +527,54 @@ pub fn emitMir(emit: *Emit) Error!void { loc_buf[1] = .{ .consts = reg_off.off }; break :off &loc_buf[1]; }, - } } }; + } }; }, - .pseudo_dbg_local_am => loc: { - const mem = emit.lower.mem(undefined, mir_inst.data.ax.payload); - break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{ + .pseudo_dbg_arg_m, .pseudo_dbg_var_m => { + const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode(); + break :loc .{ .plus = .{ base: { loc_buf[0] = switch (mem.base()) { .none => .{ .constu = 0 }, .reg => |reg| .{ .breg = reg.dwarfNum() }, .frame, .table, .rip_inst => unreachable, - .reloc => |sym_index| .{ .addr_reloc = sym_index }, - .pcrel => unreachable, + .nav => |nav| .{ .addr_reloc = switch (codegen.genNavRef( + emit.bin_file, + emit.pt, + emit.lower.src_loc, + nav, + emit.lower.target.*, + ) catch |err| switch (err) { + error.CodegenFail, + => return emit.fail("unable to codegen: {s}", .{@errorName(err)}), + else => |e| return e, + }) { + .mcv => |mcv| switch (mcv) { + else => unreachable, + .load_direct, .load_symbol => |sym_index| sym_index, + }, + .fail => |em| { + assert(emit.lower.err_msg == null); + emit.lower.err_msg = em; + return error.EmitFail; + }, + } }, + .uav => |uav| .{ .addr_reloc = switch (try emit.bin_file.lowerUav( + emit.pt, + uav.val, + Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu), + emit.lower.src_loc, + )) { + .mcv => |mcv| switch (mcv) { + else => unreachable, + .load_direct, .load_symbol => |sym_index| sym_index, + }, + .fail => |em| { + assert(emit.lower.err_msg == null); + emit.lower.err_msg = em; + return error.EmitFail; + }, + } }, + .lazy_sym, .extern_func => unreachable, }; break :base &loc_buf[0]; }, @@ -449,34 +585,57 @@ pub fn emitMir(emit: *Emit) Error!void { }; break :disp &loc_buf[1]; }, - } } }; + } }; }, }; - const ip = &emit.lower.bin_file.comp.zcu.?.intern_pool; - const air_inst = emit.air.instructions.get(@intFromEnum(air_inst_index)); - const name: Air.NullTerminatedString = switch (air_inst.tag) { - else => unreachable, - .arg => air_inst.data.arg.name, - .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => @enumFromInt(air_inst.data.pl_op.payload), - }; - try dwarf.genLocalDebugInfo( - switch (air_inst.tag) { + + const local = &emit.lower.mir.locals[local_index]; + local_index += 1; + try dwarf.genLocalVarDebugInfo( + switch (mir_inst.ops) { else => unreachable, - .arg, .dbg_arg_inline => .local_arg, - .dbg_var_ptr, .dbg_var_val => .local_var, + .pseudo_dbg_arg_none, + .pseudo_dbg_arg_i_s, + .pseudo_dbg_arg_i_u, + .pseudo_dbg_arg_i_64, + .pseudo_dbg_arg_ro, + .pseudo_dbg_arg_fa, + .pseudo_dbg_arg_m, + .pseudo_dbg_arg_val, + => .arg, + .pseudo_dbg_var_none, + .pseudo_dbg_var_i_s, + .pseudo_dbg_var_i_u, + .pseudo_dbg_var_i_64, + .pseudo_dbg_var_ro, + .pseudo_dbg_var_fa, + .pseudo_dbg_var_m, + .pseudo_dbg_var_val, + => .local_var, }, - name.toSlice(emit.air), - switch (air_inst.tag) { + local.name.toSlice(&emit.lower.mir), + .fromInterned(local.type), + loc, + ); + }, + .plan9, .none => local_index += 1, + }, + .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) { + .dwarf => |dwarf| { + const local = &emit.lower.mir.locals[local_index]; + local_index += 1; + try dwarf.genLocalConstDebugInfo( + emit.lower.src_loc, + switch (mir_inst.ops) { else => unreachable, - .arg => emit.air.typeOfIndex(air_inst_index, ip), - .dbg_var_ptr => emit.air.typeOf(air_inst.data.pl_op.operand, ip).childTypeIp(ip), - .dbg_var_val, .dbg_arg_inline => emit.air.typeOf(air_inst.data.pl_op.operand, ip), + .pseudo_dbg_arg_val => .comptime_arg, + .pseudo_dbg_var_val => .local_const, }, - loc, + local.name.toSlice(&emit.lower.mir), + .fromInterned(mir_inst.data.ip_index), ); }, - .plan9 => {}, - .none => {}, + .plan9, .none => local_index += 1, }, .pseudo_dbg_var_args_none => switch (emit.debug_output) { .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(), @@ -488,8 +647,8 @@ pub fn emitMir(emit: *Emit) Error!void { } } } - for (relocs.items) |reloc| { - const target = code_offset_mapping[reloc.target]; + for (emit.relocs.items) |reloc| { + const target = emit.code_offset_mapping.items[reloc.target]; const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.inst_offset + reloc.inst_length)) + reloc.target_offset; const inst_bytes = emit.code.items[reloc.inst_offset..][0..reloc.inst_length]; switch (reloc.source_length) { @@ -503,13 +662,13 @@ pub fn emitMir(emit: *Emit) Error!void { } } if (emit.lower.mir.table.len > 0) { - if (emit.lower.bin_file.cast(.elf)) |elf_file| { + if (emit.bin_file.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; const atom = zo.symbol(emit.atom_index).atom(elf_file).?; const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8); var table_offset = std.mem.alignForward(u32, @intCast(emit.code.items.len), ptr_size); - for (table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{ + for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{ .r_offset = table_reloc.source_offset, .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"), .r_addend = @as(i64, table_offset) + table_reloc.target_offset, @@ -518,7 +677,7 @@ pub fn emitMir(emit: *Emit) Error!void { try atom.addReloc(gpa, .{ .r_offset = table_offset, .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"64"), - .r_addend = code_offset_mapping[entry], + .r_addend = emit.code_offset_mapping.items[entry], }, zo); table_offset += ptr_size; } @@ -527,6 +686,200 @@ pub fn emitMir(emit: *Emit) Error!void { } } +pub fn deinit(emit: *Emit) void { + const gpa = emit.bin_file.comp.gpa; + emit.code_offset_mapping.deinit(gpa); + emit.relocs.deinit(gpa); + emit.table_relocs.deinit(gpa); + emit.* = undefined; +} + +const RelocInfo = struct { + op_index: Lower.InstOpIndex, + off: i32 = 0, + target: Target, + + const Target = struct { + index: u32, + is_extern: bool, + type: Target.Type, + force_pcrel_direct: bool = false, + + const Type = enum { inst, table, symbol, branch, tls, tlv }; + }; +}; + +fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocInfo) Error!void { + const comp = emit.bin_file.comp; + const gpa = comp.gpa; + const start_offset: u32 = @intCast(emit.code.items.len); + try lowered_inst.encode(emit.code.writer(gpa), .{}); + const end_offset: u32 = @intCast(emit.code.items.len); + for (reloc_info) |reloc| switch (reloc.target.type) { + .inst => { + const inst_length: u4 = @intCast(end_offset - start_offset); + const reloc_offset, const reloc_length = reloc_offset_length: { + var reloc_offset = inst_length; + var op_index: usize = lowered_inst.ops.len; + while (true) { + op_index -= 1; + const op = lowered_inst.encoding.data.ops[op_index]; + if (op == .none) continue; + const is_mem = op.isMemory(); + const enc_length: u4 = if (is_mem) switch (lowered_inst.ops[op_index].mem.sib.base) { + .rip_inst => 4, + else => unreachable, + } else @intCast(std.math.divCeil(u7, @intCast(op.immBitSize()), 8) catch unreachable); + reloc_offset -= enc_length; + if (op_index == reloc.op_index) break :reloc_offset_length .{ reloc_offset, enc_length }; + assert(!is_mem); + } + }; + try emit.relocs.append(emit.lower.allocator, .{ + .inst_offset = start_offset, + .inst_length = inst_length, + .source_offset = reloc_offset, + .source_length = reloc_length, + .target = reloc.target.index, + .target_offset = reloc.off, + }); + }, + .table => try emit.table_relocs.append(emit.lower.allocator, .{ + .source_offset = end_offset - 4, + .target_offset = reloc.off, + }), + .symbol => if (emit.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; + const r_type: std.elf.R_X86_64 = if (!emit.pic) + .@"32" + else if (reloc.target.is_extern and !reloc.target.force_pcrel_direct) + .GOTPCREL + else + .PC32; + try atom.addReloc(gpa, .{ + .r_offset = end_offset - 4, + .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), + .r_addend = if (emit.pic) reloc.off - 4 else reloc.off, + }, zo); + } else if (emit.bin_file.cast(.macho)) |macho_file| { + const zo = macho_file.getZigObject().?; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; + try atom.addReloc(macho_file, .{ + .tag = .@"extern", + .offset = end_offset - 4, + .target = reloc.target.index, + .addend = reloc.off, + .type = if (reloc.target.is_extern and !reloc.target.force_pcrel_direct) .got_load else .signed, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(reloc.target.index), + }, + }); + } else if (emit.bin_file.cast(.coff)) |coff_file| { + const atom_index = coff_file.getAtomIndexForSymbol( + .{ .sym_index = emit.atom_index, .file = null }, + ).?; + try coff_file.addRelocation(atom_index, .{ + .type = if (reloc.target.is_extern) .got else .direct, + .target = if (reloc.target.is_extern) + coff_file.getGlobalByIndex(reloc.target.index) + else + .{ .sym_index = reloc.target.index, .file = null }, + .offset = end_offset - 4, + .addend = @intCast(reloc.off), + .pcrel = true, + .length = 2, + }); + } else unreachable, + .branch => if (emit.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; + const r_type: std.elf.R_X86_64 = .PLT32; + try atom.addReloc(gpa, .{ + .r_offset = end_offset - 4, + .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), + .r_addend = reloc.off - 4, + }, zo); + } else if (emit.bin_file.cast(.macho)) |macho_file| { + const zo = macho_file.getZigObject().?; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; + try atom.addReloc(macho_file, .{ + .tag = .@"extern", + .offset = end_offset - 4, + .target = reloc.target.index, + .addend = reloc.off, + .type = .branch, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(reloc.target.index), + }, + }); + } else if (emit.bin_file.cast(.coff)) |coff_file| { + const atom_index = coff_file.getAtomIndexForSymbol( + .{ .sym_index = emit.atom_index, .file = null }, + ).?; + try coff_file.addRelocation(atom_index, .{ + .type = if (reloc.target.is_extern) .import else .got, + .target = if (reloc.target.is_extern) + coff_file.getGlobalByIndex(reloc.target.index) + else + .{ .sym_index = reloc.target.index, .file = null }, + .offset = end_offset - 4, + .addend = @intCast(reloc.off), + .pcrel = true, + .length = 2, + }); + } else return emit.fail("TODO implement {s} reloc for {s}", .{ + @tagName(reloc.target.type), @tagName(emit.bin_file.tag), + }), + .tls => if (emit.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; + const r_type: std.elf.R_X86_64 = if (emit.pic) .TLSLD else unreachable; + try atom.addReloc(gpa, .{ + .r_offset = end_offset - 4, + .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), + .r_addend = reloc.off - 4, + }, zo); + } else return emit.fail("TODO implement {s} reloc for {s}", .{ + @tagName(reloc.target.type), @tagName(emit.bin_file.tag), + }), + .tlv => if (emit.bin_file.cast(.elf)) |elf_file| { + const zo = elf_file.zigObjectPtr().?; + const atom = zo.symbol(emit.atom_index).atom(elf_file).?; + const r_type: std.elf.R_X86_64 = if (emit.pic) .DTPOFF32 else .TPOFF32; + try atom.addReloc(gpa, .{ + .r_offset = end_offset - 4, + .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), + .r_addend = reloc.off, + }, zo); + } else if (emit.bin_file.cast(.macho)) |macho_file| { + const zo = macho_file.getZigObject().?; + const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; + try atom.addReloc(macho_file, .{ + .tag = .@"extern", + .offset = end_offset - 4, + .target = reloc.target.index, + .addend = reloc.off, + .type = .tlv, + .meta = .{ + .pcrel = true, + .has_subtractor = false, + .length = 2, + .symbolnum = @intCast(reloc.target.index), + }, + }); + } else return emit.fail("TODO implement {s} reloc for {s}", .{ + @tagName(reloc.target.type), @tagName(emit.bin_file.tag), + }), + }; +} + fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error { return switch (emit.lower.fail(format, args)) { error.LowerFail => error.EmitFail, @@ -610,12 +963,17 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { } } +const assert = std.debug.assert; const bits = @import("bits.zig"); +const codegen = @import("../../codegen.zig"); +const Emit = @This(); +const encoder = @import("encoder.zig"); +const Instruction = encoder.Instruction; +const InternPool = @import("../../InternPool.zig"); const link = @import("../../link.zig"); const log = std.log.scoped(.emit); -const std = @import("std"); - -const Air = @import("../../Air.zig"); -const Emit = @This(); const Lower = @import("Lower.zig"); const Mir = @import("Mir.zig"); +const std = @import("std"); +const Type = @import("../../Type.zig"); +const Zcu = @import("../../Zcu.zig"); diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 838f155d10db..ca1fb1e428b6 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -1,10 +1,6 @@ //! This file contains the functionality for lowering x86_64 MIR to Instructions -bin_file: *link.File, target: *const std.Target, -output_mode: std.builtin.OutputMode, -link_mode: std.builtin.LinkMode, -pic: bool, allocator: std.mem.Allocator, mir: Mir, cc: std.builtin.CallingConvention, @@ -17,7 +13,6 @@ result_relocs: [max_result_relocs]Reloc = undefined, const max_result_insts = @max( 1, // non-pseudo instructions - 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode 2, // cmovcc: cmovcc \ cmovcc 3, // setcc: setcc \ setcc \ logicop 2, // jcc: jcc \ jcc @@ -25,6 +20,7 @@ const max_result_insts = @max( pseudo_probe_adjust_unrolled_max_insts, pseudo_probe_adjust_setup_insts, pseudo_probe_adjust_loop_insts, + abi.zigcc.callee_preserved_regs.len * 2, // push_regs/pop_regs abi.Win64.callee_preserved_regs.len * 2, // push_regs/pop_regs abi.SysV.callee_preserved_regs.len * 2, // push_regs/pop_regs ); @@ -33,14 +29,13 @@ const max_result_relocs = @max( 2, // jcc: jcc \ jcc 2, // test \ jcc \ probe \ sub \ jmp 1, // probe \ sub \ jcc - 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode ); -const ResultInstIndex = std.math.IntFittingRange(0, max_result_insts - 1); -const ResultRelocIndex = std.math.IntFittingRange(0, max_result_relocs - 1); -const InstOpIndex = std.math.IntFittingRange( +const ResultInstIndex = std.math.IntFittingRange(0, max_result_insts); +const ResultRelocIndex = std.math.IntFittingRange(0, max_result_relocs); +pub const InstOpIndex = std.math.IntFittingRange( 0, - @typeInfo(@FieldType(Instruction, "ops")).array.len - 1, + @typeInfo(@FieldType(Instruction, "ops")).array.len, ); pub const pseudo_probe_align_insts = 5; // test \ jcc \ probe \ sub \ jmp @@ -54,7 +49,8 @@ pub const Error = error{ LowerFail, InvalidInstruction, CannotEncode, -}; + CodegenFail, +} || codegen.GenerateSymbolError; pub const Reloc = struct { lowered_inst_index: ResultInstIndex, @@ -65,14 +61,10 @@ pub const Reloc = struct { const Target = union(enum) { inst: Mir.Inst.Index, table, - linker_reloc: u32, - linker_pcrel: u32, - linker_tlsld: u32, - linker_dtpoff: u32, - linker_extern_fn: u32, - linker_got: u32, - linker_direct: u32, - linker_import: u32, + nav: InternPool.Nav.Index, + uav: InternPool.Key.Ptr.BaseAddr.Uav, + lazy_sym: link.File.LazySymbol, + extern_func: Mir.NullTerminatedString, }; }; @@ -80,7 +72,7 @@ const Options = struct { allow_frame_locs: bool }; /// The returned slice is overwritten by the next call to lowerMir. pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { - insts: []const Instruction, + insts: []Instruction, relocs: []const Reloc, } { lower.result_insts = undefined; @@ -98,130 +90,130 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo => switch (inst.ops) { .pseudo_cmov_z_and_np_rr => { assert(inst.data.rr.fixes == ._); - try lower.emit(.none, .cmovnz, &.{ + try lower.encode(.none, .cmovnz, &.{ .{ .reg = inst.data.rr.r2 }, .{ .reg = inst.data.rr.r1 }, }); - try lower.emit(.none, .cmovnp, &.{ + try lower.encode(.none, .cmovnp, &.{ .{ .reg = inst.data.rr.r1 }, .{ .reg = inst.data.rr.r2 }, }); }, .pseudo_cmov_nz_or_p_rr => { assert(inst.data.rr.fixes == ._); - try lower.emit(.none, .cmovnz, &.{ + try lower.encode(.none, .cmovnz, &.{ .{ .reg = inst.data.rr.r1 }, .{ .reg = inst.data.rr.r2 }, }); - try lower.emit(.none, .cmovp, &.{ + try lower.encode(.none, .cmovp, &.{ .{ .reg = inst.data.rr.r1 }, .{ .reg = inst.data.rr.r2 }, }); }, .pseudo_cmov_nz_or_p_rm => { assert(inst.data.rx.fixes == ._); - try lower.emit(.none, .cmovnz, &.{ + try lower.encode(.none, .cmovnz, &.{ .{ .reg = inst.data.rx.r1 }, .{ .mem = lower.mem(1, inst.data.rx.payload) }, }); - try lower.emit(.none, .cmovp, &.{ + try lower.encode(.none, .cmovp, &.{ .{ .reg = inst.data.rx.r1 }, .{ .mem = lower.mem(1, inst.data.rx.payload) }, }); }, .pseudo_set_z_and_np_r => { assert(inst.data.rr.fixes == ._); - try lower.emit(.none, .setz, &.{ + try lower.encode(.none, .setz, &.{ .{ .reg = inst.data.rr.r1 }, }); - try lower.emit(.none, .setnp, &.{ + try lower.encode(.none, .setnp, &.{ .{ .reg = inst.data.rr.r2 }, }); - try lower.emit(.none, .@"and", &.{ + try lower.encode(.none, .@"and", &.{ .{ .reg = inst.data.rr.r1 }, .{ .reg = inst.data.rr.r2 }, }); }, .pseudo_set_z_and_np_m => { assert(inst.data.rx.fixes == ._); - try lower.emit(.none, .setz, &.{ + try lower.encode(.none, .setz, &.{ .{ .mem = lower.mem(0, inst.data.rx.payload) }, }); - try lower.emit(.none, .setnp, &.{ + try lower.encode(.none, .setnp, &.{ .{ .reg = inst.data.rx.r1 }, }); - try lower.emit(.none, .@"and", &.{ + try lower.encode(.none, .@"and", &.{ .{ .mem = lower.mem(0, inst.data.rx.payload) }, .{ .reg = inst.data.rx.r1 }, }); }, .pseudo_set_nz_or_p_r => { assert(inst.data.rr.fixes == ._); - try lower.emit(.none, .setnz, &.{ + try lower.encode(.none, .setnz, &.{ .{ .reg = inst.data.rr.r1 }, }); - try lower.emit(.none, .setp, &.{ + try lower.encode(.none, .setp, &.{ .{ .reg = inst.data.rr.r2 }, }); - try lower.emit(.none, .@"or", &.{ + try lower.encode(.none, .@"or", &.{ .{ .reg = inst.data.rr.r1 }, .{ .reg = inst.data.rr.r2 }, }); }, .pseudo_set_nz_or_p_m => { assert(inst.data.rx.fixes == ._); - try lower.emit(.none, .setnz, &.{ + try lower.encode(.none, .setnz, &.{ .{ .mem = lower.mem(0, inst.data.rx.payload) }, }); - try lower.emit(.none, .setp, &.{ + try lower.encode(.none, .setp, &.{ .{ .reg = inst.data.rx.r1 }, }); - try lower.emit(.none, .@"or", &.{ + try lower.encode(.none, .@"or", &.{ .{ .mem = lower.mem(0, inst.data.rx.payload) }, .{ .reg = inst.data.rx.r1 }, }); }, .pseudo_j_z_and_np_inst => { assert(inst.data.inst.fixes == ._); - try lower.emit(.none, .jnz, &.{ + try lower.encode(.none, .jnz, &.{ .{ .imm = lower.reloc(0, .{ .inst = index + 1 }, 0) }, }); - try lower.emit(.none, .jnp, &.{ + try lower.encode(.none, .jnp, &.{ .{ .imm = lower.reloc(0, .{ .inst = inst.data.inst.inst }, 0) }, }); }, .pseudo_j_nz_or_p_inst => { assert(inst.data.inst.fixes == ._); - try lower.emit(.none, .jnz, &.{ + try lower.encode(.none, .jnz, &.{ .{ .imm = lower.reloc(0, .{ .inst = inst.data.inst.inst }, 0) }, }); - try lower.emit(.none, .jp, &.{ + try lower.encode(.none, .jp, &.{ .{ .imm = lower.reloc(0, .{ .inst = inst.data.inst.inst }, 0) }, }); }, .pseudo_probe_align_ri_s => { - try lower.emit(.none, .@"test", &.{ + try lower.encode(.none, .@"test", &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = .s(@bitCast(inst.data.ri.i)) }, }); - try lower.emit(.none, .jz, &.{ + try lower.encode(.none, .jz, &.{ .{ .imm = lower.reloc(0, .{ .inst = index + 1 }, 0) }, }); - try lower.emit(.none, .lea, &.{ + try lower.encode(.none, .lea, &.{ .{ .reg = inst.data.ri.r1 }, .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = inst.data.ri.r1 }, .disp = -page_size, }) }, }); - try lower.emit(.none, .@"test", &.{ + try lower.encode(.none, .@"test", &.{ .{ .mem = Memory.initSib(.dword, .{ .base = .{ .reg = inst.data.ri.r1 }, }) }, .{ .reg = inst.data.ri.r1.to32() }, }); - try lower.emit(.none, .jmp, &.{ + try lower.encode(.none, .jmp, &.{ .{ .imm = lower.reloc(0, .{ .inst = index }, 0) }, }); assert(lower.result_insts_len == pseudo_probe_align_insts); @@ -229,7 +221,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_probe_adjust_unrolled_ri_s => { var offset = page_size; while (offset < @as(i32, @bitCast(inst.data.ri.i))) : (offset += page_size) { - try lower.emit(.none, .@"test", &.{ + try lower.encode(.none, .@"test", &.{ .{ .mem = Memory.initSib(.dword, .{ .base = .{ .reg = inst.data.ri.r1 }, .disp = -offset, @@ -237,25 +229,25 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .{ .reg = inst.data.ri.r1.to32() }, }); } - try lower.emit(.none, .sub, &.{ + try lower.encode(.none, .sub, &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = .s(@bitCast(inst.data.ri.i)) }, }); assert(lower.result_insts_len <= pseudo_probe_adjust_unrolled_max_insts); }, .pseudo_probe_adjust_setup_rri_s => { - try lower.emit(.none, .mov, &.{ + try lower.encode(.none, .mov, &.{ .{ .reg = inst.data.rri.r2.to32() }, .{ .imm = .s(@bitCast(inst.data.rri.i)) }, }); - try lower.emit(.none, .sub, &.{ + try lower.encode(.none, .sub, &.{ .{ .reg = inst.data.rri.r1 }, .{ .reg = inst.data.rri.r2 }, }); assert(lower.result_insts_len == pseudo_probe_adjust_setup_insts); }, .pseudo_probe_adjust_loop_rr => { - try lower.emit(.none, .@"test", &.{ + try lower.encode(.none, .@"test", &.{ .{ .mem = Memory.initSib(.dword, .{ .base = .{ .reg = inst.data.rr.r1 }, .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 }, @@ -263,11 +255,11 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { }) }, .{ .reg = inst.data.rr.r1.to32() }, }); - try lower.emit(.none, .sub, &.{ + try lower.encode(.none, .sub, &.{ .{ .reg = inst.data.rr.r2 }, .{ .imm = .s(page_size) }, }); - try lower.emit(.none, .jae, &.{ + try lower.encode(.none, .jae, &.{ .{ .imm = lower.reloc(0, .{ .inst = index }, 0) }, }); assert(lower.result_insts_len == pseudo_probe_adjust_loop_insts); @@ -275,47 +267,47 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst), .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst), - .pseudo_cfi_def_cfa_ri_s => try lower.emit(.directive, .@".cfi_def_cfa", &.{ + .pseudo_cfi_def_cfa_ri_s => try lower.encode(.directive, .@".cfi_def_cfa", &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = lower.imm(.ri_s, inst.data.ri.i) }, }), - .pseudo_cfi_def_cfa_register_r => try lower.emit(.directive, .@".cfi_def_cfa_register", &.{ + .pseudo_cfi_def_cfa_register_r => try lower.encode(.directive, .@".cfi_def_cfa_register", &.{ .{ .reg = inst.data.r.r1 }, }), - .pseudo_cfi_def_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_def_cfa_offset", &.{ + .pseudo_cfi_def_cfa_offset_i_s => try lower.encode(.directive, .@".cfi_def_cfa_offset", &.{ .{ .imm = lower.imm(.i_s, inst.data.i.i) }, }), - .pseudo_cfi_adjust_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_adjust_cfa_offset", &.{ + .pseudo_cfi_adjust_cfa_offset_i_s => try lower.encode(.directive, .@".cfi_adjust_cfa_offset", &.{ .{ .imm = lower.imm(.i_s, inst.data.i.i) }, }), - .pseudo_cfi_offset_ri_s => try lower.emit(.directive, .@".cfi_offset", &.{ + .pseudo_cfi_offset_ri_s => try lower.encode(.directive, .@".cfi_offset", &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = lower.imm(.ri_s, inst.data.ri.i) }, }), - .pseudo_cfi_val_offset_ri_s => try lower.emit(.directive, .@".cfi_val_offset", &.{ + .pseudo_cfi_val_offset_ri_s => try lower.encode(.directive, .@".cfi_val_offset", &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = lower.imm(.ri_s, inst.data.ri.i) }, }), - .pseudo_cfi_rel_offset_ri_s => try lower.emit(.directive, .@".cfi_rel_offset", &.{ + .pseudo_cfi_rel_offset_ri_s => try lower.encode(.directive, .@".cfi_rel_offset", &.{ .{ .reg = inst.data.ri.r1 }, .{ .imm = lower.imm(.ri_s, inst.data.ri.i) }, }), - .pseudo_cfi_register_rr => try lower.emit(.directive, .@".cfi_register", &.{ + .pseudo_cfi_register_rr => try lower.encode(.directive, .@".cfi_register", &.{ .{ .reg = inst.data.rr.r1 }, .{ .reg = inst.data.rr.r2 }, }), - .pseudo_cfi_restore_r => try lower.emit(.directive, .@".cfi_restore", &.{ + .pseudo_cfi_restore_r => try lower.encode(.directive, .@".cfi_restore", &.{ .{ .reg = inst.data.r.r1 }, }), - .pseudo_cfi_undefined_r => try lower.emit(.directive, .@".cfi_undefined", &.{ + .pseudo_cfi_undefined_r => try lower.encode(.directive, .@".cfi_undefined", &.{ .{ .reg = inst.data.r.r1 }, }), - .pseudo_cfi_same_value_r => try lower.emit(.directive, .@".cfi_same_value", &.{ + .pseudo_cfi_same_value_r => try lower.encode(.directive, .@".cfi_same_value", &.{ .{ .reg = inst.data.r.r1 }, }), - .pseudo_cfi_remember_state_none => try lower.emit(.directive, .@".cfi_remember_state", &.{}), - .pseudo_cfi_restore_state_none => try lower.emit(.directive, .@".cfi_restore_state", &.{}), - .pseudo_cfi_escape_bytes => try lower.emit(.directive, .@".cfi_escape", &.{ + .pseudo_cfi_remember_state_none => try lower.encode(.directive, .@".cfi_remember_state", &.{}), + .pseudo_cfi_restore_state_none => try lower.encode(.directive, .@".cfi_restore_state", &.{}), + .pseudo_cfi_escape_bytes => try lower.encode(.directive, .@".cfi_escape", &.{ .{ .bytes = inst.data.bytes.get(lower.mir) }, }), @@ -327,16 +319,23 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { .pseudo_dbg_leave_block_none, .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func, - .pseudo_dbg_local_a, - .pseudo_dbg_local_ai_s, - .pseudo_dbg_local_ai_u, - .pseudo_dbg_local_ai_64, - .pseudo_dbg_local_as, - .pseudo_dbg_local_aso, - .pseudo_dbg_local_aro, - .pseudo_dbg_local_af, - .pseudo_dbg_local_am, + .pseudo_dbg_arg_none, + .pseudo_dbg_arg_i_s, + .pseudo_dbg_arg_i_u, + .pseudo_dbg_arg_i_64, + .pseudo_dbg_arg_ro, + .pseudo_dbg_arg_fa, + .pseudo_dbg_arg_m, + .pseudo_dbg_arg_val, .pseudo_dbg_var_args_none, + .pseudo_dbg_var_none, + .pseudo_dbg_var_i_s, + .pseudo_dbg_var_i_u, + .pseudo_dbg_var_i_64, + .pseudo_dbg_var_ro, + .pseudo_dbg_var_fa, + .pseudo_dbg_var_m, + .pseudo_dbg_var_val, .pseudo_dead_none, => {}, @@ -353,7 +352,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error { @branchHint(.cold); assert(lower.err_msg == null); - lower.err_msg = try Zcu.ErrorMsg.create(lower.allocator, lower.src_loc, format, args); + lower.err_msg = try .create(lower.allocator, lower.src_loc, format, args); return error.LowerFail; } @@ -364,7 +363,8 @@ pub fn imm(lower: *const Lower, ops: Mir.Inst.Ops, i: u32) Immediate { .i_s, .mi_s, .rmi_s, - .pseudo_dbg_local_ai_s, + .pseudo_dbg_arg_i_s, + .pseudo_dbg_var_i_s, => .s(@bitCast(i)), .ii, @@ -379,24 +379,32 @@ pub fn imm(lower: *const Lower, ops: Mir.Inst.Ops, i: u32) Immediate { .mri, .rrm, .rrmi, - .pseudo_dbg_local_ai_u, + .pseudo_dbg_arg_i_u, + .pseudo_dbg_var_i_u, => .u(i), .ri_64, - .pseudo_dbg_local_ai_64, => .u(lower.mir.extraData(Mir.Imm64, i).data.decode()), + .pseudo_dbg_arg_i_64, + .pseudo_dbg_var_i_64, + => unreachable, + else => unreachable, }; } -pub fn mem(lower: *Lower, op_index: InstOpIndex, payload: u32) Memory { - var m = lower.mir.resolveFrameLoc(lower.mir.extraData(Mir.Memory, payload).data).decode(); +fn mem(lower: *Lower, op_index: InstOpIndex, payload: u32) Memory { + var m = lower.mir.resolveMemoryExtra(payload).decode(); switch (m) { .sib => |*sib| switch (sib.base) { - else => {}, + .none, .reg, .frame => {}, .table => sib.disp = lower.reloc(op_index, .table, sib.disp).signed, .rip_inst => |inst_index| sib.disp = lower.reloc(op_index, .{ .inst = inst_index }, sib.disp).signed, + .nav => |nav| sib.disp = lower.reloc(op_index, .{ .nav = nav }, sib.disp).signed, + .uav => |uav| sib.disp = lower.reloc(op_index, .{ .uav = uav }, sib.disp).signed, + .lazy_sym => |lazy_sym| sib.disp = lower.reloc(op_index, .{ .lazy_sym = lazy_sym }, sib.disp).signed, + .extern_func => |extern_func| sib.disp = lower.reloc(op_index, .{ .extern_func = extern_func }, sib.disp).signed, }, else => {}, } @@ -414,177 +422,40 @@ fn reloc(lower: *Lower, op_index: InstOpIndex, target: Reloc.Target, off: i32) I return .s(0); } -fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { - const emit_prefix = prefix; - var emit_mnemonic = mnemonic; - var emit_ops_storage: [4]Operand = undefined; - const emit_ops = emit_ops_storage[0..ops.len]; - for (emit_ops, ops, 0..) |*emit_op, op, op_index| { - emit_op.* = switch (op) { - else => op, - .mem => |mem_op| op: switch (mem_op.base()) { - else => op, - .reloc => |sym_index| { - assert(prefix == .none); - assert(mem_op.sib.disp == 0); - assert(mem_op.sib.scale_index.scale == 0); - - if (lower.bin_file.cast(.elf)) |elf_file| { - const zo = elf_file.zigObjectPtr().?; - const elf_sym = zo.symbol(sym_index); - - if (elf_sym.flags.is_tls) { - // TODO handle extern TLS vars, i.e., emit GD model - if (lower.pic) { - // Here, we currently assume local dynamic TLS vars, and so - // we emit LD model. - _ = lower.reloc(1, .{ .linker_tlsld = sym_index }, 0); - lower.result_insts[lower.result_insts_len] = try .new(.none, .lea, &.{ - .{ .reg = .rdi }, - .{ .mem = Memory.initRip(.none, 0) }, - }, lower.target); - lower.result_insts_len += 1; - _ = lower.reloc(0, .{ - .linker_extern_fn = try elf_file.getGlobalSymbol("__tls_get_addr", null), - }, 0); - lower.result_insts[lower.result_insts_len] = try .new(.none, .call, &.{ - .{ .imm = .s(0) }, - }, lower.target); - lower.result_insts_len += 1; - _ = lower.reloc(@intCast(op_index), .{ .linker_dtpoff = sym_index }, 0); - emit_mnemonic = .lea; - break :op .{ .mem = Memory.initSib(.none, .{ - .base = .{ .reg = .rax }, - .disp = std.math.minInt(i32), - }) }; - } else { - // Since we are linking statically, we emit LE model directly. - lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{ - .{ .reg = .rax }, - .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .fs } }) }, - }, lower.target); - lower.result_insts_len += 1; - _ = lower.reloc(@intCast(op_index), .{ .linker_reloc = sym_index }, 0); - emit_mnemonic = .lea; - break :op .{ .mem = Memory.initSib(.none, .{ - .base = .{ .reg = .rax }, - .disp = std.math.minInt(i32), - }) }; - } - } - - if (lower.pic) switch (mnemonic) { - .lea => { - _ = lower.reloc(@intCast(op_index), .{ .linker_reloc = sym_index }, 0); - if (!elf_sym.flags.is_extern_ptr) break :op .{ .mem = Memory.initRip(.none, 0) }; - emit_mnemonic = .mov; - break :op .{ .mem = Memory.initRip(.ptr, 0) }; - }, - .mov => { - if (elf_sym.flags.is_extern_ptr) { - const reg = ops[0].reg; - _ = lower.reloc(1, .{ .linker_reloc = sym_index }, 0); - lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{ - .{ .reg = reg.to64() }, - .{ .mem = Memory.initRip(.qword, 0) }, - }, lower.target); - lower.result_insts_len += 1; - break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{ - .reg = reg.to64(), - } }) }; - } - _ = lower.reloc(@intCast(op_index), .{ .linker_reloc = sym_index }, 0); - break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }; - }, - else => unreachable, - }; - _ = lower.reloc(@intCast(op_index), .{ .linker_reloc = sym_index }, 0); - switch (mnemonic) { - .call => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ - .base = .{ .reg = .ds }, - }) }, - .lea => { - emit_mnemonic = .mov; - break :op .{ .imm = .s(0) }; - }, - .mov => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ - .base = .{ .reg = .ds }, - }) }, - else => unreachable, - } - } else if (lower.bin_file.cast(.macho)) |macho_file| { - const zo = macho_file.getZigObject().?; - const macho_sym = zo.symbols.items[sym_index]; - - if (macho_sym.flags.tlv) { - _ = lower.reloc(1, .{ .linker_reloc = sym_index }, 0); - lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{ - .{ .reg = .rdi }, - .{ .mem = Memory.initRip(.ptr, 0) }, - }, lower.target); - lower.result_insts_len += 1; - lower.result_insts[lower.result_insts_len] = try .new(.none, .call, &.{ - .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .rdi } }) }, - }, lower.target); - lower.result_insts_len += 1; - emit_mnemonic = .mov; - break :op .{ .reg = .rax }; - } - - break :op switch (mnemonic) { - .lea => { - _ = lower.reloc(@intCast(op_index), .{ .linker_reloc = sym_index }, 0); - if (!macho_sym.flags.is_extern_ptr) break :op .{ .mem = Memory.initRip(.none, 0) }; - emit_mnemonic = .mov; - break :op .{ .mem = Memory.initRip(.ptr, 0) }; - }, - .mov => { - if (macho_sym.flags.is_extern_ptr) { - const reg = ops[0].reg; - _ = lower.reloc(1, .{ .linker_reloc = sym_index }, 0); - lower.result_insts[lower.result_insts_len] = try .new(.none, .mov, &.{ - .{ .reg = reg.to64() }, - .{ .mem = Memory.initRip(.qword, 0) }, - }, lower.target); - lower.result_insts_len += 1; - break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{ - .reg = reg.to64(), - } }) }; - } - _ = lower.reloc(@intCast(op_index), .{ .linker_reloc = sym_index }, 0); - break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }; - }, - else => unreachable, - }; - } else { - return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)}); - } - }, - .pcrel => |sym_index| { - assert(prefix == .none); - assert(mem_op.sib.disp == 0); - assert(mem_op.sib.scale_index.scale == 0); +fn encode(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { + lower.result_insts[lower.result_insts_len] = try .new(prefix, mnemonic, ops, lower.target); + lower.result_insts_len += 1; +} - _ = lower.reloc(@intCast(op_index), .{ .linker_pcrel = sym_index }, 0); - break :op switch (lower.bin_file.tag) { - .elf => op, - .macho => switch (mnemonic) { - .lea => .{ .mem = Memory.initRip(.none, 0) }, - .mov => .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }, - else => unreachable, - }, - else => |tag| return lower.fail("TODO: bin format '{s}'", .{@tagName(tag)}), - }; - }, - }, +const inst_tags_len = @typeInfo(Mir.Inst.Tag).@"enum".fields.len; +const inst_fixes_len = @typeInfo(Mir.Inst.Fixes).@"enum".fields.len; +/// Lookup table, indexed by `@intFromEnum(inst.tag) * inst_fixes_len + @intFromEnum(fixes)`. +/// The value is the resulting `Mnemonic`, or `null` if the combination is not valid. +const mnemonic_table: [inst_tags_len * inst_fixes_len]?Mnemonic = table: { + @setEvalBranchQuota(80_000); + var table: [inst_tags_len * inst_fixes_len]?Mnemonic = undefined; + for (0..inst_fixes_len) |fixes_i| { + const fixes: Mir.Inst.Fixes = @enumFromInt(fixes_i); + const prefix, const suffix = affix: { + const pattern = if (std.mem.indexOfScalar(u8, @tagName(fixes), ' ')) |i| + @tagName(fixes)[i + 1 ..] + else + @tagName(fixes); + const wildcard_idx = std.mem.indexOfScalar(u8, pattern, '_').?; + break :affix .{ pattern[0..wildcard_idx], pattern[wildcard_idx + 1 ..] }; }; + for (0..inst_tags_len) |inst_tag_i| { + const inst_tag: Mir.Inst.Tag = @enumFromInt(inst_tag_i); + const name = prefix ++ @tagName(inst_tag) ++ suffix; + const idx = inst_tag_i * inst_fixes_len + fixes_i; + table[idx] = if (@hasField(Mnemonic, name)) @field(Mnemonic, name) else null; + } } - lower.result_insts[lower.result_insts_len] = try .new(emit_prefix, emit_mnemonic, emit_ops, lower.target); - lower.result_insts_len += 1; -} + break :table table; +}; fn generic(lower: *Lower, inst: Mir.Inst) Error!void { - @setEvalBranchQuota(2_800); + @setEvalBranchQuota(2_000); const fixes = switch (inst.ops) { .none => inst.data.none.fixes, .inst => inst.data.inst.fixes, @@ -604,28 +475,27 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .rrmi => inst.data.rrix.fixes, .mi_u, .mi_s => inst.data.x.fixes, .m => inst.data.x.fixes, - .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc, .rel => ._, + .nav, .uav, .lazy_sym, .extern_func => ._, else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}), }; - try lower.emit(switch (fixes) { + try lower.encode(switch (fixes) { inline else => |tag| comptime if (std.mem.indexOfScalar(u8, @tagName(tag), ' ')) |space| @field(Prefix, @tagName(tag)[0..space]) else .none, }, mnemonic: { - comptime var max_len = 0; - inline for (@typeInfo(Mnemonic).@"enum".fields) |field| max_len = @max(field.name.len, max_len); - var buf: [max_len]u8 = undefined; - + if (mnemonic_table[@intFromEnum(inst.tag) * inst_fixes_len + @intFromEnum(fixes)]) |mnemonic| { + break :mnemonic mnemonic; + } + // This combination is invalid; make the theoretical mnemonic name and emit an error with it. const fixes_name = @tagName(fixes); const pattern = fixes_name[if (std.mem.indexOfScalar(u8, fixes_name, ' ')) |i| i + " ".len else 0..]; const wildcard_index = std.mem.indexOfScalar(u8, pattern, '_').?; - const parts = .{ pattern[0..wildcard_index], @tagName(inst.tag), pattern[wildcard_index + "_".len ..] }; - const err_msg = "unsupported mnemonic: "; - const mnemonic = std.fmt.bufPrint(&buf, "{s}{s}{s}", parts) catch - return lower.fail(err_msg ++ "'{s}{s}{s}'", parts); - break :mnemonic std.meta.stringToEnum(Mnemonic, mnemonic) orelse - return lower.fail(err_msg ++ "'{s}'", .{mnemonic}); + return lower.fail("unsupported mnemonic: '{s}{s}{s}'", .{ + pattern[0..wildcard_index], + @tagName(inst.tag), + pattern[wildcard_index + "_".len ..], + }); }, switch (inst.ops) { .none => &.{}, .inst => &.{ @@ -738,22 +608,17 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { .{ .mem = lower.mem(2, inst.data.rrix.payload) }, .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) }, }, - .extern_fn_reloc, .rel => &.{ - .{ .imm = lower.reloc(0, .{ .linker_extern_fn = inst.data.reloc.sym_index }, inst.data.reloc.off) }, + .nav => &.{ + .{ .imm = lower.reloc(0, .{ .nav = inst.data.nav.index }, inst.data.nav.off) }, }, - .got_reloc, .direct_reloc, .import_reloc => ops: { - const reg = inst.data.rx.r1; - const extra = lower.mir.extraData(bits.SymbolOffset, inst.data.rx.payload).data; - _ = lower.reloc(1, switch (inst.ops) { - .got_reloc => .{ .linker_got = extra.sym_index }, - .direct_reloc => .{ .linker_direct = extra.sym_index }, - .import_reloc => .{ .linker_import = extra.sym_index }, - else => unreachable, - }, extra.off); - break :ops &.{ - .{ .reg = reg }, - .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, - }; + .uav => &.{ + .{ .imm = lower.reloc(0, .{ .uav = inst.data.uav }, 0) }, + }, + .lazy_sym => &.{ + .{ .imm = lower.reloc(0, .{ .lazy_sym = inst.data.lazy_sym }, 0) }, + }, + .extern_func => &.{ + .{ .imm = lower.reloc(0, .{ .extern_func = inst.data.extern_func }, 0) }, }, else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), }); @@ -773,7 +638,7 @@ fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Er else => unreachable, } }); while (it.next()) |i| { - try lower.emit(.none, mnemonic, &.{.{ + try lower.encode(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i], }}); switch (mnemonic) { @@ -787,7 +652,7 @@ fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Er .push => { var it = inst.data.reg_list.iterator(.{}); while (it.next()) |i| { - try lower.emit(.directive, .@".cfi_rel_offset", &.{ + try lower.encode(.directive, .@".cfi_rel_offset", &.{ .{ .reg = callee_preserved_regs[i] }, .{ .imm = .s(off) }, }); @@ -805,12 +670,14 @@ const page_size: i32 = 1 << 12; const abi = @import("abi.zig"); const assert = std.debug.assert; const bits = @import("bits.zig"); +const codegen = @import("../../codegen.zig"); const encoder = @import("encoder.zig"); const link = @import("../../link.zig"); const std = @import("std"); const Immediate = Instruction.Immediate; const Instruction = encoder.Instruction; +const InternPool = @import("../../InternPool.zig"); const Lower = @This(); const Memory = Instruction.Memory; const Mir = @import("Mir.zig"); @@ -819,3 +686,4 @@ const Zcu = @import("../../Zcu.zig"); const Operand = Instruction.Operand; const Prefix = Instruction.Prefix; const Register = bits.Register; +const Type = @import("../../Type.zig"); diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 8d202e6baeb3..70f809068552 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -9,6 +9,8 @@ instructions: std.MultiArrayList(Inst).Slice, /// The meaning of this data is determined by `Inst.Tag` value. extra: []const u32, +string_bytes: []const u8, +locals: []const Local, table: []const Inst.Index, frame_locs: std.MultiArrayList(FrameLoc).Slice, @@ -1361,9 +1363,6 @@ pub const Inst = struct { /// Immediate (byte), register operands. /// Uses `ri` payload. ir, - /// Relative displacement operand. - /// Uses `reloc` payload. - rel, /// Register, memory operands. /// Uses `rx` payload with extra data of type `Memory`. rm, @@ -1409,21 +1408,18 @@ pub const Inst = struct { /// References another Mir instruction directly. /// Uses `inst` payload. inst, - /// Linker relocation - external function. - /// Uses `reloc` payload. - extern_fn_reloc, - /// Linker relocation - GOT indirection. - /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. - got_reloc, - /// Linker relocation - direct reference. - /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. - direct_reloc, - /// Linker relocation - imports table indirection (binding). - /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. - import_reloc, - /// Linker relocation - threadlocal variable via GOT indirection. - /// Uses `rx` payload with extra data of type `bits.SymbolOffset`. - tlv_reloc, + /// References a nav. + /// Uses `nav` payload. + nav, + /// References an uav. + /// Uses `uav` payload. + uav, + /// References a lazy symbol. + /// Uses `lazy_sym` payload. + lazy_sym, + /// References an external symbol. + /// Uses `extern_func` payload. + extern_func, // Pseudo instructions: @@ -1522,6 +1518,7 @@ pub const Inst = struct { pseudo_cfi_escape_bytes, /// End of prologue + /// Uses `none` payload. pseudo_dbg_prologue_end_none, /// Update debug line with is_stmt register set /// Uses `line_column` payload. @@ -1530,44 +1527,70 @@ pub const Inst = struct { /// Uses `line_column` payload. pseudo_dbg_line_line_column, /// Start of epilogue + /// Uses `none` payload. pseudo_dbg_epilogue_begin_none, /// Start of lexical block + /// Uses `none` payload. pseudo_dbg_enter_block_none, /// End of lexical block + /// Uses `none` payload. pseudo_dbg_leave_block_none, /// Start of inline function + /// Uses `ip_index` payload. pseudo_dbg_enter_inline_func, /// End of inline function + /// Uses `ip_index` payload. pseudo_dbg_leave_inline_func, - /// Local argument or variable. - /// Uses `a` payload. - pseudo_dbg_local_a, - /// Local argument or variable. - /// Uses `ai` payload. - pseudo_dbg_local_ai_s, - /// Local argument or variable. - /// Uses `ai` payload. - pseudo_dbg_local_ai_u, - /// Local argument or variable. - /// Uses `ai` payload with extra data of type `Imm64`. - pseudo_dbg_local_ai_64, - /// Local argument or variable. - /// Uses `as` payload. - pseudo_dbg_local_as, - /// Local argument or variable. - /// Uses `ax` payload with extra data of type `bits.SymbolOffset`. - pseudo_dbg_local_aso, - /// Local argument or variable. - /// Uses `rx` payload with extra data of type `AirOffset`. - pseudo_dbg_local_aro, - /// Local argument or variable. - /// Uses `ax` payload with extra data of type `bits.FrameAddr`. - pseudo_dbg_local_af, - /// Local argument or variable. - /// Uses `ax` payload with extra data of type `Memory`. - pseudo_dbg_local_am, + /// Local argument. + /// Uses `none` payload. + pseudo_dbg_arg_none, + /// Local argument. + /// Uses `i` payload. + pseudo_dbg_arg_i_s, + /// Local argument. + /// Uses `i` payload. + pseudo_dbg_arg_i_u, + /// Local argument. + /// Uses `i64` payload. + pseudo_dbg_arg_i_64, + /// Local argument. + /// Uses `ro` payload. + pseudo_dbg_arg_ro, + /// Local argument. + /// Uses `fa` payload. + pseudo_dbg_arg_fa, + /// Local argument. + /// Uses `x` payload with extra data of type `Memory`. + pseudo_dbg_arg_m, + /// Local argument. + /// Uses `ip_index` payload. + pseudo_dbg_arg_val, /// Remaining arguments are varargs. pseudo_dbg_var_args_none, + /// Local variable. + /// Uses `none` payload. + pseudo_dbg_var_none, + /// Local variable. + /// Uses `i` payload. + pseudo_dbg_var_i_s, + /// Local variable. + /// Uses `i` payload. + pseudo_dbg_var_i_u, + /// Local variable. + /// Uses `i64` payload. + pseudo_dbg_var_i_64, + /// Local variable. + /// Uses `ro` payload. + pseudo_dbg_var_ro, + /// Local variable. + /// Uses `fa` payload. + pseudo_dbg_var_fa, + /// Local variable. + /// Uses `x` payload with extra data of type `Memory`. + pseudo_dbg_var_m, + /// Local variable. + /// Uses `ip_index` payload. + pseudo_dbg_var_val, /// Tombstone /// Emitter should skip this instruction. @@ -1584,6 +1607,7 @@ pub const Inst = struct { inst: Index, }, /// A 32-bit immediate value. + i64: u64, i: struct { fixes: Fixes = ._, i: u32, @@ -1683,31 +1707,18 @@ pub const Inst = struct { return std.mem.sliceAsBytes(mir.extra[bytes.payload..])[0..bytes.len]; } }, - a: struct { - air_inst: Air.Inst.Index, - }, - ai: struct { - air_inst: Air.Inst.Index, - i: u32, - }, - as: struct { - air_inst: Air.Inst.Index, - sym_index: u32, - }, - ax: struct { - air_inst: Air.Inst.Index, - payload: u32, - }, - /// Relocation for the linker where: - /// * `sym_index` is the index of the target - /// * `off` is the offset from the target - reloc: bits.SymbolOffset, + fa: bits.FrameAddr, + ro: bits.RegisterOffset, + nav: bits.NavOffset, + uav: InternPool.Key.Ptr.BaseAddr.Uav, + lazy_sym: link.File.LazySymbol, + extern_func: Mir.NullTerminatedString, /// Debug line and column position line_column: struct { line: u32, column: u32, }, - func: InternPool.Index, + ip_index: InternPool.Index, /// Register list reg_list: RegisterList, }; @@ -1760,13 +1771,11 @@ pub const Inst = struct { } }; -pub const AirOffset = struct { air_inst: Air.Inst.Index, off: i32 }; - /// Used in conjunction with payload to transfer a list of used registers in a compact manner. pub const RegisterList = struct { bitset: BitSet, - const BitSet = IntegerBitSet(32); + const BitSet = std.bit_set.IntegerBitSet(32); const Self = @This(); pub const empty: RegisterList = .{ .bitset = .initEmpty() }; @@ -1805,6 +1814,22 @@ pub const RegisterList = struct { } }; +pub const NullTerminatedString = enum(u32) { + none = std.math.maxInt(u32), + _, + + pub fn toSlice(nts: NullTerminatedString, mir: *const Mir) ?[:0]const u8 { + if (nts == .none) return null; + const string_bytes = mir.string_bytes[@intFromEnum(nts)..]; + return string_bytes[0..std.mem.indexOfScalar(u8, string_bytes, 0).? :0]; + } +}; + +pub const Local = struct { + name: NullTerminatedString, + type: InternPool.Index, +}; + pub const Imm32 = struct { imm: u32, }; @@ -1840,11 +1865,10 @@ pub const Memory = struct { size: bits.Memory.Size, index: Register, scale: bits.Memory.Scale, - _: u14 = undefined, + _: u13 = undefined, }; pub fn encode(mem: bits.Memory) Memory { - assert(mem.base != .reloc or mem.mod != .off); return .{ .info = .{ .base = mem.base, @@ -1866,17 +1890,27 @@ pub const Memory = struct { .none, .table => undefined, .reg => |reg| @intFromEnum(reg), .frame => |frame_index| @intFromEnum(frame_index), - .reloc, .pcrel => |sym_index| sym_index, .rip_inst => |inst_index| inst_index, + .nav => |nav| @intFromEnum(nav), + .uav => |uav| @intFromEnum(uav.val), + .lazy_sym => |lazy_sym| @intFromEnum(lazy_sym.ty), + .extern_func => |extern_func| @intFromEnum(extern_func), }, .off = switch (mem.mod) { .rm => |rm| @bitCast(rm.disp), .off => |off| @truncate(off), }, - .extra = if (mem.mod == .off) - @intCast(mem.mod.off >> 32) - else - undefined, + .extra = switch (mem.mod) { + .rm => switch (mem.base) { + else => undefined, + .uav => |uav| @intFromEnum(uav.orig_ty), + .lazy_sym => |lazy_sym| @intFromEnum(lazy_sym.kind), + }, + .off => switch (mem.base) { + .reg => @intCast(mem.mod.off >> 32), + else => unreachable, + }, + }, }; } @@ -1894,9 +1928,11 @@ pub const Memory = struct { .reg => .{ .reg = @enumFromInt(mem.base) }, .frame => .{ .frame = @enumFromInt(mem.base) }, .table => .table, - .reloc => .{ .reloc = mem.base }, - .pcrel => .{ .pcrel = mem.base }, .rip_inst => .{ .rip_inst = mem.base }, + .nav => .{ .nav = @enumFromInt(mem.base) }, + .uav => .{ .uav = .{ .val = @enumFromInt(mem.base), .orig_ty = @enumFromInt(mem.extra) } }, + .lazy_sym => .{ .lazy_sym = .{ .kind = @enumFromInt(mem.extra), .ty = @enumFromInt(mem.base) } }, + .extern_func => .{ .extern_func = @enumFromInt(mem.base) }, }, .scale_index = switch (mem.info.index) { .none => null, @@ -1924,11 +1960,132 @@ pub const Memory = struct { pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { mir.instructions.deinit(gpa); gpa.free(mir.extra); + gpa.free(mir.string_bytes); + gpa.free(mir.locals); gpa.free(mir.table); mir.frame_locs.deinit(gpa); mir.* = undefined; } +pub fn emit( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) codegen.CodeGenError!void { + const zcu = pt.zcu; + const comp = zcu.comp; + const gpa = comp.gpa; + const func = zcu.funcInfo(func_index); + const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?; + const nav = func.owner_nav; + const mod = zcu.navFileScope(nav).mod.?; + var e: Emit = .{ + .lower = .{ + .target = &mod.resolved_target.result, + .allocator = gpa, + .mir = mir, + .cc = fn_info.cc, + .src_loc = src_loc, + }, + .bin_file = lf, + .pt = pt, + .pic = mod.pic, + .atom_index = sym: { + if (lf.cast(.elf)) |ef| break :sym try ef.zigObjectPtr().?.getOrCreateMetadataForNav(zcu, nav); + if (lf.cast(.macho)) |mf| break :sym try mf.getZigObject().?.getOrCreateMetadataForNav(mf, nav); + if (lf.cast(.coff)) |cf| { + const atom = try cf.getOrCreateAtomForNav(nav); + break :sym cf.getAtom(atom).getSymbolIndex().?; + } + if (lf.cast(.plan9)) |p9f| break :sym try p9f.seeNav(pt, nav); + unreachable; + }, + .debug_output = debug_output, + .code = code, + + .prev_di_loc = .{ + .line = func.lbrace_line, + .column = func.lbrace_column, + .is_stmt = switch (debug_output) { + .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt, + .plan9 => undefined, + .none => undefined, + }, + }, + .prev_di_pc = 0, + + .code_offset_mapping = .empty, + .relocs = .empty, + .table_relocs = .empty, + }; + defer e.deinit(); + e.emitMir() catch |err| switch (err) { + error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?), + error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}), + else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}), + }; +} + +pub fn emitLazy( + mir: Mir, + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + lazy_sym: link.File.LazySymbol, + code: *std.ArrayListUnmanaged(u8), + debug_output: link.File.DebugInfoOutput, +) codegen.CodeGenError!void { + const zcu = pt.zcu; + const comp = zcu.comp; + const gpa = comp.gpa; + const mod = comp.root_mod; + var e: Emit = .{ + .lower = .{ + .target = &mod.resolved_target.result, + .allocator = gpa, + .mir = mir, + .cc = .auto, + .src_loc = src_loc, + }, + .bin_file = lf, + .pt = pt, + .pic = mod.pic, + .atom_index = sym: { + if (lf.cast(.elf)) |ef| break :sym ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_sym) catch |err| + return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); + if (lf.cast(.macho)) |mf| break :sym mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_sym) catch |err| + return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); + if (lf.cast(.coff)) |cf| { + const atom = cf.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| + return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); + break :sym cf.getAtom(atom).getSymbolIndex().?; + } + if (lf.cast(.plan9)) |p9f| break :sym p9f.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| + return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); + unreachable; + }, + .debug_output = debug_output, + .code = code, + + .prev_di_loc = undefined, + .prev_di_pc = undefined, + + .code_offset_mapping = .empty, + .relocs = .empty, + .table_relocs = .empty, + }; + defer e.deinit(); + e.emitMir() catch |err| switch (err) { + error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?), + error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}), + else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}), + }; +} + pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end: u32 } { const fields = std.meta.fields(T); var i: u32 = index; @@ -1937,7 +2094,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end: @field(result, field.name) = switch (field.type) { u32 => mir.extra[i], i32, Memory.Info => @bitCast(mir.extra[i]), - bits.FrameIndex, Air.Inst.Index => @enumFromInt(mir.extra[i]), + bits.FrameIndex => @enumFromInt(mir.extra[i]), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), }; i += 1; @@ -1958,9 +2115,10 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse return .{ .reg = frame_loc.base, .off = frame_loc.disp + frame_addr.off }; } -pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory { +pub fn resolveMemoryExtra(mir: Mir, payload: u32) Memory { + const mem = mir.extraData(Mir.Memory, payload).data; return switch (mem.info.base) { - .none, .reg, .table, .reloc, .pcrel, .rip_inst => mem, + .none, .reg, .table, .rip_inst, .nav, .uav, .lazy_sym, .extern_func => mem, .frame => if (mir.frame_locs.len > 0) .{ .info = .{ .base = .reg, @@ -1982,8 +2140,10 @@ const builtin = @import("builtin"); const encoder = @import("encoder.zig"); const std = @import("std"); -const Air = @import("../../Air.zig"); -const IntegerBitSet = std.bit_set.IntegerBitSet; const InternPool = @import("../../InternPool.zig"); const Mir = @This(); const Register = bits.Register; +const Emit = @import("Emit.zig"); +const codegen = @import("../../codegen.zig"); +const link = @import("../../link.zig"); +const Zcu = @import("../../Zcu.zig"); diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig index 63b5d4b238c2..c854af91d2fb 100644 --- a/src/arch/x86_64/bits.zig +++ b/src/arch/x86_64/bits.zig @@ -4,6 +4,8 @@ const expect = std.testing.expect; const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; +const InternPool = @import("../../InternPool.zig"); +const link = @import("../../link.zig"); const Mir = @import("Mir.zig"); /// EFLAGS condition codes @@ -684,8 +686,6 @@ test "Register id - different classes" { try expect(Register.xmm0.id() == Register.ymm0.id()); try expect(Register.xmm0.id() != Register.mm0.id()); try expect(Register.mm0.id() != Register.st0.id()); - - try expect(Register.es.id() == 0b110000); } test "Register enc - different classes" { @@ -750,20 +750,22 @@ pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; pub const RegisterOffset = struct { reg: Register, off: i32 = 0 }; -pub const SymbolOffset = struct { sym_index: u32, off: i32 = 0 }; +pub const NavOffset = struct { index: InternPool.Nav.Index, off: i32 = 0 }; pub const Memory = struct { base: Base = .none, mod: Mod = .{ .rm = .{} }, - pub const Base = union(enum(u3)) { + pub const Base = union(enum(u4)) { none, reg: Register, frame: FrameIndex, table, - reloc: u32, - pcrel: u32, rip_inst: Mir.Inst.Index, + nav: InternPool.Nav.Index, + uav: InternPool.Key.Ptr.BaseAddr.Uav, + lazy_sym: link.File.LazySymbol, + extern_func: Mir.NullTerminatedString, pub const Tag = @typeInfo(Base).@"union".tag_type.?; }; @@ -899,7 +901,10 @@ pub const Memory = struct { pub const Immediate = union(enum) { signed: i32, unsigned: u64, - reloc: SymbolOffset, + nav: NavOffset, + uav: InternPool.Key.Ptr.BaseAddr.Uav, + lazy_sym: link.File.LazySymbol, + extern_func: Mir.NullTerminatedString, pub fn u(x: u64) Immediate { return .{ .unsigned = x }; @@ -909,10 +914,6 @@ pub const Immediate = union(enum) { return .{ .signed = x }; } - pub fn rel(sym_off: SymbolOffset) Immediate { - return .{ .reloc = sym_off }; - } - pub fn format( imm: Immediate, comptime _: []const u8, @@ -921,7 +922,10 @@ pub const Immediate = union(enum) { ) @TypeOf(writer).Error!void { switch (imm) { inline else => |int| try writer.print("{d}", .{int}), - .reloc => |sym_off| try writer.print("Symbol({[sym_index]d}) + {[off]d}", sym_off), + .nav => |nav_off| try writer.print("Nav({d}) + {d}", .{ @intFromEnum(nav_off.nav), nav_off.off }), + .uav => |uav| try writer.print("Uav({d})", .{@intFromEnum(uav.val)}), + .lazy_sym => |lazy_sym| try writer.print("LazySym({s}, {d})", .{ @tagName(lazy_sym.kind), @intFromEnum(lazy_sym.ty) }), + .extern_func => |extern_func| try writer.print("ExternFunc({d})", .{@intFromEnum(extern_func)}), } } }; diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index cb1272fba0a4..8d07dce83a8b 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -138,7 +138,7 @@ pub const Instruction = struct { .moffs => true, .rip => false, .sib => |s| switch (s.base) { - .none, .frame, .table, .reloc, .pcrel, .rip_inst => false, + .none, .frame, .table, .rip_inst, .nav, .uav, .lazy_sym, .extern_func => false, .reg => |reg| reg.isClass(.segment), }, }; @@ -211,7 +211,7 @@ pub const Instruction = struct { .none, .imm => 0b00, .reg => |reg| @truncate(reg.enc() >> 3), .mem => |mem| switch (mem.base()) { - .none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended + .none, .frame, .table, .rip_inst, .nav, .uav, .lazy_sym, .extern_func => 0b00, // rsp, rbp, and rip are not extended .reg => |reg| @truncate(reg.enc() >> 3), }, .bytes => unreachable, @@ -281,9 +281,14 @@ pub const Instruction = struct { .reg => |reg| try writer.print("{s}", .{@tagName(reg)}), .frame => |frame_index| try writer.print("{}", .{frame_index}), .table => try writer.print("Table", .{}), - .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}), - .pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}), .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}), + .nav => |nav| try writer.print("Nav({d})", .{@intFromEnum(nav)}), + .uav => |uav| try writer.print("Uav({d})", .{@intFromEnum(uav.val)}), + .lazy_sym => |lazy_sym| try writer.print("LazySym({s}, {d})", .{ + @tagName(lazy_sym.kind), + @intFromEnum(lazy_sym.ty), + }), + .extern_func => |extern_func| try writer.print("ExternFunc({d})", .{@intFromEnum(extern_func)}), } if (mem.scaleIndex()) |si| { if (any) try writer.writeAll(" + "); @@ -718,11 +723,11 @@ pub const Instruction = struct { try encoder.modRm_indirectDisp32(operand_enc, 0); try encoder.disp32(undefined); } else return error.CannotEncode, - .reloc => if (@TypeOf(encoder).options.allow_symbols) { + .nav, .uav, .lazy_sym, .extern_func => if (@TypeOf(encoder).options.allow_symbols) { try encoder.modRm_indirectDisp32(operand_enc, 0); try encoder.disp32(undefined); } else return error.CannotEncode, - .pcrel, .rip_inst => { + .rip_inst => { try encoder.modRm_RIPDisp32(operand_enc); try encoder.disp32(sib.disp); }, diff --git a/src/codegen.zig b/src/codegen.zig index a2de3e2d01de..9cc27b55ba6a 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -85,13 +85,99 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co } } +/// Every code generation backend has a different MIR representation. However, we want to pass +/// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a +/// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`. +pub const AnyMir = union { + aarch64: @import("arch/aarch64/Mir.zig"), + arm: @import("arch/arm/Mir.zig"), + powerpc: noreturn, //@import("arch/powerpc/Mir.zig"), + riscv64: @import("arch/riscv64/Mir.zig"), + sparc64: @import("arch/sparc64/Mir.zig"), + x86_64: @import("arch/x86_64/Mir.zig"), + wasm: @import("arch/wasm/Mir.zig"), + c: @import("codegen/c.zig").Mir, + + pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 { + return switch (backend) { + .stage2_aarch64 => "aarch64", + .stage2_arm => "arm", + .stage2_powerpc => "powerpc", + .stage2_riscv64 => "riscv64", + .stage2_sparc64 => "sparc64", + .stage2_x86_64 => "x86_64", + .stage2_wasm => "wasm", + .stage2_c => "c", + else => unreachable, + }; + } + + pub fn deinit(mir: *AnyMir, zcu: *const Zcu) void { + const gpa = zcu.gpa; + const backend = target_util.zigBackend(zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); + switch (backend) { + else => unreachable, + inline .stage2_aarch64, + .stage2_arm, + .stage2_powerpc, + .stage2_riscv64, + .stage2_sparc64, + .stage2_x86_64, + .stage2_wasm, + .stage2_c, + => |backend_ct| @field(mir, tag(backend_ct)).deinit(gpa), + } + } +}; + +/// Runs code generation for a function. This process converts the `Air` emitted by `Sema`, +/// alongside annotated `Liveness` data, to machine code in the form of MIR (see `AnyMir`). +/// +/// This is supposed to be a "pure" process, but some backends are currently buggy; see +/// `Zcu.Feature.separate_thread` for details. pub fn generateFunction( lf: *link.File, pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + air: *const Air, + liveness: *const Air.Liveness, +) CodeGenError!AnyMir { + const zcu = pt.zcu; + const func = zcu.funcInfo(func_index); + const target = zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; + switch (target_util.zigBackend(target, false)) { + else => unreachable, + inline .stage2_aarch64, + .stage2_arm, + .stage2_powerpc, + .stage2_riscv64, + .stage2_sparc64, + .stage2_x86_64, + .stage2_wasm, + .stage2_c, + => |backend| { + dev.check(devFeatureForBackend(backend)); + const CodeGen = importBackend(backend); + const mir = try CodeGen.generate(lf, pt, src_loc, func_index, air, liveness); + return @unionInit(AnyMir, AnyMir.tag(backend), mir); + }, + } +} + +/// Converts the MIR returned by `generateFunction` to finalized machine code to be placed in +/// the output binary. This is called from linker implementations, and may query linker state. +/// +/// This function is not called for the C backend, as `link.C` directly understands its MIR. +/// +/// The `air` parameter is not supposed to exist, but some backends are currently buggy; see +/// `Zcu.Feature.separate_thread` for details. +pub fn emitFunction( + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + any_mir: *const AnyMir, code: *std.ArrayListUnmanaged(u8), debug_output: link.File.DebugInfoOutput, ) CodeGenError!void { @@ -108,7 +194,8 @@ pub fn generateFunction( .stage2_x86_64, => |backend| { dev.check(devFeatureForBackend(backend)); - return importBackend(backend).generate(lf, pt, src_loc, func_index, air, liveness, code, debug_output); + const mir = &@field(any_mir, AnyMir.tag(backend)); + return mir.emit(lf, pt, src_loc, func_index, code, debug_output); }, } } @@ -695,7 +782,6 @@ fn lowerUavRef( const comp = lf.comp; const target = &comp.root_mod.resolved_target.result; const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8); - const is_obj = comp.config.output_mode == .Obj; const uav_val = uav.val; const uav_ty = Type.fromInterned(ip.typeOf(uav_val)); const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn"; @@ -715,21 +801,7 @@ fn lowerUavRef( dev.check(link.File.Tag.wasm.devFeature()); const wasm = lf.cast(.wasm).?; assert(reloc_parent == .none); - if (is_obj) { - try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), - .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav.val) }, - .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, - .addend = @intCast(offset), - }); - } else { - try wasm.uav_fixups.ensureUnusedCapacity(gpa, 1); - wasm.uav_fixups.appendAssumeCapacity(.{ - .uavs_exe_index = try wasm.refUavExe(uav.val, uav.orig_ty), - .offset = @intCast(code.items.len), - .addend = @intCast(offset), - }); - } + try wasm.addUavReloc(code.items.len, uav.val, uav.orig_ty, @intCast(offset)); code.appendNTimesAssumeCapacity(0, ptr_width_bytes); return; }, @@ -879,73 +951,39 @@ pub const GenResult = union(enum) { }; }; -fn genNavRef( +pub fn genNavRef( lf: *link.File, pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, - val: Value, nav_index: InternPool.Nav.Index, target: std.Target, ) CodeGenError!GenResult { const zcu = pt.zcu; const ip = &zcu.intern_pool; - const ty = val.typeOf(zcu); - log.debug("genNavRef: val = {}", .{val.fmtValue(pt)}); - - if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { - const imm: u64 = switch (@divExact(target.ptrBitWidth(), 8)) { - 1 => 0xaa, - 2 => 0xaaaa, - 4 => 0xaaaaaaaa, - 8 => 0xaaaaaaaaaaaaaaaa, - else => unreachable, - }; - return .{ .mcv = .{ .immediate = imm } }; - } - - const comp = lf.comp; - const gpa = comp.gpa; - - // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? - if (ty.castPtrToFn(zcu)) |fn_ty| { - if (zcu.typeToFunc(fn_ty).?.is_generic) { - return .{ .mcv = .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? } }; - } - } else if (ty.zigTypeTag(zcu) == .pointer) { - const elem_ty = ty.elemType2(zcu); - if (!elem_ty.hasRuntimeBits(zcu)) { - return .{ .mcv = .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? } }; - } - } - const nav = ip.getNav(nav_index); - assert(!nav.isThreadlocal(ip)); + log.debug("genNavRef({})", .{nav.fqn.fmt(ip)}); - const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e| - .{ e.lib_name, e.linkage, e.visibility } + const lib_name, const linkage, const is_threadlocal = if (nav.getExtern(ip)) |e| + .{ e.lib_name, e.linkage, e.is_threadlocal and zcu.comp.config.any_non_single_threaded } else - .{ .none, .internal, .default }; - - const name = nav.name; + .{ .none, .internal, false }; if (lf.cast(.elf)) |elf_file| { const zo = elf_file.zigObjectPtr().?; switch (linkage) { .internal => { const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index); + if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true; return .{ .mcv = .{ .lea_symbol = sym_index } }; }, .strong, .weak => { - const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); + const sym_index = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip)); switch (linkage) { .internal => unreachable, .strong => {}, .weak => zo.symbol(sym_index).flags.weak = true, .link_once => unreachable, } - switch (visibility) { - .default => zo.symbol(sym_index).flags.is_extern_ptr = true, - .hidden, .protected => {}, - } + if (is_threadlocal) zo.symbol(sym_index).flags.is_tls = true; return .{ .mcv = .{ .lea_symbol = sym_index } }; }, .link_once => unreachable, @@ -955,21 +993,18 @@ fn genNavRef( switch (linkage) { .internal => { const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index); - const sym = zo.symbols.items[sym_index]; - return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } }; + if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true; + return .{ .mcv = .{ .lea_symbol = sym_index } }; }, .strong, .weak => { - const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); + const sym_index = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip)); switch (linkage) { .internal => unreachable, .strong => {}, .weak => zo.symbols.items[sym_index].flags.weak = true, .link_once => unreachable, } - switch (visibility) { - .default => zo.symbols.items[sym_index].flags.is_extern_ptr = true, - .hidden, .protected => {}, - } + if (is_threadlocal) zo.symbols.items[sym_index].flags.tlv = true; return .{ .mcv = .{ .lea_symbol = sym_index } }; }, .link_once => unreachable, @@ -980,12 +1015,12 @@ fn genNavRef( .internal => { const atom_index = try coff_file.getOrCreateAtomForNav(nav_index); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; - return .{ .mcv = .{ .load_got = sym_index } }; + return .{ .mcv = .{ .lea_symbol = sym_index } }; }, .strong, .weak => { - const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); - try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT - return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } }; + const global_index = try coff_file.getGlobalSymbol(nav.name.toSlice(ip), lib_name.toSlice(ip)); + try coff_file.need_got_table.put(zcu.gpa, global_index, {}); // needs GOT + return .{ .mcv = .{ .lea_symbol = global_index } }; }, .link_once => unreachable, } @@ -994,11 +1029,12 @@ fn genNavRef( const atom = p9.getAtom(atom_index); return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } }; } else { - const msg = try ErrorMsg.create(gpa, src_loc, "TODO genNavRef for target {}", .{target}); + const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target}); return .{ .fail = msg }; } } +/// deprecated legacy code path pub fn genTypedValue( lf: *link.File, pt: Zcu.PerThread, @@ -1006,45 +1042,96 @@ pub fn genTypedValue( val: Value, target: std.Target, ) CodeGenError!GenResult { + return switch (try lowerValue(pt, val, &target)) { + .none => .{ .mcv = .none }, + .undef => .{ .mcv = .undef }, + .immediate => |imm| .{ .mcv = .{ .immediate = imm } }, + .lea_nav => |nav| genNavRef(lf, pt, src_loc, nav, target), + .lea_uav => |uav| switch (try lf.lowerUav( + pt, + uav.val, + Type.fromInterned(uav.orig_ty).ptrAlignment(pt.zcu), + src_loc, + )) { + .mcv => |mcv| .{ .mcv = switch (mcv) { + else => unreachable, + .load_direct => |sym_index| .{ .lea_direct = sym_index }, + .load_symbol => |sym_index| .{ .lea_symbol = sym_index }, + } }, + .fail => |em| .{ .fail = em }, + }, + .load_uav => |uav| lf.lowerUav( + pt, + uav.val, + Type.fromInterned(uav.orig_ty).ptrAlignment(pt.zcu), + src_loc, + ), + }; +} + +const LowerResult = union(enum) { + none, + undef, + /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets + /// such as ARM, the immediate will never exceed 32-bits. + immediate: u64, + lea_nav: InternPool.Nav.Index, + lea_uav: InternPool.Key.Ptr.BaseAddr.Uav, + load_uav: InternPool.Key.Ptr.BaseAddr.Uav, +}; + +pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allocator.Error!LowerResult { const zcu = pt.zcu; const ip = &zcu.intern_pool; const ty = val.typeOf(zcu); - log.debug("genTypedValue: val = {}", .{val.fmtValue(pt)}); + log.debug("lowerValue(@as({}, {}))", .{ ty.fmt(pt), val.fmtValue(pt) }); - if (val.isUndef(zcu)) return .{ .mcv = .undef }; + if (val.isUndef(zcu)) return .undef; switch (ty.zigTypeTag(zcu)) { - .void => return .{ .mcv = .none }, + .void => return .none, .pointer => switch (ty.ptrSize(zcu)) { .slice => {}, else => switch (val.toIntern()) { .null_value => { - return .{ .mcv = .{ .immediate = 0 } }; + return .{ .immediate = 0 }; }, else => switch (ip.indexToKey(val.toIntern())) { .int => { - return .{ .mcv = .{ .immediate = val.toUnsignedInt(zcu) } }; + return .{ .immediate = val.toUnsignedInt(zcu) }; }, .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) { - .nav => |nav| return genNavRef(lf, pt, src_loc, val, nav, target), - .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).hasRuntimeBits(zcu)) - return switch (try lf.lowerUav( - pt, - uav.val, - Type.fromInterned(uav.orig_ty).ptrAlignment(zcu), - src_loc, - )) { - .mcv => |mcv| return .{ .mcv = switch (mcv) { - .load_direct => |sym_index| .{ .lea_direct = sym_index }, - .load_symbol => |sym_index| .{ .lea_symbol = sym_index }, + .nav => |nav| { + if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { + const imm: u64 = switch (@divExact(target.ptrBitWidth(), 8)) { + 1 => 0xaa, + 2 => 0xaaaa, + 4 => 0xaaaaaaaa, + 8 => 0xaaaaaaaaaaaaaaaa, else => unreachable, - } }, - .fail => |em| return .{ .fail = em }, + }; + return .{ .immediate = imm }; } + + if (ty.castPtrToFn(zcu)) |fn_ty| { + if (zcu.typeToFunc(fn_ty).?.is_generic) { + return .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? }; + } + } else if (ty.zigTypeTag(zcu) == .pointer) { + const elem_ty = ty.elemType2(zcu); + if (!elem_ty.hasRuntimeBits(zcu)) { + return .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? }; + } + } + + return .{ .lea_nav = nav }; + }, + .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).hasRuntimeBits(zcu)) + return .{ .lea_uav = uav } else - return .{ .mcv = .{ .immediate = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu) - .forward(@intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() | 1)) / 3)) } }, + return .{ .immediate = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu) + .forward(@intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() | 1)) / 3)) }, else => {}, }, else => {}, @@ -1058,39 +1145,35 @@ pub fn genTypedValue( .signed => @bitCast(val.toSignedInt(zcu)), .unsigned => val.toUnsignedInt(zcu), }; - return .{ .mcv = .{ .immediate = unsigned } }; + return .{ .immediate = unsigned }; } }, .bool => { - return .{ .mcv = .{ .immediate = @intFromBool(val.toBool()) } }; + return .{ .immediate = @intFromBool(val.toBool()) }; }, .optional => { if (ty.isPtrLikeOptional(zcu)) { - return genTypedValue( - lf, + return lowerValue( pt, - src_loc, - val.optionalValue(zcu) orelse return .{ .mcv = .{ .immediate = 0 } }, + val.optionalValue(zcu) orelse return .{ .immediate = 0 }, target, ); } else if (ty.abiSize(zcu) == 1) { - return .{ .mcv = .{ .immediate = @intFromBool(!val.isNull(zcu)) } }; + return .{ .immediate = @intFromBool(!val.isNull(zcu)) }; } }, .@"enum" => { const enum_tag = ip.indexToKey(val.toIntern()).enum_tag; - return genTypedValue( - lf, + return lowerValue( pt, - src_loc, Value.fromInterned(enum_tag.int), target, ); }, .error_set => { const err_name = ip.indexToKey(val.toIntern()).err.name; - const error_index = try pt.getErrorValue(err_name); - return .{ .mcv = .{ .immediate = error_index } }; + const error_index = ip.getErrorValueIfExists(err_name).?; + return .{ .immediate = error_index }; }, .error_union => { const err_type = ty.errorUnionSet(zcu); @@ -1099,20 +1182,16 @@ pub fn genTypedValue( // We use the error type directly as the type. const err_int_ty = try pt.errorIntType(); switch (ip.indexToKey(val.toIntern()).error_union.val) { - .err_name => |err_name| return genTypedValue( - lf, + .err_name => |err_name| return lowerValue( pt, - src_loc, Value.fromInterned(try pt.intern(.{ .err = .{ .ty = err_type.toIntern(), .name = err_name, } })), target, ), - .payload => return genTypedValue( - lf, + .payload => return lowerValue( pt, - src_loc, try pt.intValue(err_int_ty, 0), target, ), @@ -1132,7 +1211,10 @@ pub fn genTypedValue( else => {}, } - return lf.lowerUav(pt, val.toIntern(), .none, src_loc); + return .{ .load_uav = .{ + .val = val.toIntern(), + .orig_ty = (try pt.singleConstPtrType(ty)).toIntern(), + } }; } pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Zcu) u64 { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 3b8ab5298287..f4952d4a5807 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const assert = std.debug.assert; const mem = std.mem; const log = std.log.scoped(.c); +const Allocator = mem.Allocator; const dev = @import("../dev.zig"); const link = @import("../link.zig"); @@ -30,6 +31,35 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features { }) else null; // we don't currently ask zig1 to use safe optimization modes } +/// For most backends, MIR is basically a sequence of machine code instructions, perhaps with some +/// "pseudo instructions" thrown in. For the C backend, it is instead the generated C code for a +/// single function. We also need to track some information to get merged into the global `link.C` +/// state, including: +/// * The UAVs used, so declarations can be emitted in `flush` +/// * The types used, so declarations can be emitted in `flush` +/// * The lazy functions used, so definitions can be emitted in `flush` +pub const Mir = struct { + /// This map contains all the UAVs we saw generating this function. + /// `link.C` will merge them into its `uavs`/`aligned_uavs` fields. + /// Key is the value of the UAV; value is the UAV's alignment, or + /// `.none` for natural alignment. The specified alignment is never + /// less than the natural alignment. + uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), + // These remaining fields are essentially just an owned version of `link.C.AvBlock`. + code: []u8, + fwd_decl: []u8, + ctype_pool: CType.Pool, + lazy_fns: LazyFnMap, + + pub fn deinit(mir: *Mir, gpa: Allocator) void { + mir.uavs.deinit(gpa); + gpa.free(mir.code); + gpa.free(mir.fwd_decl); + mir.ctype_pool.deinit(gpa); + mir.lazy_fns.deinit(gpa); + } +}; + pub const CType = @import("c/Type.zig"); pub const CValue = union(enum) { @@ -671,7 +701,7 @@ pub const Object = struct { /// This data is available both when outputting .c code and when outputting an .h file. pub const DeclGen = struct { - gpa: mem.Allocator, + gpa: Allocator, pt: Zcu.PerThread, mod: *Module, pass: Pass, @@ -682,10 +712,12 @@ pub const DeclGen = struct { error_msg: ?*Zcu.ErrorMsg, ctype_pool: CType.Pool, scratch: std.ArrayListUnmanaged(u32), - /// Keeps track of anonymous decls that need to be rendered before this - /// (named) Decl in the output C code. - uav_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.AvBlock), - aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), + /// This map contains all the UAVs we saw generating this function. + /// `link.C` will merge them into its `uavs`/`aligned_uavs` fields. + /// Key is the value of the UAV; value is the UAV's alignment, or + /// `.none` for natural alignment. The specified alignment is never + /// less than the natural alignment. + uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), pub const Pass = union(enum) { nav: InternPool.Nav.Index, @@ -753,21 +785,17 @@ pub const DeclGen = struct { // Indicate that the anon decl should be rendered to the output so that // our reference above is not undefined. const ptr_type = ip.indexToKey(uav.orig_ty).ptr_type; - const gop = try dg.uav_deps.getOrPut(dg.gpa, uav.val); - if (!gop.found_existing) gop.value_ptr.* = .{}; - - // Only insert an alignment entry if the alignment is greater than ABI - // alignment. If there is already an entry, keep the greater alignment. - const explicit_alignment = ptr_type.flags.alignment; - if (explicit_alignment != .none) { - const abi_alignment = Type.fromInterned(ptr_type.child).abiAlignment(zcu); - if (explicit_alignment.order(abi_alignment).compare(.gt)) { - const aligned_gop = try dg.aligned_uavs.getOrPut(dg.gpa, uav.val); - aligned_gop.value_ptr.* = if (aligned_gop.found_existing) - aligned_gop.value_ptr.maxStrict(explicit_alignment) - else - explicit_alignment; - } + const gop = try dg.uavs.getOrPut(dg.gpa, uav.val); + if (!gop.found_existing) gop.value_ptr.* = .none; + // If there is an explicit alignment, greater than the current one, use it. + // Note that we intentionally start at `.none`, so `gop.value_ptr.*` is never + // underaligned, so we don't need to worry about the `.none` case here. + if (ptr_type.flags.alignment != .none) { + // Resolve the current alignment so we can choose the bigger one. + const cur_alignment: Alignment = if (gop.value_ptr.* == .none) abi: { + break :abi Type.fromInterned(ptr_type.child).abiAlignment(zcu); + } else gop.value_ptr.*; + gop.value_ptr.* = cur_alignment.maxStrict(ptr_type.flags.alignment); } } @@ -2895,7 +2923,79 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn } } -pub fn genFunc(f: *Function) !void { +pub fn generate( + lf: *link.File, + pt: Zcu.PerThread, + src_loc: Zcu.LazySrcLoc, + func_index: InternPool.Index, + air: *const Air, + liveness: *const Air.Liveness, +) @import("../codegen.zig").CodeGenError!Mir { + const zcu = pt.zcu; + const gpa = zcu.gpa; + + _ = src_loc; + assert(lf.tag == .c); + + const func = zcu.funcInfo(func_index); + + var function: Function = .{ + .value_map = .init(gpa), + .air = air.*, + .liveness = liveness.*, + .func_index = func_index, + .object = .{ + .dg = .{ + .gpa = gpa, + .pt = pt, + .mod = zcu.navFileScope(func.owner_nav).mod.?, + .error_msg = null, + .pass = .{ .nav = func.owner_nav }, + .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked, + .expected_block = null, + .fwd_decl = .init(gpa), + .ctype_pool = .empty, + .scratch = .empty, + .uavs = .empty, + }, + .code = .init(gpa), + .indent_writer = undefined, // set later so we can get a pointer to object.code + }, + .lazy_fns = .empty, + }; + defer { + function.object.code.deinit(); + function.object.dg.fwd_decl.deinit(); + function.object.dg.ctype_pool.deinit(gpa); + function.object.dg.scratch.deinit(gpa); + function.object.dg.uavs.deinit(gpa); + function.deinit(); + } + try function.object.dg.ctype_pool.init(gpa); + function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; + + genFunc(&function) catch |err| switch (err) { + error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?), + error.OutOfMemory => |e| return e, + }; + + var mir: Mir = .{ + .uavs = .empty, + .code = &.{}, + .fwd_decl = &.{}, + .ctype_pool = .empty, + .lazy_fns = .empty, + }; + errdefer mir.deinit(gpa); + mir.uavs = function.object.dg.uavs.move(); + mir.code = try function.object.code.toOwnedSlice(); + mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice(); + mir.ctype_pool = function.object.dg.ctype_pool.move(); + mir.lazy_fns = function.lazy_fns.move(); + return mir; +} + +fn genFunc(f: *Function) !void { const tracy = trace(@src()); defer tracy.end(); @@ -8482,7 +8582,7 @@ fn iterateBigTomb(f: *Function, inst: Air.Inst.Index) BigTomb { /// A naive clone of this map would create copies of the ArrayList which is /// stored in the values. This function additionally clones the values. -fn cloneFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) !LocalsMap { +fn cloneFreeLocalsMap(gpa: Allocator, map: *LocalsMap) !LocalsMap { var cloned = try map.clone(gpa); const values = cloned.values(); var i: usize = 0; @@ -8499,7 +8599,7 @@ fn cloneFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) !LocalsMap { return cloned; } -fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void { +fn deinitFreeLocalsMap(gpa: Allocator, map: *LocalsMap) void { for (map.values()) |*value| { value.deinit(gpa); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3fc6250d3f32..658764ba3cf7 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1121,8 +1121,8 @@ pub const Object = struct { o: *Object, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + air: *const Air, + liveness: *const Air.Liveness, ) !void { assert(std.meta.eql(pt, o.pt)); const zcu = pt.zcu; @@ -1479,8 +1479,8 @@ pub const Object = struct { var fg: FuncGen = .{ .gpa = gpa, - .air = air, - .liveness = liveness, + .air = air.*, + .liveness = liveness.*, .ng = &ng, .wip = wip, .is_naked = fn_info.cc == .naked, @@ -1506,10 +1506,9 @@ pub const Object = struct { deinit_wip = false; fg.genBody(air.getMainBody(), .poi) catch |err| switch (err) { - error.CodegenFail => { - try zcu.failed_codegen.put(gpa, func.owner_nav, ng.err_msg.?); - ng.err_msg = null; - return; + error.CodegenFail => switch (zcu.codegenFailMsg(func.owner_nav, ng.err_msg.?)) { + error.CodegenFail => return, + error.OutOfMemory => |e| return e, }, else => |e| return e, }; @@ -1561,10 +1560,9 @@ pub const Object = struct { .err_msg = null, }; ng.genDecl() catch |err| switch (err) { - error.CodegenFail => { - try pt.zcu.failed_codegen.put(pt.zcu.gpa, nav_index, ng.err_msg.?); - ng.err_msg = null; - return; + error.CodegenFail => switch (pt.zcu.codegenFailMsg(nav_index, ng.err_msg.?)) { + error.CodegenFail => return, + error.OutOfMemory => |e| return e, }, else => |e| return e, }; @@ -1586,6 +1584,27 @@ pub const Object = struct { const global_index = self.nav_map.get(nav_index).?; const comp = zcu.comp; + // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use. + coff_export_flags: { + const lf = comp.bin_file orelse break :coff_export_flags; + const lld = lf.cast(.lld) orelse break :coff_export_flags; + const coff = switch (lld.ofmt) { + .elf, .wasm => break :coff_export_flags, + .coff => |*coff| coff, + }; + if (!ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) break :coff_export_flags; + const flags = &coff.lld_export_flags; + for (export_indices) |export_index| { + const name = export_index.ptr(zcu).opts.name; + if (name.eqlSlice("main", ip)) flags.c_main = true; + if (name.eqlSlice("WinMain", ip)) flags.winmain = true; + if (name.eqlSlice("wWinMain", ip)) flags.wwinmain = true; + if (name.eqlSlice("WinMainCRTStartup", ip)) flags.winmain_crt_startup = true; + if (name.eqlSlice("wWinMainCRTStartup", ip)) flags.wwinmain_crt_startup = true; + if (name.eqlSlice("DllMainCRTStartup", ip)) flags.dllmain_crt_startup = true; + } + } + if (export_indices.len != 0) { return updateExportedGlobal(self, zcu, global_index, export_indices); } else { @@ -9490,15 +9509,21 @@ pub const FuncGen = struct { const inst_ty = self.typeOfIndex(inst); - const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name; - if (name == .none) return arg_val; - const func = zcu.funcInfo(zcu.navValue(self.ng.nav_index).toIntern()); + const func_zir = func.zir_body_inst.resolveFull(&zcu.intern_pool).?; + const file = zcu.fileByIndex(func_zir.file); + + const mod = file.mod.?; + if (mod.strip) return arg_val; + const arg = self.air.instructions.items(.data)[@intFromEnum(inst)].arg; + const zir = &file.zir.?; + const name = zir.nullTerminatedString(zir.getParamName(zir.getParamBody(func_zir.inst)[arg.zir_param_index]).?); + const lbrace_line = zcu.navSrcLine(func.owner_nav) + func.lbrace_line + 1; const lbrace_col = func.lbrace_column + 1; const debug_parameter = try o.builder.debugParameter( - try o.builder.metadataString(name.toSlice(self.air)), + try o.builder.metadataString(name), self.file, self.scope, lbrace_line, @@ -9516,7 +9541,6 @@ pub const FuncGen = struct { }, }; - const mod = self.ng.ownerModule(); if (isByRef(inst_ty, zcu)) { _ = try self.wip.callIntrinsic( .normal, diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index f83c6979ffd3..b9eb56dd2376 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -230,8 +230,9 @@ pub const Object = struct { defer nav_gen.deinit(); nav_gen.genNav(do_codegen) catch |err| switch (err) { - error.CodegenFail => { - try zcu.failed_codegen.put(gpa, nav_index, nav_gen.error_msg.?); + error.CodegenFail => switch (zcu.codegenFailMsg(nav_index, nav_gen.error_msg.?)) { + error.CodegenFail => {}, + error.OutOfMemory => |e| return e, }, else => |other| { // There might be an error that happened *after* self.error_msg @@ -249,12 +250,12 @@ pub const Object = struct { self: *Object, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + air: *const Air, + liveness: *const Air.Liveness, ) !void { const nav = pt.zcu.funcInfo(func_index).owner_nav; // TODO: Separate types for generating decls and functions? - try self.genNav(pt, nav, air, liveness, true); + try self.genNav(pt, nav, air.*, liveness.*, true); } pub fn updateNav( diff --git a/src/codegen/spirv/Section.zig b/src/codegen/spirv/Section.zig index 4fe12f999f82..5c2a5fde62d0 100644 --- a/src/codegen/spirv/Section.zig +++ b/src/codegen/spirv/Section.zig @@ -386,8 +386,6 @@ test "SPIR-V Section emit() - string" { } test "SPIR-V Section emit() - extended mask" { - if (@import("builtin").zig_backend == .stage1) return error.SkipZigTest; - var section = Section{}; defer section.deinit(std.testing.allocator); diff --git a/src/dev.zig b/src/dev.zig index 1dc8264ebc2c..2438ae6df72d 100644 --- a/src/dev.zig +++ b/src/dev.zig @@ -25,6 +25,9 @@ pub const Env = enum { /// - `zig build-* -fno-emit-bin` sema, + /// - `zig build-* -ofmt=c` + cbe, + /// - sema /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-` @"x86_64-linux", @@ -144,6 +147,12 @@ pub const Env = enum { => true, else => Env.ast_gen.supports(feature), }, + .cbe => switch (feature) { + .c_backend, + .c_linker, + => true, + else => Env.sema.supports(feature), + }, .@"x86_64-linux" => switch (feature) { .build_command, .stdio_listen, diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index 47fef32773e4..f6195ffa914e 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -985,7 +985,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { assert(comp.freebsd_so_files == null); comp.freebsd_so_files = so_files; - var task_buffer: [libs.len]link.Task = undefined; + var task_buffer: [libs.len]link.PrelinkTask = undefined; var task_buffer_i: usize = 0; { @@ -1004,7 +1004,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { } } - comp.queueLinkTasks(task_buffer[0..task_buffer_i]); + comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]); } fn buildSharedLib( @@ -1019,10 +1019,6 @@ fn buildSharedLib( defer tracy.end(); const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }); - const emit_bin = Compilation.EmitLoc{ - .directory = bin_directory, - .basename = basename, - }; const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; @@ -1077,13 +1073,14 @@ fn buildSharedLib( .dirs = comp.dirs.withoutLocalCache(), .thread_pool = comp.thread_pool, .self_exe_path = comp.self_exe_path, - .cache_mode = .incremental, + // Because we manually cache the whole set of objects, we don't cache the individual objects + // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path. + .cache_mode = .none, .config = config, .root_mod = root_mod, .root_name = lib.name, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index cc781c547201..8031827a9d29 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -1148,7 +1148,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { assert(comp.glibc_so_files == null); comp.glibc_so_files = so_files; - var task_buffer: [libs.len]link.Task = undefined; + var task_buffer: [libs.len]link.PrelinkTask = undefined; var task_buffer_i: usize = 0; { @@ -1170,7 +1170,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { } } - comp.queueLinkTasks(task_buffer[0..task_buffer_i]); + comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]); } fn buildSharedLib( @@ -1185,10 +1185,6 @@ fn buildSharedLib( defer tracy.end(); const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }); - const emit_bin = Compilation.EmitLoc{ - .directory = bin_directory, - .basename = basename, - }; const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; @@ -1243,13 +1239,14 @@ fn buildSharedLib( .dirs = comp.dirs.withoutLocalCache(), .thread_pool = comp.thread_pool, .self_exe_path = comp.self_exe_path, - .cache_mode = .incremental, + // Because we manually cache the whole set of objects, we don't cache the individual objects + // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path. + .cache_mode = .none, .config = config, .root_mod = root_mod, .root_name = lib.name, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, diff --git a/src/libs/libcxx.zig b/src/libs/libcxx.zig index 17a7d3d29ea6..0009bfe120c8 100644 --- a/src/libs/libcxx.zig +++ b/src/libs/libcxx.zig @@ -122,17 +122,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! const output_mode = .Lib; const link_mode = .static; const target = comp.root_mod.resolved_target.result; - const basename = try std.zig.binNameAlloc(arena, .{ - .root_name = root_name, - .target = target, - .output_mode = output_mode, - .link_mode = link_mode, - }); - - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }; const cxxabi_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxxabi", "include" }); const cxx_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "include" }); @@ -271,8 +260,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! .root_name = root_name, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .yes_cache, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, @@ -308,7 +296,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! assert(comp.libcxx_static_lib == null); const crt_file = try sub_compilation.toCrtFile(); comp.libcxx_static_lib = crt_file; - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); } pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { @@ -327,17 +315,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr const output_mode = .Lib; const link_mode = .static; const target = comp.root_mod.resolved_target.result; - const basename = try std.zig.binNameAlloc(arena, .{ - .root_name = root_name, - .target = target, - .output_mode = output_mode, - .link_mode = link_mode, - }); - - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }; const cxxabi_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxxabi", "include" }); const cxx_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "include" }); @@ -467,8 +444,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .root_name = root_name, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .yes_cache, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, @@ -504,7 +480,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr assert(comp.libcxxabi_static_lib == null); const crt_file = try sub_compilation.toCrtFile(); comp.libcxxabi_static_lib = crt_file; - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); } pub fn addCxxArgs( diff --git a/src/libs/libtsan.zig b/src/libs/libtsan.zig index 8a5ffd2eab5b..f2cd6831f7d7 100644 --- a/src/libs/libtsan.zig +++ b/src/libs/libtsan.zig @@ -45,11 +45,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .link_mode = link_mode, }); - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }; - const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); const unwind_tables: std.builtin.UnwindTables = @@ -287,8 +282,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .root_mod = root_mod, .root_name = root_name, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .yes_cache, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, @@ -325,7 +319,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo }; const crt_file = try sub_compilation.toCrtFile(); - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); assert(comp.tsan_lib == null); comp.tsan_lib = crt_file; } diff --git a/src/libs/libunwind.zig b/src/libs/libunwind.zig index 945689ebab16..711d63ebbcb0 100644 --- a/src/libs/libunwind.zig +++ b/src/libs/libunwind.zig @@ -31,7 +31,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr const unwind_tables: std.builtin.UnwindTables = if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async"; const config = Compilation.Config.resolve(.{ - .output_mode = .Lib, + .output_mode = output_mode, .resolved_target = comp.root_mod.resolved_target, .is_test = false, .have_zcu = false, @@ -85,17 +85,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr }; const root_name = "unwind"; - const link_mode = .static; - const basename = try std.zig.binNameAlloc(arena, .{ - .root_name = root_name, - .target = target, - .output_mode = output_mode, - .link_mode = link_mode, - }); - const emit_bin = Compilation.EmitLoc{ - .directory = null, // Put it in the cache directory. - .basename = basename, - }; var c_source_files: [unwind_src_list.len]Compilation.CSourceFile = undefined; for (unwind_src_list, 0..) |unwind_src, i| { var cflags = std.ArrayList([]const u8).init(arena); @@ -160,7 +149,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .main_mod = null, .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, + .emit_bin = .yes_cache, .function_sections = comp.function_sections, .c_source_files = &c_source_files, .verbose_cc = comp.verbose_cc, @@ -195,7 +184,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr }; const crt_file = try sub_compilation.toCrtFile(); - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); assert(comp.libunwind_static_lib == null); comp.libunwind_static_lib = crt_file; } diff --git a/src/libs/musl.zig b/src/libs/musl.zig index d208b0982747..7c4e71c9744f 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -252,8 +252,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro .thread_pool = comp.thread_pool, .root_name = "c", .libc_installation = comp.libc_installation, - .emit_bin = .{ .directory = null, .basename = "libc.so" }, - .emit_h = null, + .emit_bin = .yes_cache, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, @@ -278,7 +277,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro errdefer comp.gpa.free(basename); const crt_file = try sub_compilation.toCrtFile(); - comp.queueLinkTaskMode(crt_file.full_object_path, &config); + comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); { comp.mutex.lock(); defer comp.mutex.unlock(); diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index 718861bf5cef..fdab27f217f3 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -650,7 +650,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { assert(comp.netbsd_so_files == null); comp.netbsd_so_files = so_files; - var task_buffer: [libs.len]link.Task = undefined; + var task_buffer: [libs.len]link.PrelinkTask = undefined; var task_buffer_i: usize = 0; { @@ -669,7 +669,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void { } } - comp.queueLinkTasks(task_buffer[0..task_buffer_i]); + comp.queuePrelinkTasks(task_buffer[0..task_buffer_i]); } fn buildSharedLib( @@ -684,10 +684,6 @@ fn buildSharedLib( defer tracy.end(); const basename = try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ lib.name, lib.sover }); - const emit_bin = Compilation.EmitLoc{ - .directory = bin_directory, - .basename = basename, - }; const version: Version = .{ .major = lib.sover, .minor = 0, .patch = 0 }; const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?); const soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else basename; @@ -741,13 +737,14 @@ fn buildSharedLib( .dirs = comp.dirs.withoutLocalCache(), .thread_pool = comp.thread_pool, .self_exe_path = comp.self_exe_path, - .cache_mode = .incremental, + // Because we manually cache the whole set of objects, we don't cache the individual objects + // within it. In fact, we *can't* do that, because we need `emit_bin` to specify the path. + .cache_mode = .none, .config = config, .root_mod = root_mod, .root_name = lib.name, .libc_installation = comp.libc_installation, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, diff --git a/src/link.zig b/src/link.zig index 688210c3556d..9bed6b41314d 100644 --- a/src/link.zig +++ b/src/link.zig @@ -8,7 +8,6 @@ const log = std.log.scoped(.link); const trace = @import("tracy.zig").trace; const wasi_libc = @import("libs/wasi_libc.zig"); -const Air = @import("Air.zig"); const Allocator = std.mem.Allocator; const Cache = std.Build.Cache; const Path = std.Build.Cache.Path; @@ -19,15 +18,13 @@ const Zcu = @import("Zcu.zig"); const InternPool = @import("InternPool.zig"); const Type = @import("Type.zig"); const Value = @import("Value.zig"); -const LlvmObject = @import("codegen/llvm.zig").Object; -const lldMain = @import("main.zig").lldMain; const Package = @import("Package.zig"); const dev = @import("dev.zig"); -const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue; const target_util = @import("target.zig"); const codegen = @import("codegen.zig"); pub const LdScript = @import("link/LdScript.zig"); +pub const Queue = @import("link/Queue.zig"); pub const Diags = struct { /// Stored here so that function definitions can distinguish between @@ -386,10 +383,11 @@ pub const File = struct { emit: Path, file: ?fs.File, - /// 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. - zcu_object_sub_path: ?[]const u8 = null, - disable_lld_caching: bool, + /// When using the LLVM backend, the emitted object is written to a file with this name. This + /// object file then becomes a normal link input to LLD or a self-hosted linker. + /// + /// To convert this to an actual path, see `Compilation.resolveEmitPath` (with `kind == .temp`). + zcu_object_basename: ?[]const u8 = null, gc_sections: bool, print_gc_sections: bool, build_id: std.zig.BuildId, @@ -425,7 +423,7 @@ pub const File = struct { tsaware: bool, nxcompat: bool, dynamicbase: bool, - compress_debug_sections: Elf.CompressDebugSections, + compress_debug_sections: Lld.Elf.CompressDebugSections, bind_global_refs_locally: bool, import_symbols: bool, import_table: bool, @@ -436,9 +434,8 @@ pub const File = struct { export_symbol_names: []const []const u8, global_base: ?u64, build_id: std.zig.BuildId, - disable_lld_caching: bool, - hash_style: Elf.HashStyle, - sort_section: ?Elf.SortSection, + hash_style: Lld.Elf.HashStyle, + sort_section: ?Lld.Elf.SortSection, major_subsystem_version: ?u16, minor_subsystem_version: ?u16, gc_sections: ?bool, @@ -522,12 +519,20 @@ pub const File = struct { emit: Path, options: OpenOptions, ) !*File { + if (comp.config.use_lld) { + dev.check(.lld_linker); + assert(comp.zcu == null or comp.config.use_llvm); + // LLD does not support incremental linking. + const lld: *Lld = try .createEmpty(arena, comp, emit, options); + return &lld.base; + } switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { inline else => |tag| { dev.check(tag.devFeature()); const ptr = try tag.Type().open(arena, comp, emit, options); return &ptr.base; }, + .lld => unreachable, // not known from ofmt } } @@ -537,12 +542,19 @@ pub const File = struct { emit: Path, options: OpenOptions, ) !*File { + if (comp.config.use_lld) { + dev.check(.lld_linker); + assert(comp.zcu == null or comp.config.use_llvm); + const lld: *Lld = try .createEmpty(arena, comp, emit, options); + return &lld.base; + } switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { inline else => |tag| { dev.check(tag.devFeature()); const ptr = try tag.Type().createEmpty(arena, comp, emit, options); return &ptr.base; }, + .lld => unreachable, // not known from ofmt } } @@ -555,6 +567,7 @@ pub const File = struct { const comp = base.comp; const gpa = comp.gpa; switch (base.tag) { + .lld => assert(base.file == null), .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff => { if (base.file != null) return; dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker }); @@ -587,13 +600,12 @@ pub const File = struct { } } } - 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.root_dir.handle.createFile(emit.sub_path, .{ .truncate = false, .read = true, - .mode = determineMode(use_lld, output_mode, link_mode), + .mode = determineMode(output_mode, link_mode), }); }, .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), @@ -619,7 +631,6 @@ pub const File = struct { 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, @@ -630,13 +641,9 @@ pub const File = struct { .Exe => {}, } switch (base.tag) { + .lld => assert(base.file == null), .elf => if (base.file) |f| { dev.check(.elf_linker); - if (base.zcu_object_sub_path != 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. - return; - } f.close(); base.file = null; @@ -651,11 +658,6 @@ pub const File = struct { }, .coff, .macho, .plan9, .wasm, .goff, .xcoff => if (base.file) |f| { dev.checkAny(&.{ .coff_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker }); - if (base.zcu_object_sub_path != null) { - // The file we have open is not the final file that we want to - // make executable, so we don't have to close it. - return; - } f.close(); base.file = null; @@ -693,6 +695,7 @@ pub const File = struct { pub fn getGlobalSymbol(base: *File, name: []const u8, lib_name: ?[]const u8) UpdateNavError!u32 { log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name }); switch (base.tag) { + .lld => unreachable, .plan9 => unreachable, .spirv => unreachable, .c => unreachable, @@ -704,10 +707,13 @@ pub const File = struct { } /// May be called before or after updateExports for any given Nav. - pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void { + /// Asserts that the ZCU is not using the LLVM backend. + fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void { + assert(base.comp.zcu.?.llvm_object == null); const nav = pt.zcu.intern_pool.getNav(nav_index); assert(nav.status == .fully_resolved); switch (base.tag) { + .lld => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateNav(pt, nav_index); @@ -721,8 +727,11 @@ pub const File = struct { TypeFailureReported, }; - pub fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void { + /// Never called when LLVM is codegenning the ZCU. + fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, else => {}, inline .elf => |tag| { dev.check(tag.devFeature()); @@ -732,17 +741,24 @@ pub const File = struct { } /// May be called before or after updateExports for any given Decl. - pub fn updateFunc( + /// The active tag of `mir` is determined by the backend used for the module this function is in. + /// Never called when LLVM is codegenning the ZCU. + fn updateFunc( base: *File, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + /// This is owned by the caller, but the callee is permitted to mutate it provided + /// that `mir.deinit` remains legal for the caller. For instance, the callee can + /// take ownership of an embedded slice and replace it with `&.{}` in `mir`. + mir: *codegen.AnyMir, ) UpdateNavError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, + .spirv => unreachable, // see corresponding special case in `Zcu.PerThread.runCodegenInner` inline else => |tag| { dev.check(tag.devFeature()); - return @as(*tag.Type(), @fieldParentPtr("base", base)).updateFunc(pt, func_index, air, liveness); + return @as(*tag.Type(), @fieldParentPtr("base", base)).updateFunc(pt, func_index, mir); }, } } @@ -755,7 +771,9 @@ pub const File = struct { /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`. - pub fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void { + /// Never called when LLVM is codegenning the ZCU. + fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void { + assert(base.comp.zcu.?.llvm_object == null); { const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?; const file = pt.zcu.fileByIndex(ti.file); @@ -764,6 +782,7 @@ pub const File = struct { } switch (base.tag) { + .lld => unreachable, .spirv => {}, .goff, .xcoff => {}, inline else => |tag| { @@ -803,8 +822,7 @@ pub const File = struct { OutOfMemory, }; - /// Commit pending changes and write headers. Takes into account final output mode - /// and `use_lld`, not only `effectiveOutputMode`. + /// Commit pending changes and write headers. Takes into account final output mode. /// `arena` has the lifetime of the call to `Compilation.update`. pub fn flush(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { const comp = base.comp; @@ -826,15 +844,7 @@ pub const File = struct { }; return; } - assert(base.post_prelink); - - 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(arena, tid, prog_node); - } switch (base.tag) { inline else => |tag| { dev.check(tag.devFeature()); @@ -843,17 +853,6 @@ pub const File = struct { } } - /// Commit pending changes and write headers. Works based on `effectiveOutputMode` - /// rather than final output mode. - pub fn flushModule(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { - switch (base.tag) { - inline else => |tag| { - dev.check(tag.devFeature()); - return @as(*tag.Type(), @fieldParentPtr("base", base)).flushModule(arena, tid, prog_node); - }, - } - } - pub const UpdateExportsError = error{ OutOfMemory, AnalysisFail, @@ -863,13 +862,16 @@ pub const File = struct { /// a list of size 1, meaning that `exported` is exported once. However, it is possible /// to export the same thing with multiple different symbol names (aliases). /// May be called before or after updateDecl for any given Decl. + /// Never called when LLVM is codegenning the ZCU. pub fn updateExports( base: *File, pt: Zcu.PerThread, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, ) UpdateExportsError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, inline else => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(pt, exported, export_indices); @@ -895,8 +897,11 @@ pub const File = struct { /// `Nav`'s address was not yet resolved, or the containing atom gets moved in virtual memory. /// May be called before or after updateFunc/updateNav therefore it is up to the linker to allocate /// the block/atom. + /// Never called when LLVM is codegenning the ZCU. pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) !u64 { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, .c => unreachable, .spirv => unreachable, .wasm => unreachable, @@ -908,6 +913,7 @@ pub const File = struct { } } + /// Never called when LLVM is codegenning the ZCU. pub fn lowerUav( base: *File, pt: Zcu.PerThread, @@ -915,7 +921,9 @@ pub const File = struct { decl_align: InternPool.Alignment, src_loc: Zcu.LazySrcLoc, ) !codegen.GenResult { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, .c => unreachable, .spirv => unreachable, .wasm => unreachable, @@ -927,8 +935,11 @@ pub const File = struct { } } + /// Never called when LLVM is codegenning the ZCU. pub fn getUavVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, .c => unreachable, .spirv => unreachable, .wasm => unreachable, @@ -940,12 +951,16 @@ pub const File = struct { } } + /// Never called when LLVM is codegenning the ZCU. pub fn deleteExport( base: *File, exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { + .lld => unreachable, + .plan9, .spirv, .goff, @@ -961,6 +976,7 @@ pub const File = struct { /// Opens a path as an object file and parses it into the linker. fn openLoadObject(base: *File, path: Path) anyerror!void { + if (base.tag == .lld) return; const diags = &base.comp.link_diags; const input = try openObjectInput(diags, path); errdefer input.object.file.close(); @@ -970,6 +986,7 @@ pub const File = struct { /// Opens a path as a static library and parses it into the linker. /// If `query` is non-null, allows GNU ld scripts. fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void { + if (base.tag == .lld) return; if (opt_query) |query| { const archive = try openObject(path, query.must_link, query.hidden); errdefer archive.file.close(); @@ -992,6 +1009,7 @@ pub const File = struct { /// Opens a path as a shared library and parses it into the linker. /// Handles GNU ld scripts. fn openLoadDso(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void { + if (base.tag == .lld) return; const dso = try openDso(path, query.needed, query.weak, query.reexport); errdefer dso.file.close(); loadInput(base, .{ .dso = dso }) catch |err| switch (err) { @@ -1044,8 +1062,7 @@ pub const File = struct { } pub fn loadInput(base: *File, input: Input) anyerror!void { - const use_lld = build_options.have_llvm and base.comp.config.use_lld; - if (use_lld) return; + if (base.tag == .lld) return; switch (base.tag) { inline .elf, .wasm => |tag| { dev.check(tag.devFeature()); @@ -1057,186 +1074,23 @@ pub const File = struct { /// Called when all linker inputs have been sent via `loadInput`. After /// this, `loadInput` will not be called anymore. - pub fn prelink(base: *File, prog_node: std.Progress.Node) FlushError!void { + pub fn prelink(base: *File) FlushError!void { assert(!base.post_prelink); - const use_lld = build_options.have_llvm and base.comp.config.use_lld; - if (use_lld) return; // In this case, an object file is created by the LLVM backend, so // there is no prelink phase. The Zig code is linked as a standard // object along with the others. - if (base.zcu_object_sub_path != null) return; + if (base.zcu_object_basename != null) return; switch (base.tag) { inline .wasm => |tag| { dev.check(tag.devFeature()); - return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(prog_node); + return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); }, else => {}, } } - pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { - dev.check(.lld_linker); - - const tracy = trace(@src()); - defer tracy.end(); - - const comp = base.comp; - const diags = &comp.link_diags; - - return linkAsArchiveInner(base, arena, tid, prog_node) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.LinkFailure => return error.LinkFailure, - else => |e| return diags.fail("failed to link as archive: {s}", .{@errorName(e)}), - }; - } - - fn linkAsArchiveInner(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { - const comp = base.comp; - - const directory = base.emit.root_dir; // 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 = comp.zcu; - - // 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 zcu_obj_path: ?[]const u8 = if (opt_zcu != null) blk: { - try base.flushModule(arena, tid, prog_node); - - const dirname = fs.path.dirname(full_out_path_z) orelse "."; - break :blk try fs.path.join(arena, &.{ dirname, base.zcu_object_sub_path.? }); - } else null; - - log.debug("zcu_obj_path={s}", .{if (zcu_obj_path) |s| s else "(null)"}); - - const compiler_rt_path: ?Path = if (comp.compiler_rt_strat == .obj) - comp.compiler_rt_obj.?.full_object_path - else - null; - - const ubsan_rt_path: ?Path = if (comp.ubsan_rt_strat == .obj) - comp.ubsan_rt_obj.?.full_object_path - else - null; - - // This function follows the same pattern as link.Elf.linkWithLLD so if you want some - // insight as to what's going on here you can read that function body which is more - // well-commented. - - const id_symlink_basename = "llvm-ar.id"; - - var man: Cache.Manifest = undefined; - defer if (!base.disable_lld_caching) man.deinit(); - - const link_inputs = comp.link_inputs; - - var digest: [Cache.hex_digest_len]u8 = undefined; - - 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(); - - try hashInputs(&man, link_inputs); - - for (comp.c_object_table.keys()) |key| { - _ = try man.addFilePath(key.status.success.object_path, null); - } - for (comp.win32_resource_table.keys()) |key| { - _ = try man.addFile(key.status.success.res_path, null); - } - try man.addOptionalFile(zcu_obj_path); - try man.addOptionalFilePath(compiler_rt_path); - try man.addOptionalFilePath(ubsan_rt_path); - - // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. - _ = try man.hit(); - digest = man.final(); - - var prev_digest_buf: [digest.len]u8 = undefined; - const prev_digest: []u8 = Cache.readSmallFile( - directory.handle, - id_symlink_basename, - &prev_digest_buf, - ) catch |err| b: { - log.debug("archive new_digest={s} readFile error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); - break :b prev_digest_buf[0..0]; - }; - if (mem.eql(u8, prev_digest, &digest)) { - log.debug("archive digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); - base.lock = man.toOwnedLock(); - return; - } - - // We are about to change the output file to be different, so we invalidate the build hash now. - directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { - error.FileNotFound => {}, - else => |e| return e, - }; - } - - var object_files: std.ArrayListUnmanaged([*:0]const u8) = .empty; - - try object_files.ensureUnusedCapacity(arena, link_inputs.len); - for (link_inputs) |input| { - object_files.appendAssumeCapacity(try input.path().?.toStringZ(arena)); - } - - try object_files.ensureUnusedCapacity(arena, comp.c_object_table.count() + - comp.win32_resource_table.count() + 2); - - for (comp.c_object_table.keys()) |key| { - object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena)); - } - for (comp.win32_resource_table.keys()) |key| { - object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path)); - } - if (zcu_obj_path) |p| object_files.appendAssumeCapacity(try arena.dupeZ(u8, p)); - if (compiler_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); - if (ubsan_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); - - if (comp.verbose_link) { - std.debug.print("ar rcs {s}", .{full_out_path_z}); - for (object_files.items) |arg| { - std.debug.print(" {s}", .{arg}); - } - std.debug.print("\n", .{}); - } - - const llvm_bindings = @import("codegen/llvm/bindings.zig"); - const llvm = @import("codegen/llvm.zig"); - const target = comp.root_mod.resolved_target.result; - llvm.initializeLLVMTarget(target.cpu.arch); - const bad = llvm_bindings.WriteArchive( - full_out_path_z, - object_files.items.ptr, - object_files.items.len, - switch (target.os.tag) { - .aix => .AIXBIG, - .windows => .COFF, - else => if (target.os.tag.isDarwin()) .DARWIN else .GNU, - }, - ); - if (bad) return error.UnableToWriteArchive; - - 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)}); - }; - - if (man.have_exclusive_lock) { - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when archiving: {s}", .{@errorName(err)}); - }; - } - - base.lock = man.toOwnedLock(); - } - } - pub const Tag = enum { coff, elf, @@ -1247,6 +1101,7 @@ pub const File = struct { plan9, goff, xcoff, + lld, pub fn Type(comptime tag: Tag) type { return switch (tag) { @@ -1259,10 +1114,11 @@ pub const File = struct { .plan9 => Plan9, .goff => Goff, .xcoff => Xcoff, + .lld => Lld, }; } - pub fn fromObjectFormat(ofmt: std.Target.ObjectFormat) Tag { + fn fromObjectFormat(ofmt: std.Target.ObjectFormat) Tag { return switch (ofmt) { .coff => .coff, .elf => .elf, @@ -1290,15 +1146,7 @@ pub const File = struct { ty: InternPool.Index, }; - pub fn effectiveOutputMode( - use_lld: bool, - output_mode: std.builtin.OutputMode, - ) std.builtin.OutputMode { - return if (use_lld) .Obj else output_mode; - } - pub fn determineMode( - use_lld: bool, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, ) fs.File.Mode { @@ -1307,7 +1155,7 @@ pub const File = struct { // more leniently. As another data point, C's fopen seems to open files with the // 666 mode. const executable_mode = if (builtin.target.os.tag == .windows) 0 else 0o777; - switch (effectiveOutputMode(use_lld, output_mode)) { + switch (output_mode) { .Lib => return switch (link_mode) { .dynamic => executable_mode, .static => fs.File.default_mode, @@ -1345,21 +1193,6 @@ pub const File = struct { return output_mode == .Lib and !self.isStatic(); } - pub fn emitLlvmObject( - base: File, - arena: Allocator, - llvm_object: LlvmObject.Ptr, - prog_node: std.Progress.Node, - ) !void { - return base.comp.emitLlvmObject(arena, .{ - .root_dir = base.emit.root_dir, - .sub_path = std.fs.path.dirname(base.emit.sub_path) orelse "", - }, .{ - .directory = null, - .basename = base.zcu_object_sub_path.?, - }, llvm_object, prog_node); - } - pub fn cgFail( base: *File, nav_index: InternPool.Nav.Index, @@ -1370,6 +1203,7 @@ pub const File = struct { return base.comp.zcu.?.codegenFail(nav_index, format, args); } + pub const Lld = @import("link/Lld.zig"); pub const C = @import("link/C.zig"); pub const Coff = @import("link/Coff.zig"); pub const Plan9 = @import("link/Plan9.zig"); @@ -1382,40 +1216,7 @@ pub const File = struct { pub const Dwarf = @import("link/Dwarf.zig"); }; -/// Does all the tasks in the queue. Runs in exactly one separate thread -/// from the rest of compilation. All tasks performed here are -/// single-threaded with respect to one another. -pub fn flushTaskQueue(tid: usize, comp: *Compilation) void { - const diags = &comp.link_diags; - // As soon as check() is called, another `flushTaskQueue` call could occur, - // so the safety lock must go after the check. - while (comp.link_task_queue.check()) |tasks| { - comp.link_task_queue_safety.lock(); - defer comp.link_task_queue_safety.unlock(); - - if (comp.remaining_prelink_tasks > 0) { - comp.link_task_queue_postponed.ensureUnusedCapacity(comp.gpa, tasks.len) catch |err| switch (err) { - error.OutOfMemory => return diags.setAllocFailure(), - }; - } - - for (tasks) |task| doTask(comp, tid, task); - - if (comp.remaining_prelink_tasks == 0) { - if (comp.bin_file) |base| if (!base.post_prelink) { - base.prelink(comp.work_queue_progress_node) catch |err| switch (err) { - error.OutOfMemory => diags.setAllocFailure(), - error.LinkFailure => continue, - }; - base.post_prelink = true; - for (comp.link_task_queue_postponed.items) |task| doTask(comp, tid, task); - comp.link_task_queue_postponed.clearRetainingCapacity(); - }; - } - } -} - -pub const Task = union(enum) { +pub const PrelinkTask = union(enum) { /// Loads the objects, shared objects, and archives that are already /// known from the command line. load_explicitly_provided, @@ -1433,32 +1234,74 @@ pub const Task = union(enum) { /// Tells the linker to load an input which could be an object file, /// archive, or shared library. load_input: Input, - +}; +pub const ZcuTask = union(enum) { /// Write the constant value for a Decl to the output file. - codegen_nav: InternPool.Nav.Index, + link_nav: InternPool.Nav.Index, /// Write the machine code for a function to the output file. - codegen_func: CodegenFunc, - codegen_type: InternPool.Index, - + link_func: LinkFunc, + link_type: InternPool.Index, update_line_number: InternPool.TrackedInst.Index, - - pub const CodegenFunc = struct { + pub fn deinit(task: ZcuTask, zcu: *const Zcu) void { + switch (task) { + .link_nav, + .link_type, + .update_line_number, + => {}, + .link_func => |link_func| { + switch (link_func.mir.status.load(.monotonic)) { + .pending => unreachable, // cannot deinit until MIR done + .failed => {}, // MIR not populated so doesn't need freeing + .ready => link_func.mir.value.deinit(zcu), + } + zcu.gpa.destroy(link_func.mir); + }, + } + } + pub const LinkFunc = struct { /// This will either be a non-generic `func_decl` or a `func_instance`. func: InternPool.Index, - /// This `Air` is owned by the `Job` and allocated with `gpa`. - /// It must be deinited when the job is processed. - air: Air, + /// This pointer is allocated into `gpa` and must be freed when the `ZcuTask` is processed. + /// The pointer is shared with the codegen worker, which will populate the MIR inside once + /// it has been generated. It's important that the `link_func` is queued at the same time as + /// the codegen job to ensure that the linker receives functions in a deterministic order, + /// allowing reproducible builds. + mir: *SharedMir, + /// This is not actually used by `doZcuTask`. Instead, `Queue` uses this value as a heuristic + /// to avoid queueing too much AIR/MIR for codegen/link at a time. Essentially, we cap the + /// total number of AIR bytes which are being processed at once, preventing unbounded memory + /// usage when AIR is produced faster than it is processed. + air_bytes: u32, + + pub const SharedMir = struct { + /// This is initially `.pending`. When `value` is populated, the codegen thread will set + /// this to `.ready`, and alert the queue if needed. It could also end up `.failed`. + /// The action of storing a value (other than `.pending`) to this atomic transfers + /// ownership of memory assoicated with `value` to this `ZcuTask`. + status: std.atomic.Value(enum(u8) { + /// We are waiting on codegen to generate MIR (or die trying). + pending, + /// `value` is not populated and will not be populated. Just drop the task from the queue and move on. + failed, + /// `value` is populated with the MIR from the backend in use, which is not LLVM. + ready, + }), + /// This is `undefined` until `ready` is set to `true`. Once populated, this MIR belongs + /// to the `ZcuTask`, and must be `deinit`ed when it is processed. Allocated into `gpa`. + value: codegen.AnyMir, + }; }; }; -pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { +pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { const diags = &comp.link_diags; + const base = comp.bin_file orelse { + comp.link_prog_node.completeOne(); + return; + }; switch (task) { .load_explicitly_provided => { - comp.remaining_prelink_tasks -= 1; - const base = comp.bin_file orelse return; - - const prog_node = comp.work_queue_progress_node.start("Parse Linker Inputs", comp.link_inputs.len); + const prog_node = comp.link_prog_node.start("Parse Inputs", comp.link_inputs.len); defer prog_node.end(); for (comp.link_inputs) |input| { base.loadInput(input) catch |err| switch (err) { @@ -1475,10 +1318,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { } }, .load_host_libc => { - comp.remaining_prelink_tasks -= 1; - const base = comp.bin_file orelse return; - - const prog_node = comp.work_queue_progress_node.start("Linker Parse Host libc", 0); + const prog_node = comp.link_prog_node.start("Parse Host libc", 0); defer prog_node.end(); const target = comp.root_mod.resolved_target.result; @@ -1537,9 +1377,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { } }, .load_object => |path| { - comp.remaining_prelink_tasks -= 1; - const base = comp.bin_file orelse return; - const prog_node = comp.work_queue_progress_node.start("Linker Parse Object", 0); + const prog_node = comp.link_prog_node.start("Parse Object", 0); defer prog_node.end(); base.openLoadObject(path) catch |err| switch (err) { error.LinkFailure => return, // error reported via diags @@ -1547,9 +1385,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { }; }, .load_archive => |path| { - comp.remaining_prelink_tasks -= 1; - const base = comp.bin_file orelse return; - const prog_node = comp.work_queue_progress_node.start("Linker Parse Archive", 0); + const prog_node = comp.link_prog_node.start("Parse Archive", 0); defer prog_node.end(); base.openLoadArchive(path, null) catch |err| switch (err) { error.LinkFailure => return, // error reported via link_diags @@ -1557,9 +1393,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { }; }, .load_dso => |path| { - comp.remaining_prelink_tasks -= 1; - const base = comp.bin_file orelse return; - const prog_node = comp.work_queue_progress_node.start("Linker Parse Shared Library", 0); + const prog_node = comp.link_prog_node.start("Parse Shared Library", 0); defer prog_node.end(); base.openLoadDso(path, .{ .preferred_mode = .dynamic, @@ -1570,9 +1404,7 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { }; }, .load_input => |input| { - comp.remaining_prelink_tasks -= 1; - const base = comp.bin_file orelse return; - const prog_node = comp.work_queue_progress_node.start("Linker Parse Input", 0); + const prog_node = comp.link_prog_node.start("Parse Input", 0); defer prog_node.end(); base.loadInput(input) catch |err| switch (err) { error.LinkFailure => return, // error reported via link_diags @@ -1585,159 +1417,113 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { }, }; }, - .codegen_nav => |nav_index| { - if (comp.remaining_prelink_tasks == 0) { - const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); - defer pt.deactivate(); - pt.linkerUpdateNav(nav_index) catch |err| switch (err) { + } +} +pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void { + const diags = &comp.link_diags; + const zcu = comp.zcu.?; + const ip = &zcu.intern_pool; + const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid)); + defer pt.deactivate(); + switch (task) { + .link_nav => |nav_index| { + const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip); + const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0); + defer nav_prog_node.end(); + if (zcu.llvm_object) |llvm_object| { + llvm_object.updateNav(pt, nav_index) catch |err| switch (err) { error.OutOfMemory => diags.setAllocFailure(), }; - } else { - comp.link_task_queue_postponed.appendAssumeCapacity(task); - } - }, - .codegen_func => |func| { - if (comp.remaining_prelink_tasks == 0) { - const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); - defer pt.deactivate(); - var air = func.air; - defer air.deinit(comp.gpa); - pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) { + } else if (comp.bin_file) |lf| { + lf.updateNav(pt, nav_index) catch |err| switch (err) { error.OutOfMemory => diags.setAllocFailure(), + error.CodegenFail => zcu.assertCodegenFailed(nav_index), + error.Overflow, error.RelocationNotByteAligned => { + switch (zcu.codegenFail(nav_index, "unable to codegen: {s}", .{@errorName(err)})) { + error.CodegenFail => return, + error.OutOfMemory => return diags.setAllocFailure(), + } + // Not a retryable failure. + }, }; - } else { - comp.link_task_queue_postponed.appendAssumeCapacity(task); } }, - .codegen_type => |ty| { - if (comp.remaining_prelink_tasks == 0) { - const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); - defer pt.deactivate(); - pt.linkerUpdateContainerType(ty) catch |err| switch (err) { - error.OutOfMemory => diags.setAllocFailure(), + .link_func => |func| { + const nav = zcu.funcInfo(func.func).owner_nav; + const fqn_slice = ip.getNav(nav).fqn.toSlice(ip); + const nav_prog_node = comp.link_prog_node.start(fqn_slice, 0); + defer nav_prog_node.end(); + switch (func.mir.status.load(.monotonic)) { + .pending => unreachable, + .ready => {}, + .failed => return, + } + assert(zcu.llvm_object == null); // LLVM codegen doesn't produce MIR + const mir = &func.mir.value; + if (comp.bin_file) |lf| { + lf.updateFunc(pt, func.func, mir) catch |err| switch (err) { + error.OutOfMemory => return diags.setAllocFailure(), + error.CodegenFail => return zcu.assertCodegenFailed(nav), + error.Overflow, error.RelocationNotByteAligned => { + switch (zcu.codegenFail(nav, "unable to codegen: {s}", .{@errorName(err)})) { + error.OutOfMemory => return diags.setAllocFailure(), + error.CodegenFail => return, + } + }, }; - } else { - comp.link_task_queue_postponed.appendAssumeCapacity(task); + } + }, + .link_type => |ty| { + const name = Type.fromInterned(ty).containerTypeName(ip).toSlice(ip); + const nav_prog_node = comp.link_prog_node.start(name, 0); + defer nav_prog_node.end(); + if (zcu.llvm_object == null) { + if (comp.bin_file) |lf| { + lf.updateContainerType(pt, ty) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + error.TypeFailureReported => assert(zcu.failed_types.contains(ty)), + }; + } } }, .update_line_number => |ti| { - const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); - defer pt.deactivate(); - pt.linkerUpdateLineNumber(ti) catch |err| switch (err) { - error.OutOfMemory => diags.setAllocFailure(), - }; + const nav_prog_node = comp.link_prog_node.start("Update line number", 0); + defer nav_prog_node.end(); + if (pt.zcu.llvm_object == null) { + if (comp.bin_file) |lf| { + lf.updateLineNumber(pt, ti) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + else => |e| log.err("update line number failed: {s}", .{@errorName(e)}), + }; + } + } }, } } - -pub fn spawnLld( - comp: *Compilation, - arena: Allocator, - argv: []const []const u8, -) !void { - if (comp.verbose_link) { - // Skip over our own name so that the LLD linker name is the first argv item. - Compilation.dump_argv(argv[1..]); - } - - // If possible, we run LLD as a child process because it does not always - // behave properly as a library, unfortunately. - // https://github.com/ziglang/zig/issues/3825 - if (!std.process.can_spawn) { - const exit_code = try lldMain(arena, argv, false); - if (exit_code == 0) return; - if (comp.clang_passthrough_mode) std.process.exit(exit_code); - return error.LinkFailure; - } - - var stderr: []u8 = &.{}; - defer comp.gpa.free(stderr); - - var child = std.process.Child.init(argv, arena); - const term = (if (comp.clang_passthrough_mode) term: { - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - break :term child.spawnAndWait(); - } else term: { - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; - - child.spawn() catch |err| break :term err; - stderr = try child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize)); - break :term child.wait(); - }) catch |first_err| term: { - const err = switch (first_err) { - error.NameTooLong => err: { - const s = fs.path.sep_str; - const rand_int = std.crypto.random.int(u64); - const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp"; - - const rsp_file = try comp.dirs.local_cache.handle.createFileZ(rsp_path, .{}); - defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err| - log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) }); - { - defer rsp_file.close(); - var rsp_buf = std.io.bufferedWriter(rsp_file.writer()); - const rsp_writer = rsp_buf.writer(); - for (argv[2..]) |arg| { - try rsp_writer.writeByte('"'); - for (arg) |c| { - switch (c) { - '\"', '\\' => try rsp_writer.writeByte('\\'), - else => {}, - } - try rsp_writer.writeByte(c); - } - try rsp_writer.writeByte('"'); - try rsp_writer.writeByte('\n'); - } - try rsp_buf.flush(); - } - - var rsp_child = std.process.Child.init(&.{ argv[0], argv[1], try std.fmt.allocPrint( - arena, - "@{s}", - .{try comp.dirs.local_cache.join(arena, &.{rsp_path})}, - ) }, arena); - if (comp.clang_passthrough_mode) { - rsp_child.stdin_behavior = .Inherit; - rsp_child.stdout_behavior = .Inherit; - rsp_child.stderr_behavior = .Inherit; - - break :term rsp_child.spawnAndWait() catch |err| break :err err; - } else { - rsp_child.stdin_behavior = .Ignore; - rsp_child.stdout_behavior = .Ignore; - rsp_child.stderr_behavior = .Pipe; - - rsp_child.spawn() catch |err| break :err err; - stderr = try rsp_child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize)); - break :term rsp_child.wait() catch |err| break :err err; +/// After the main pipeline is done, but before flush, the compilation may need to link one final +/// `Nav` into the binary: the `builtin.test_functions` value. Since the link thread isn't running +/// by then, we expose this function which can be called directly. +pub fn linkTestFunctionsNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) void { + const zcu = pt.zcu; + const comp = zcu.comp; + const diags = &comp.link_diags; + if (zcu.llvm_object) |llvm_object| { + llvm_object.updateNav(pt, nav_index) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + }; + } else if (comp.bin_file) |lf| { + lf.updateNav(pt, nav_index) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + error.CodegenFail => zcu.assertCodegenFailed(nav_index), + error.Overflow, error.RelocationNotByteAligned => { + switch (zcu.codegenFail(nav_index, "unable to codegen: {s}", .{@errorName(err)})) { + error.CodegenFail => return, + error.OutOfMemory => return diags.setAllocFailure(), } + // Not a retryable failure. }, - else => first_err, }; - log.err("unable to spawn LLD {s}: {s}", .{ argv[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - - const diags = &comp.link_diags; - switch (term) { - .Exited => |code| if (code != 0) { - if (comp.clang_passthrough_mode) std.process.exit(code); - diags.lockAndParseLldStderr(argv[1], stderr); - return error.LinkFailure; - }, - else => { - if (comp.clang_passthrough_mode) std.process.abort(); - return diags.fail("{s} terminated with stderr:\n{s}", .{ argv[0], stderr }); - }, } - - if (stderr.len > 0) log.warn("unexpected LLD stderr:\n{s}", .{stderr}); } /// Provided by the CLI, processed into `LinkInput` instances at the start of diff --git a/src/link/C.zig b/src/link/C.zig index c32d8ba80ba0..f3465055b862 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -17,7 +17,7 @@ const link = @import("../link.zig"); const trace = @import("../tracy.zig").trace; const Type = @import("../Type.zig"); const Value = @import("../Value.zig"); -const Air = @import("../Air.zig"); +const AnyMir = @import("../codegen.zig").AnyMir; pub const zig_h = "#include \"zig.h\"\n"; @@ -145,7 +145,6 @@ pub fn createEmpty( .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = file, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, }; @@ -167,6 +166,9 @@ pub fn deinit(self: *C) void { self.uavs.deinit(gpa); self.aligned_uavs.deinit(gpa); + self.exported_navs.deinit(gpa); + self.exported_uavs.deinit(gpa); + self.string_bytes.deinit(gpa); self.fwd_decl_buf.deinit(gpa); self.code_buf.deinit(gpa); @@ -178,73 +180,23 @@ pub fn updateFunc( self: *C, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *AnyMir, ) link.File.UpdateNavError!void { const zcu = pt.zcu; const gpa = zcu.gpa; const func = zcu.funcInfo(func_index); - const gop = try self.navs.getOrPut(gpa, func.owner_nav); - if (!gop.found_existing) gop.value_ptr.* = .{}; - const ctype_pool = &gop.value_ptr.ctype_pool; - const lazy_fns = &gop.value_ptr.lazy_fns; - const fwd_decl = &self.fwd_decl_buf; - const code = &self.code_buf; - try ctype_pool.init(gpa); - ctype_pool.clearRetainingCapacity(); - lazy_fns.clearRetainingCapacity(); - fwd_decl.clearRetainingCapacity(); - code.clearRetainingCapacity(); - - var function: codegen.Function = .{ - .value_map = codegen.CValueMap.init(gpa), - .air = air, - .liveness = liveness, - .func_index = func_index, - .object = .{ - .dg = .{ - .gpa = gpa, - .pt = pt, - .mod = zcu.navFileScope(func.owner_nav).mod.?, - .error_msg = null, - .pass = .{ .nav = func.owner_nav }, - .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked, - .expected_block = null, - .fwd_decl = fwd_decl.toManaged(gpa), - .ctype_pool = ctype_pool.*, - .scratch = .{}, - .uav_deps = self.uavs, - .aligned_uavs = self.aligned_uavs, - }, - .code = code.toManaged(gpa), - .indent_writer = undefined, // set later so we can get a pointer to object.code - }, - .lazy_fns = lazy_fns.*, - }; - function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; - defer { - self.uavs = function.object.dg.uav_deps; - self.aligned_uavs = function.object.dg.aligned_uavs; - fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged(); - ctype_pool.* = function.object.dg.ctype_pool.move(); - ctype_pool.freeUnusedCapacity(gpa); - function.object.dg.scratch.deinit(gpa); - lazy_fns.* = function.lazy_fns.move(); - lazy_fns.shrinkAndFree(gpa, lazy_fns.count()); - code.* = function.object.code.moveToUnmanaged(); - function.deinit(); - } - try zcu.failed_codegen.ensureUnusedCapacity(gpa, 1); - codegen.genFunc(&function) catch |err| switch (err) { - error.AnalysisFail => { - zcu.failed_codegen.putAssumeCapacityNoClobber(func.owner_nav, function.object.dg.error_msg.?); - return; - }, - else => |e| return e, + const gop = try self.navs.getOrPut(gpa, func.owner_nav); + if (gop.found_existing) gop.value_ptr.deinit(gpa); + gop.value_ptr.* = .{ + .code = .empty, + .fwd_decl = .empty, + .ctype_pool = mir.c.ctype_pool.move(), + .lazy_fns = mir.c.lazy_fns.move(), }; - gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items); - gop.value_ptr.code = try self.addString(function.object.code.items); + gop.value_ptr.code = try self.addString(mir.c.code); + gop.value_ptr.fwd_decl = try self.addString(mir.c.fwd_decl); + try self.addUavsFromCodegen(&mir.c.uavs); } fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void { @@ -268,16 +220,14 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void { .fwd_decl = fwd_decl.toManaged(gpa), .ctype_pool = codegen.CType.Pool.empty, .scratch = .{}, - .uav_deps = self.uavs, - .aligned_uavs = self.aligned_uavs, + .uavs = .empty, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code }; object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { - self.uavs = object.dg.uav_deps; - self.aligned_uavs = object.dg.aligned_uavs; + object.dg.uavs.deinit(gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); object.dg.ctype_pool.deinit(object.dg.gpa); object.dg.scratch.deinit(gpa); @@ -296,8 +246,10 @@ fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) !void { else => |e| return e, }; + try self.addUavsFromCodegen(&object.dg.uavs); + object.dg.ctype_pool.freeUnusedCapacity(gpa); - object.dg.uav_deps.values()[i] = .{ + self.uavs.values()[i] = .{ .code = try self.addString(object.code.items), .fwd_decl = try self.addString(object.dg.fwd_decl.items), .ctype_pool = object.dg.ctype_pool.move(), @@ -344,16 +296,14 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l .fwd_decl = fwd_decl.toManaged(gpa), .ctype_pool = ctype_pool.*, .scratch = .{}, - .uav_deps = self.uavs, - .aligned_uavs = self.aligned_uavs, + .uavs = .empty, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code }; object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { - self.uavs = object.dg.uav_deps; - self.aligned_uavs = object.dg.aligned_uavs; + object.dg.uavs.deinit(gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); ctype_pool.* = object.dg.ctype_pool.move(); ctype_pool.freeUnusedCapacity(gpa); @@ -361,16 +311,16 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l code.* = object.code.moveToUnmanaged(); } - try zcu.failed_codegen.ensureUnusedCapacity(gpa, 1); codegen.genDecl(&object) catch |err| switch (err) { - error.AnalysisFail => { - zcu.failed_codegen.putAssumeCapacityNoClobber(nav_index, object.dg.error_msg.?); - return; + error.AnalysisFail => switch (zcu.codegenFailMsg(nav_index, object.dg.error_msg.?)) { + error.CodegenFail => return, + error.OutOfMemory => |e| return e, }, else => |e| return e, }; gop.value_ptr.code = try self.addString(object.code.items); gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items); + try self.addUavsFromCodegen(&object.dg.uavs); } pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { @@ -381,10 +331,6 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn _ = ti_id; } -pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); -} - fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { const gpa = self.base.comp.gpa; var defines = std.ArrayList(u8).init(gpa); @@ -400,7 +346,7 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { return defines; } -pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { +pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { _ = arena; // Has the same lifetime as the call to Compilation.update. const tracy = trace(@src()); @@ -676,16 +622,14 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F .fwd_decl = fwd_decl.toManaged(gpa), .ctype_pool = ctype_pool.*, .scratch = .{}, - .uav_deps = self.uavs, - .aligned_uavs = self.aligned_uavs, + .uavs = .empty, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code }; object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { - self.uavs = object.dg.uav_deps; - self.aligned_uavs = object.dg.aligned_uavs; + object.dg.uavs.deinit(gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); ctype_pool.* = object.dg.ctype_pool.move(); ctype_pool.freeUnusedCapacity(gpa); @@ -697,6 +641,8 @@ fn flushErrDecls(self: *C, pt: Zcu.PerThread, ctype_pool: *codegen.CType.Pool) F error.AnalysisFail => unreachable, else => |e| return e, }; + + try self.addUavsFromCodegen(&object.dg.uavs); } fn flushLazyFn( @@ -724,8 +670,7 @@ fn flushLazyFn( .fwd_decl = fwd_decl.toManaged(gpa), .ctype_pool = ctype_pool.*, .scratch = .{}, - .uav_deps = .{}, - .aligned_uavs = .{}, + .uavs = .empty, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code @@ -734,8 +679,7 @@ fn flushLazyFn( defer { // If this assert trips just handle the anon_decl_deps the same as // `updateFunc()` does. - assert(object.dg.uav_deps.count() == 0); - assert(object.dg.aligned_uavs.count() == 0); + assert(object.dg.uavs.count() == 0); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); ctype_pool.* = object.dg.ctype_pool.move(); ctype_pool.freeUnusedCapacity(gpa); @@ -871,12 +815,10 @@ pub fn updateExports( .fwd_decl = fwd_decl.toManaged(gpa), .ctype_pool = decl_block.ctype_pool, .scratch = .{}, - .uav_deps = .{}, - .aligned_uavs = .{}, + .uavs = .empty, }; defer { - assert(dg.uav_deps.count() == 0); - assert(dg.aligned_uavs.count() == 0); + assert(dg.uavs.count() == 0); fwd_decl.* = dg.fwd_decl.moveToUnmanaged(); ctype_pool.* = dg.ctype_pool.move(); ctype_pool.freeUnusedCapacity(gpa); @@ -896,3 +838,21 @@ pub fn deleteExport( .uav => |uav| _ = self.exported_uavs.swapRemove(uav), } } + +fn addUavsFromCodegen(c: *C, uavs: *const std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment)) Allocator.Error!void { + const gpa = c.base.comp.gpa; + try c.uavs.ensureUnusedCapacity(gpa, uavs.count()); + try c.aligned_uavs.ensureUnusedCapacity(gpa, uavs.count()); + for (uavs.keys(), uavs.values()) |uav_val, uav_align| { + { + const gop = c.uavs.getOrPutAssumeCapacity(uav_val); + if (!gop.found_existing) gop.value_ptr.* = .{}; + } + if (uav_align != .none) { + const gop = c.aligned_uavs.getOrPutAssumeCapacity(uav_val); + gop.value_ptr.* = if (gop.found_existing) max: { + break :max gop.value_ptr.*.maxStrict(uav_align); + } else uav_align; + } + } +} diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 5100406030bd..0e00229b78e0 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1,26 +1,14 @@ -//! The main driver of the COFF linker. -//! Currently uses our own implementation for the incremental linker, and falls back to -//! 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 emitted to zcu_object_sub_path. -llvm_object: ?LlvmObject.Ptr = null, +//! The main driver of the self-hosted COFF linker. base: link.File, image_base: u64, -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: u16, minor_subsystem_version: u16, -lib_directories: []const Directory, entry: link.File.OpenOptions.Entry, entry_addr: ?u32, module_definition_file: ?[]const u8, -pdb_out_path: ?[]const u8, repro: bool, ptr_width: PtrWidth, @@ -226,7 +214,6 @@ pub fn createEmpty( const output_mode = comp.config.output_mode; const link_mode = comp.config.link_mode; const use_llvm = comp.config.use_llvm; - const use_lld = build_options.have_llvm and comp.config.use_lld; const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 0...32 => .p32, @@ -237,29 +224,21 @@ pub fn createEmpty( else => 0x1000, }; - // If using LLD to link, this code should produce an object file so that it - // can be passed to LLD. - // If using LLVM to generate the object file for the zig compilation unit, - // we need a place to put the object file so that it can be subsequently - // handled. - const zcu_object_sub_path = if (!use_lld and !use_llvm) - null - else - try allocPrint(arena, "{s}.obj", .{emit.sub_path}); - const coff = try arena.create(Coff); coff.* = .{ .base = .{ .tag = .coff, .comp = comp, .emit = emit, - .zcu_object_sub_path = zcu_object_sub_path, + .zcu_object_basename = if (use_llvm) + try std.fmt.allocPrint(arena, "{s}_zcu.obj", .{fs.path.stem(emit.sub_path)}) + else + null, .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, .build_id = options.build_id, }, .ptr_width = ptr_width, @@ -284,45 +263,23 @@ pub fn createEmpty( .Obj => 0, }, - // Subsystem depends on the set of public symbol names from linked objects. - // See LinkerDriver::inferSubsystem from the LLD project for the flow chart. - .subsystem = options.subsystem, - .entry = options.entry, - .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_directories = options.lib_directories, .entry_addr = math.cast(u32, options.entry_addr orelse 0) orelse return error.EntryAddressTooBig, .module_definition_file = options.module_definition_file, - .pdb_out_path = options.pdb_out_path, .repro = options.repro, }; - if (use_llvm and comp.config.have_zcu) { - coff.llvm_object = try LlvmObject.create(arena, comp); - } errdefer coff.base.destroy(); - if (use_lld and (use_llvm or !comp.config.have_zcu)) { - // LLVM emits the object file (if any); LLD links it into the final product. - return coff; - } - - // What path should this COFF linker code output to? - // If using LLD to link, this code should produce an object file so that it - // can be passed to LLD. - const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; - coff.base.file = try emit.root_dir.handle.createFile(sub_path, .{ + coff.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{ .truncate = true, .read = true, - .mode = link.File.determineMode(use_lld, output_mode, link_mode), + .mode = link.File.determineMode(output_mode, link_mode), }); - assert(coff.llvm_object == null); const gpa = comp.gpa; try coff.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); @@ -428,8 +385,6 @@ pub fn open( pub fn deinit(coff: *Coff) void { const gpa = coff.base.comp.gpa; - if (coff.llvm_object) |llvm_object| llvm_object.deinit(); - for (coff.sections.items(.free_list)) |*free_list| { free_list.deinit(gpa); } @@ -1097,15 +1052,11 @@ pub fn updateFunc( coff: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { if (build_options.skip_non_native and builtin.object_format != .coff) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (coff.llvm_object) |llvm_object| { - return llvm_object.updateFunc(pt, func_index, air, liveness); - } const tracy = trace(@src()); defer tracy.end(); @@ -1122,29 +1073,15 @@ pub fn updateFunc( var code_buffer: std.ArrayListUnmanaged(u8) = .empty; defer code_buffer.deinit(gpa); - codegen.generateFunction( + try codegen.emitFunction( &coff.base, pt, zcu.navSrcLoc(nav_index), func_index, - air, - liveness, + mir, &code_buffer, .none, - ) catch |err| switch (err) { - error.CodegenFail => return error.CodegenFail, - error.OutOfMemory => return error.OutOfMemory, - error.Overflow, error.RelocationNotByteAligned => |e| { - try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create( - gpa, - zcu.navSrcLoc(nav_index), - "unable to codegen: {s}", - .{@errorName(e)}, - )); - try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index })); - return error.CodegenFail; - }, - }; + ); try coff.updateNavCode(pt, nav_index, code_buffer.items, .FUNCTION); @@ -1205,7 +1142,6 @@ pub fn updateNav( if (build_options.skip_non_native and builtin.object_format != .coff) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (coff.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index); const tracy = trace(@src()); defer tracy.end(); @@ -1330,7 +1266,7 @@ pub fn getOrCreateAtomForLazySymbol( } state_ptr.* = .pending_flush; const atom = atom_ptr.*; - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flush if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) { .code => coff.text_section_index.?, .const_data => coff.rdata_section_index.?, @@ -1463,8 +1399,6 @@ fn updateNavCode( } pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void { - if (coff.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index); - const gpa = coff.base.comp.gpa; if (coff.decls.fetchOrderedRemove(nav_index)) |const_kv| { @@ -1485,50 +1419,7 @@ pub fn updateExports( } const zcu = pt.zcu; - const ip = &zcu.intern_pool; - const comp = coff.base.comp; - const target = comp.root_mod.resolved_target.result; - - if (comp.config.use_llvm) { - // Even in the case of LLVM, we need to notice certain exported symbols in order to - // detect the default subsystem. - for (export_indices) |export_idx| { - const exp = export_idx.ptr(zcu); - const exported_nav_index = switch (exp.exported) { - .nav => |nav| nav, - .uav => continue, - }; - const exported_nav = ip.getNav(exported_nav_index); - const exported_ty = exported_nav.typeOf(ip); - if (!ip.isFunctionType(exported_ty)) continue; - const c_cc = target.cCallingConvention().?; - const winapi_cc: std.builtin.CallingConvention = switch (target.cpu.arch) { - .x86 => .{ .x86_stdcall = .{} }, - else => c_cc, - }; - const exported_cc = Type.fromInterned(exported_ty).fnCallingConvention(zcu); - const CcTag = std.builtin.CallingConvention.Tag; - if (@as(CcTag, exported_cc) == @as(CcTag, c_cc) and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) { - zcu.stage1_flags.have_c_main = true; - } else if (@as(CcTag, exported_cc) == @as(CcTag, winapi_cc) and target.os.tag == .windows) { - if (exp.opts.name.eqlSlice("WinMain", ip)) { - zcu.stage1_flags.have_winmain = true; - } else if (exp.opts.name.eqlSlice("wWinMain", ip)) { - zcu.stage1_flags.have_wwinmain = true; - } else if (exp.opts.name.eqlSlice("WinMainCRTStartup", ip)) { - zcu.stage1_flags.have_winmain_crt_startup = true; - } else if (exp.opts.name.eqlSlice("wWinMainCRTStartup", ip)) { - zcu.stage1_flags.have_wwinmain_crt_startup = true; - } else if (exp.opts.name.eqlSlice("DllMainCRTStartup", ip)) { - zcu.stage1_flags.have_dllmain_crt_startup = true; - } - } - } - } - - if (coff.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); - - const gpa = comp.gpa; + const gpa = zcu.gpa; const metadata = switch (exported) { .nav => |nav| blk: { @@ -1621,7 +1512,6 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (coff.llvm_object) |_| return; const metadata = switch (exported) { .nav => |nav| coff.navs.getPtr(nav), .uav => |uav| coff.uavs.getPtr(uav), @@ -1680,571 +1570,7 @@ fn resolveGlobalSymbol(coff: *Coff, current: SymbolWithLoc) !void { gop.value_ptr.* = current; } -pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - const comp = coff.base.comp; - const use_lld = build_options.have_llvm and comp.config.use_lld; - const diags = &comp.link_diags; - if (use_lld) { - return coff.linkWithLLD(arena, tid, prog_node) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.LinkFailure => return error.LinkFailure, - else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), - }; - } - switch (comp.config.output_mode) { - .Exe, .Obj => return coff.flushModule(arena, tid, prog_node), - .Lib => return diags.fail("writing lib files not yet implemented for COFF", .{}), - } -} - -fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { - dev.check(.lld_linker); - - const tracy = trace(@src()); - defer tracy.end(); - - const comp = coff.base.comp; - const gpa = comp.gpa; - - const directory = coff.base.emit.root_dir; // Just an alias to make it shorter to type. - const full_out_path = try directory.join(arena, &[_][]const u8{coff.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. - const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { - try coff.flushModule(arena, tid, prog_node); - - if (fs.path.dirname(full_out_path)) |dirname| { - break :blk try fs.path.join(arena, &.{ dirname, coff.base.zcu_object_sub_path.? }); - } else { - break :blk coff.base.zcu_object_sub_path.?; - } - } else null; - - const sub_prog_node = prog_node.start("LLD Link", 0); - defer sub_prog_node.end(); - - 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 = comp.root_mod.resolved_target.result; - const optimize_mode = comp.root_mod.optimize_mode; - const entry_name: ?[]const u8 = switch (coff.entry) { - // This logic isn't quite right for disabled or enabled. No point in fixing it - // when the goal is to eliminate dependency on LLD anyway. - // https://github.com/ziglang/zig/issues/17751 - .disabled, .default, .enabled => null, - .named => |name| name, - }; - - // See link/Elf.zig for comments on how this mechanism works. - const id_symlink_basename = "lld.id"; - - var man: Cache.Manifest = undefined; - defer if (!coff.base.disable_lld_caching) man.deinit(); - - var digest: [Cache.hex_digest_len]u8 = undefined; - - if (!coff.base.disable_lld_caching) { - man = comp.cache_parent.obtain(); - coff.base.releaseLock(); - - comptime assert(Compilation.link_hash_implementation_version == 14); - - try link.hashInputs(&man, comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - _ = try man.addFilePath(key.status.success.object_path, null); - } - for (comp.win32_resource_table.keys()) |key| { - _ = try man.addFile(key.status.success.res_path, null); - } - try man.addOptionalFile(module_obj_path); - man.hash.addOptionalBytes(entry_name); - man.hash.add(coff.base.stack_size); - man.hash.add(coff.image_base); - man.hash.add(coff.base.build_id); - { - // TODO remove this, libraries must instead be resolved by the frontend. - for (coff.lib_directories) |lib_directory| man.hash.addOptionalBytes(lib_directory.path); - } - man.hash.add(comp.skip_linker_dependencies); - if (comp.config.link_libc) { - man.hash.add(comp.libc_installation != null); - if (comp.libc_installation) |libc_installation| { - man.hash.addBytes(libc_installation.crt_dir.?); - if (target.abi == .msvc or target.abi == .itanium) { - man.hash.addBytes(libc_installation.msvc_lib_dir.?); - man.hash.addBytes(libc_installation.kernel32_lib_dir.?); - } - } - } - man.hash.addListOfBytes(comp.windows_libs.keys()); - man.hash.addListOfBytes(comp.force_undefined_symbols.keys()); - man.hash.addOptional(coff.subsystem); - man.hash.add(comp.config.is_test); - man.hash.add(coff.tsaware); - man.hash.add(coff.nxcompat); - man.hash.add(coff.dynamicbase); - man.hash.add(coff.base.allow_shlib_undefined); - // strip does not need to go into the linker hash because it is part of the hash namespace - man.hash.add(coff.major_subsystem_version); - man.hash.add(coff.minor_subsystem_version); - man.hash.add(coff.repro); - man.hash.addOptional(comp.version); - try man.addOptionalFile(coff.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(); - digest = man.final(); - var prev_digest_buf: [digest.len]u8 = undefined; - const prev_digest: []u8 = Cache.readSmallFile( - directory.handle, - id_symlink_basename, - &prev_digest_buf, - ) catch |err| blk: { - log.debug("COFF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); - // Handle this as a cache miss. - break :blk prev_digest_buf[0..0]; - }; - if (mem.eql(u8, prev_digest, &digest)) { - log.debug("COFF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); - // Hot diggity dog! The output binary is already there. - coff.base.lock = man.toOwnedLock(); - return; - } - log.debug("COFF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); - - // We are about to change the output file to be different, so we invalidate the build hash now. - directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { - error.FileNotFound => {}, - else => |e| return e, - }; - } - - 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. - const the_object_path = blk: { - if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; - - if (module_obj_path) |p| - break :blk Path.initCwd(p); - - // TODO I think this is unreachable. Audit this situation when solving the above TODO - // regarding eliding redundant object -> object transformations. - return error.NoObjectsToLink; - }; - try std.fs.Dir.copyFile( - the_object_path.root_dir.handle, - the_object_path.sub_path, - directory.handle, - coff.base.emit.sub_path, - .{}, - ); - } else { - // Create an LLD command line and invoke it. - 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 - - // it calls exit() and does not reset all global data between invocations. - const linker_command = "lld-link"; - try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); - - if (target.isMinGW()) { - try argv.append("-lldmingw"); - } - - try argv.append("-ERRORLIMIT:0"); - try argv.append("-NOLOGO"); - if (comp.config.debug_format != .strip) { - try argv.append("-DEBUG"); - - const out_ext = std.fs.path.extension(full_out_path); - const out_pdb = coff.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ - full_out_path[0 .. full_out_path.len - out_ext.len], - }); - const out_pdb_basename = std.fs.path.basename(out_pdb); - - try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); - try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb_basename})); - } - if (comp.version) |version| { - try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); - } - - if (target_util.llvmMachineAbi(target)) |mabi| { - try argv.append(try allocPrint(arena, "-MLLVM:-target-abi={s}", .{mabi})); - } - - try argv.append(try allocPrint(arena, "-MLLVM:-float-abi={s}", .{if (target.abi.float() == .hard) "hard" else "soft"})); - - if (comp.config.lto != .none) { - switch (optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-OPT:lldlto=2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), - } - } - if (comp.config.output_mode == .Exe) { - try argv.append(try allocPrint(arena, "-STACK:{d}", .{coff.base.stack_size})); - } - try argv.append(try allocPrint(arena, "-BASE:{d}", .{coff.image_base})); - - switch (coff.base.build_id) { - .none => try argv.append("-BUILD-ID:NO"), - .fast => try argv.append("-BUILD-ID"), - .uuid, .sha1, .md5, .hexstring => {}, - } - - if (target.cpu.arch == .x86) { - try argv.append("-MACHINE:X86"); - } else if (target.cpu.arch == .x86_64) { - try argv.append("-MACHINE:X64"); - } else if (target.cpu.arch == .thumb) { - try argv.append("-MACHINE:ARM"); - } else if (target.cpu.arch == .aarch64) { - try argv.append("-MACHINE:ARM64"); - } - - for (comp.force_undefined_symbols.keys()) |symbol| { - try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol})); - } - - if (is_dyn_lib) { - try argv.append("-DLL"); - } - - if (entry_name) |name| { - try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{name})); - } - - if (coff.repro) { - try argv.append("-BREPRO"); - } - - if (coff.tsaware) { - try argv.append("-tsaware"); - } - if (coff.nxcompat) { - try argv.append("-nxcompat"); - } - if (!coff.dynamicbase) { - try argv.append("-dynamicbase:NO"); - } - if (coff.base.allow_shlib_undefined) { - try argv.append("-FORCE:UNRESOLVED"); - } - - try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); - - if (comp.implib_emit) |emit| { - const implib_out_path = try emit.root_dir.join(arena, &[_][]const u8{emit.sub_path}); - try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path})); - } - - if (comp.config.link_libc) { - if (comp.libc_installation) |libc_installation| { - try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?})); - - if (target.abi == .msvc or target.abi == .itanium) { - try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?})); - try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?})); - } - } - } - - for (coff.lib_directories) |lib_directory| { - try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_directory.path orelse "."})); - } - - try argv.ensureUnusedCapacity(comp.link_inputs.len); - for (comp.link_inputs) |link_input| switch (link_input) { - .dso_exact => unreachable, // not applicable to PE/COFF - inline .dso, .res => |x| { - argv.appendAssumeCapacity(try x.path.toString(arena)); - }, - .object, .archive => |obj| { - if (obj.must_link) { - argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Path, obj.path)})); - } else { - argv.appendAssumeCapacity(try obj.path.toString(arena)); - } - }, - }; - - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); - } - - for (comp.win32_resource_table.keys()) |key| { - try argv.append(key.status.success.res_path); - } - - if (module_obj_path) |p| { - try argv.append(p); - } - - if (coff.module_definition_file) |def| { - try argv.append(try allocPrint(arena, "-DEF:{s}", .{def})); - } - - const resolved_subsystem: ?std.Target.SubSystem = blk: { - if (coff.subsystem) |explicit| break :blk explicit; - switch (target.os.tag) { - .windows => { - if (comp.zcu) |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 - module.stage1_flags.have_winmain_crt_startup or - module.stage1_flags.have_wwinmain_crt_startup) - { - break :blk .Console; - } - if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain) - break :blk .Windows; - } - }, - .uefi => break :blk .EfiApplication, - else => {}, - } - break :blk null; - }; - - const Mode = enum { uefi, win32 }; - const mode: Mode = mode: { - if (resolved_subsystem) |subsystem| { - const subsystem_suffix = try allocPrint(arena, ",{d}.{d}", .{ - coff.major_subsystem_version, coff.minor_subsystem_version, - }); - - switch (subsystem) { - .Console => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:console{s}", .{ - subsystem_suffix, - })); - break :mode .win32; - }, - .EfiApplication => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_application{s}", .{ - subsystem_suffix, - })); - break :mode .uefi; - }, - .EfiBootServiceDriver => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_boot_service_driver{s}", .{ - subsystem_suffix, - })); - break :mode .uefi; - }, - .EfiRom => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_rom{s}", .{ - subsystem_suffix, - })); - break :mode .uefi; - }, - .EfiRuntimeDriver => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_runtime_driver{s}", .{ - subsystem_suffix, - })); - break :mode .uefi; - }, - .Native => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:native{s}", .{ - subsystem_suffix, - })); - break :mode .win32; - }, - .Posix => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:posix{s}", .{ - subsystem_suffix, - })); - break :mode .win32; - }, - .Windows => { - try argv.append(try allocPrint(arena, "-SUBSYSTEM:windows{s}", .{ - subsystem_suffix, - })); - break :mode .win32; - }, - } - } else if (target.os.tag == .uefi) { - break :mode .uefi; - } else { - break :mode .win32; - } - }; - - switch (mode) { - .uefi => try argv.appendSlice(&[_][]const u8{ - "-BASE:0", - "-ENTRY:EfiMain", - "-OPT:REF", - "-SAFESEH:NO", - "-MERGE:.rdata=.data", - "-NODEFAULTLIB", - "-SECTION:.xdata,D", - }), - .win32 => { - if (link_in_crt) { - if (target.abi.isGnu()) { - if (target.cpu.arch == .x86) { - try argv.append("-ALTERNATENAME:__image_base__=___ImageBase"); - } else { - try argv.append("-ALTERNATENAME:__image_base__=__ImageBase"); - } - - if (is_dyn_lib) { - try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj")); - if (target.cpu.arch == .x86) { - try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12"); - } else { - try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup"); - } - } else { - try argv.append(try comp.crtFileAsString(arena, "crt2.obj")); - } - - try argv.append(try comp.crtFileAsString(arena, "libmingw32.lib")); - } else { - try argv.append(switch (comp.config.link_mode) { - .static => "libcmt.lib", - .dynamic => "msvcrt.lib", - }); - - const lib_str = switch (comp.config.link_mode) { - .static => "lib", - .dynamic => "", - }; - try argv.append(try allocPrint(arena, "{s}vcruntime.lib", .{lib_str})); - try argv.append(try allocPrint(arena, "{s}ucrt.lib", .{lib_str})); - - //Visual C++ 2015 Conformance Changes - //https://msdn.microsoft.com/en-us/library/bb531344.aspx - try argv.append("legacy_stdio_definitions.lib"); - - // msvcrt depends on kernel32 and ntdll - try argv.append("kernel32.lib"); - try argv.append("ntdll.lib"); - } - } else { - try argv.append("-NODEFAULTLIB"); - if (!is_lib and entry_name == null) { - if (comp.zcu) |module| { - if (module.stage1_flags.have_winmain_crt_startup) { - try argv.append("-ENTRY:WinMainCRTStartup"); - } else { - try argv.append("-ENTRY:wWinMainCRTStartup"); - } - } else { - try argv.append("-ENTRY:wWinMainCRTStartup"); - } - } - } - }, - } - - if (comp.config.link_libc and link_in_crt) { - if (comp.zigc_static_lib) |zigc| { - try argv.append(try zigc.full_object_path.toString(arena)); - } - } - - // libc++ dep - if (comp.config.link_libcpp) { - try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); - try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); - } - - // libunwind dep - if (comp.config.link_libunwind) { - try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); - } - - if (comp.config.any_fuzz) { - try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena)); - } - - const ubsan_rt_path: ?Path = blk: { - if (comp.ubsan_rt_lib) |x| break :blk x.full_object_path; - if (comp.ubsan_rt_obj) |x| break :blk x.full_object_path; - break :blk null; - }; - if (ubsan_rt_path) |path| { - try argv.append(try path.toString(arena)); - } - - if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) { - // MSVC compiler_rt is missing some stuff, so we build it unconditionally but - // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. - if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena)); - if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena)); - } - - try argv.ensureUnusedCapacity(comp.windows_libs.count()); - for (comp.windows_libs.keys()) |key| { - const lib_basename = try allocPrint(arena, "{s}.lib", .{key}); - if (comp.crt_files.get(lib_basename)) |crt_file| { - argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena)); - continue; - } - if (try findLib(arena, lib_basename, coff.lib_directories)) |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, coff.lib_directories)) |full_path| { - argv.appendAssumeCapacity(full_path); - continue; - } - } - if (target.abi == .msvc or target.abi == .itanium) { - argv.appendAssumeCapacity(lib_basename); - continue; - } - - log.err("DLL import library for -l{s} not found", .{key}); - return error.DllImportLibraryNotFound; - } - - try link.spawnLld(comp, arena, argv.items); - } - - if (!coff.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| { - log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)}); - }; - // Again failure here only means an unnecessary cache miss. - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); - }; - // We hang on to this lock so that the output file path can be used without - // other processes clobbering it. - coff.base.lock = man.toOwnedLock(); - } -} - -fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Directory) !?[]const u8 { - for (lib_directories) |lib_directory| { - lib_directory.handle.access(name, .{}) catch |err| switch (err) { - error.FileNotFound => continue, - else => |e| return e, - }; - return try lib_directory.join(arena, &.{name}); - } - return null; -} - -pub fn flushModule( +pub fn flush( coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, @@ -2256,22 +1582,22 @@ pub fn flushModule( const comp = coff.base.comp; const diags = &comp.link_diags; - if (coff.llvm_object) |llvm_object| { - try coff.base.emitLlvmObject(arena, llvm_object, prog_node); - return; + switch (coff.base.comp.config.output_mode) { + .Exe, .Obj => {}, + .Lib => return diags.fail("writing lib files not yet implemented for COFF", .{}), } const sub_prog_node = prog_node.start("COFF Flush", 0); defer sub_prog_node.end(); - return flushModuleInner(coff, arena, tid) catch |err| switch (err) { + return flushInner(coff, arena, tid) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("COFF flush failed: {s}", .{@errorName(e)}), }; } -fn flushModuleInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void { +fn flushInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void { _ = arena; const comp = coff.base.comp; @@ -2397,7 +1723,6 @@ pub fn getNavVAddr( nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo, ) !u64 { - assert(coff.llvm_object == null); const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); @@ -2442,7 +1767,7 @@ pub fn lowerUav( const atom = coff.getAtom(metadata.atom); const existing_addr = atom.getSymbol(coff).value; if (uav_alignment.check(existing_addr)) - return .{ .mcv = .{ .load_direct = atom.getSymbolIndex().? } }; + return .{ .mcv = .{ .load_symbol = atom.getSymbolIndex().? } }; } var name_buf: [32]u8 = undefined; @@ -2474,7 +1799,7 @@ pub fn lowerUav( .section = coff.rdata_section_index.?, }); return .{ .mcv = .{ - .load_direct = coff.getAtom(atom_index).getSymbolIndex().?, + .load_symbol = coff.getAtom(atom_index).getSymbolIndex().?, } }; } @@ -2483,8 +1808,6 @@ pub fn getUavVAddr( uav: InternPool.Index, reloc_info: link.File.RelocInfo, ) !u64 { - assert(coff.llvm_object == null); - const this_atom_index = coff.uavs.get(uav).?.atom; const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?; const atom_index = coff.getAtomIndexForSymbol(.{ @@ -3796,9 +3119,7 @@ const link = @import("../link.zig"); const target_util = @import("../target.zig"); const trace = @import("../tracy.zig").trace; -const Air = @import("../Air.zig"); const Compilation = @import("../Compilation.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); const TableSection = @import("table_section.zig").TableSection; diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e2b8229736ec..0afe10ef03db 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1474,24 +1474,59 @@ pub const WipNav = struct { try cfa.write(wip_nav); } - pub const LocalTag = enum { local_arg, local_var }; - pub fn genLocalDebugInfo( + pub const LocalVarTag = enum { arg, local_var }; + pub fn genLocalVarDebugInfo( wip_nav: *WipNav, - tag: LocalTag, - name: []const u8, + tag: LocalVarTag, + opt_name: ?[]const u8, ty: Type, loc: Loc, ) UpdateError!void { assert(wip_nav.func != .none); try wip_nav.abbrevCode(switch (tag) { - inline else => |ct_tag| @field(AbbrevCode, @tagName(ct_tag)), + .arg => if (opt_name) |_| .arg else .unnamed_arg, + .local_var => if (opt_name) |_| .local_var else unreachable, }); - try wip_nav.strp(name); + if (opt_name) |name| try wip_nav.strp(name); try wip_nav.refType(ty); try wip_nav.infoExprLoc(loc); wip_nav.any_children = true; } + pub const LocalConstTag = enum { comptime_arg, local_const }; + pub fn genLocalConstDebugInfo( + wip_nav: *WipNav, + src_loc: Zcu.LazySrcLoc, + tag: LocalConstTag, + opt_name: ?[]const u8, + val: Value, + ) UpdateError!void { + assert(wip_nav.func != .none); + const pt = wip_nav.pt; + const zcu = pt.zcu; + const ty = val.typeOf(zcu); + const has_runtime_bits = ty.hasRuntimeBits(zcu); + const has_comptime_state = ty.comptimeOnly(zcu) and try ty.onePossibleValue(pt) == null; + try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) { + .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state, + .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable, + } else if (has_comptime_state) switch (tag) { + .comptime_arg => if (opt_name) |_| .comptime_arg_comptime_state else .unnamed_comptime_arg_comptime_state, + .local_const => if (opt_name) |_| .local_const_comptime_state else unreachable, + } else if (has_runtime_bits) switch (tag) { + .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits else .unnamed_comptime_arg_runtime_bits, + .local_const => if (opt_name) |_| .local_const_runtime_bits else unreachable, + } else switch (tag) { + .comptime_arg => if (opt_name) |_| .comptime_arg else .unnamed_comptime_arg, + .local_const => if (opt_name) |_| .local_const else unreachable, + }); + if (opt_name) |name| try wip_nav.strp(name); + try wip_nav.refType(ty); + if (has_runtime_bits) try wip_nav.blockValue(src_loc, val); + if (has_comptime_state) try wip_nav.refValue(val); + wip_nav.any_children = true; + } + pub fn genVarArgsDebugInfo(wip_nav: *WipNav) UpdateError!void { assert(wip_nav.func != .none); try wip_nav.abbrevCode(.is_var_args); @@ -1825,7 +1860,8 @@ pub const WipNav = struct { fn getNavEntry(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!struct { Unit.Index, Entry.Index } { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; - const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod.?); + const nav = ip.getNav(nav_index); + const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?); const gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index); if (gop.found_existing) return .{ unit, gop.value_ptr.* }; const entry = try wip_nav.dwarf.addCommonEntry(unit); @@ -1842,10 +1878,16 @@ pub const WipNav = struct { const zcu = wip_nav.pt.zcu; const ip = &zcu.intern_pool; const maybe_inst_index = ty.typeDeclInst(zcu); - const unit = if (maybe_inst_index) |inst_index| - try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?) - else - .main; + const unit = if (maybe_inst_index) |inst_index| switch (switch (ip.indexToKey(ty.toIntern())) { + else => unreachable, + .struct_type => ip.loadStructType(ty.toIntern()).name_nav, + .union_type => ip.loadUnionType(ty.toIntern()).name_nav, + .enum_type => ip.loadEnumType(ty.toIntern()).name_nav, + .opaque_type => ip.loadOpaqueType(ty.toIntern()).name_nav, + }) { + .none => try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?), + else => |name_nav| return wip_nav.getNavEntry(name_nav.unwrap().?), + } else .main; const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern()); if (gop.found_existing) return .{ unit, gop.value_ptr.* }; const entry = try wip_nav.dwarf.addCommonEntry(unit); @@ -1864,10 +1906,8 @@ pub const WipNav = struct { const ip = &zcu.intern_pool; const ty = value.typeOf(zcu); if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null); - if (!value.isUndef(zcu)) { - if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType()); - if (ip.isFunctionType(ty.toIntern())) return wip_nav.getNavEntry(zcu.funcInfo(value.toIntern()).owner_nav); - } + if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType()); + if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(zcu.funcInfo(value.toIntern()).owner_nav); const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern()); const unit: Unit.Index = .main; if (gop.found_existing) return .{ unit, gop.value_ptr.* }; @@ -1916,7 +1956,10 @@ pub const WipNav = struct { &wip_nav.debug_info, .{ .debug_output = .{ .dwarf = wip_nav } }, ); - assert(old_len + bytes == wip_nav.debug_info.items.len); + if (old_len + bytes != wip_nav.debug_info.items.len) { + std.debug.print("{} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), bytes, wip_nav.debug_info.items.len - old_len }); + unreachable; + } } const AbbrevCodeForForm = struct { @@ -2788,6 +2831,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; + assert(!nav_gop.found_existing); nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -2890,6 +2934,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; + assert(!nav_gop.found_existing); nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -2928,6 +2973,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; + assert(!nav_gop.found_existing); nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -2998,6 +3044,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern()); if (type_gop.found_existing) { if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias; + assert(!nav_gop.found_existing); nav_gop.value_ptr.* = type_gop.value_ptr.*; } else { if (nav_gop.found_existing) @@ -3164,6 +3211,7 @@ fn updateLazyType( ) UpdateError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; + assert(ip.typeOf(type_index) == .type_type); const ty: Type = .fromInterned(type_index); switch (type_index) { .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}), @@ -3200,6 +3248,10 @@ fn updateLazyType( defer dwarf.gpa.free(name); switch (ip.indexToKey(type_index)) { + .undef => { + try wip_nav.abbrevCode(.undefined_comptime_value); + try wip_nav.refType(.type); + }, .int_type => |int_type| { try wip_nav.abbrevCode(.numeric_type); try wip_nav.strp(name); @@ -3633,7 +3685,6 @@ fn updateLazyType( }, // values, not types - .undef, .simple_value, .variable, .@"extern", @@ -3666,7 +3717,11 @@ fn updateLazyValue( ) UpdateError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; - log.debug("updateLazyValue({})", .{Value.fromInterned(value_index).fmtValue(pt)}); + assert(ip.typeOf(value_index) != .type_type); + log.debug("updateLazyValue(@as({}, {}))", .{ + Value.fromInterned(value_index).typeOf(zcu).fmt(pt), + Value.fromInterned(value_index).fmtValue(pt), + }); var wip_nav: WipNav = .{ .dwarf = dwarf, .pt = pt, @@ -3710,9 +3765,8 @@ fn updateLazyValue( .inferred_error_set_type, => unreachable, // already handled .undef => |ty| { - try wip_nav.abbrevCode(.aggregate_comptime_value); + try wip_nav.abbrevCode(.undefined_comptime_value); try wip_nav.refType(.fromInterned(ty)); - try uleb128(diw, @intFromEnum(AbbrevCode.null)); }, .simple_value => unreachable, // opv state .variable, .@"extern" => unreachable, // not a value @@ -4391,7 +4445,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A return @intFromEnum(abbrev_code); } -pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { +pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -4890,8 +4944,22 @@ const AbbrevCode = enum { block, empty_inlined_func, inlined_func, - local_arg, + arg, + unnamed_arg, + comptime_arg, + unnamed_comptime_arg, + comptime_arg_runtime_bits, + unnamed_comptime_arg_runtime_bits, + comptime_arg_comptime_state, + unnamed_comptime_arg_comptime_state, + comptime_arg_runtime_bits_comptime_state, + unnamed_comptime_arg_runtime_bits_comptime_state, local_var, + local_const, + local_const_runtime_bits, + local_const_comptime_state, + local_const_runtime_bits_comptime_state, + undefined_comptime_value, data2_comptime_value, data4_comptime_value, data8_comptime_value, @@ -5663,7 +5731,7 @@ const AbbrevCode = enum { .{ .high_pc, .data4 }, }, }, - .local_arg = .{ + .arg = .{ .tag = .formal_parameter, .attrs = &.{ .{ .name, .strp }, @@ -5671,6 +5739,81 @@ const AbbrevCode = enum { .{ .location, .exprloc }, }, }, + .unnamed_arg = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .type, .ref_addr }, + .{ .location, .exprloc }, + }, + }, + .comptime_arg = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + }, + }, + .unnamed_comptime_arg = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .type, .ref_addr }, + }, + }, + .comptime_arg_runtime_bits = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + }, + }, + .unnamed_comptime_arg_runtime_bits = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + }, + }, + .comptime_arg_comptime_state = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .unnamed_comptime_arg_comptime_state = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .type, .ref_addr }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .comptime_arg_runtime_bits_comptime_state = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .unnamed_comptime_arg_runtime_bits_comptime_state = .{ + .tag = .formal_parameter, + .attrs = &.{ + .{ .const_expr, .flag_present }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, .local_var = .{ .tag = .variable, .attrs = &.{ @@ -5679,6 +5822,44 @@ const AbbrevCode = enum { .{ .location, .exprloc }, }, }, + .local_const = .{ + .tag = .constant, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + }, + }, + .local_const_runtime_bits = .{ + .tag = .constant, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + }, + }, + .local_const_comptime_state = .{ + .tag = .constant, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .local_const_runtime_bits_comptime_state = .{ + .tag = .constant, + .attrs = &.{ + .{ .name, .strp }, + .{ .type, .ref_addr }, + .{ .const_value, .block }, + .{ .ZIG_comptime_value, .ref_addr }, + }, + }, + .undefined_comptime_value = .{ + .tag = .ZIG_comptime_value, + .attrs = &.{ + .{ .type, .ref_addr }, + }, + }, .data2_comptime_value = .{ .tag = .ZIG_comptime_value, .attrs = &.{ diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1516993c7489..0beea0d9e7d5 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -4,7 +4,6 @@ base: link.File, zig_object: ?*ZigObject, rpath_table: std.StringArrayHashMapUnmanaged(void), image_base: u64, -emit_relocs: bool, z_nodelete: bool, z_notext: bool, z_defs: bool, @@ -16,25 +15,11 @@ z_relro: bool, z_common_page_size: ?u64, /// TODO make this non optional and resolve the default in open() z_max_page_size: ?u64, -hash_style: HashStyle, -compress_debug_sections: CompressDebugSections, -symbol_wrap_set: std.StringArrayHashMapUnmanaged(void), -sort_section: ?SortSection, soname: ?[]const u8, -bind_global_refs_locally: bool, -linker_script: ?[]const u8, -version_script: ?[]const u8, -allow_undefined_version: bool, -enable_new_dtags: ?bool, -print_icf_sections: bool, -print_map: bool, entry_name: ?[]const u8, ptr_width: PtrWidth, -/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. -llvm_object: ?LlvmObject.Ptr = null, - /// A list of all input files. /// First index is a special "null file". Order is otherwise not observed. files: std.MultiArrayList(File.Entry) = .{}, @@ -204,9 +189,6 @@ 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 createEmpty( arena: Allocator, @@ -217,7 +199,6 @@ pub fn createEmpty( const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .elf); - const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; const opt_zcu = comp.zcu; const output_mode = comp.config.output_mode; @@ -268,16 +249,6 @@ pub fn createEmpty( const is_dyn_lib = output_mode == .Lib and link_mode == .dynamic; const default_sym_version: elf.Versym = if (is_dyn_lib or comp.config.rdynamic) .GLOBAL else .LOCAL; - // If using LLD to link, this code should produce an object file so that it - // can be passed to LLD. - // If using LLVM to generate the object file for the zig compilation unit, - // we need a place to put the object file so that it can be subsequently - // handled. - const zcu_object_sub_path = if (!use_lld and !use_llvm) - null - else - try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); - var rpath_table: std.StringArrayHashMapUnmanaged(void) = .empty; try rpath_table.entries.resize(arena, options.rpath_list.len); @memcpy(rpath_table.entries.items(.key), options.rpath_list); @@ -289,13 +260,15 @@ pub fn createEmpty( .tag = .elf, .comp = comp, .emit = emit, - .zcu_object_sub_path = zcu_object_sub_path, + .zcu_object_basename = if (use_llvm) + try std.fmt.allocPrint(arena, "{s}_zcu.o", .{fs.path.stem(emit.sub_path)}) + else + null, .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, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, .zig_object = null, @@ -320,7 +293,6 @@ pub fn createEmpty( }; }, - .emit_relocs = options.emit_relocs, .z_nodelete = options.z_nodelete, .z_notext = options.z_notext, .z_defs = options.z_defs, @@ -330,30 +302,11 @@ pub fn createEmpty( .z_relro = options.z_relro, .z_common_page_size = options.z_common_page_size, .z_max_page_size = options.z_max_page_size, - .hash_style = options.hash_style, - .compress_debug_sections = options.compress_debug_sections, - .symbol_wrap_set = options.symbol_wrap_set, - .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, - .allow_undefined_version = options.allow_undefined_version, - .enable_new_dtags = options.enable_new_dtags, - .print_icf_sections = options.print_icf_sections, - .print_map = options.print_map, .dump_argv_list = .empty, }; - if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, comp); - } errdefer self.base.destroy(); - if (use_lld and (use_llvm or !comp.config.have_zcu)) { - // LLVM emits the object file (if any); LLD links it into the final product. - return self; - } - // --verbose-link if (comp.verbose_link) try dumpArgvInit(self, arena); @@ -361,13 +314,11 @@ pub fn createEmpty( const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .static); // What path should this ELF linker code output to? - // If using LLD to link, this code should produce an object file so that it - // can be passed to LLD. - const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; + const sub_path = emit.sub_path; self.base.file = try emit.root_dir.handle.createFile(sub_path, .{ .truncate = true, .read = true, - .mode = link.File.determineMode(use_lld, output_mode, link_mode), + .mode = link.File.determineMode(output_mode, link_mode), }); const gpa = comp.gpa; @@ -457,8 +408,6 @@ pub fn open( pub fn deinit(self: *Elf) void { const gpa = self.base.comp.gpa; - if (self.llvm_object) |llvm_object| llvm_object.deinit(); - for (self.file_handles.items) |fh| { fh.close(); } @@ -515,7 +464,6 @@ pub fn deinit(self: *Elf) void { } pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.zigObjectPtr().?.getNavVAddr(self, pt, nav_index, reloc_info); } @@ -530,7 +478,6 @@ pub fn lowerUav( } pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.zigObjectPtr().?.getUavVAddr(self, uav, reloc_info); } @@ -795,60 +742,36 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { } pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - const comp = self.base.comp; - const use_lld = build_options.have_llvm and comp.config.use_lld; - const diags = &comp.link_diags; - if (use_lld) { - return self.linkWithLLD(arena, tid, prog_node) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.LinkFailure => return error.LinkFailure, - else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), - }; - } - try self.flushModule(arena, tid, prog_node); -} - -pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { const tracy = trace(@src()); defer tracy.end(); const comp = self.base.comp; const diags = &comp.link_diags; - 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; - } - if (comp.verbose_link) Compilation.dump_argv(self.dump_argv_list.items); const sub_prog_node = prog_node.start("ELF Flush", 0); defer sub_prog_node.end(); - return flushModuleInner(self, arena, tid) catch |err| switch (err) { + return flushInner(self, arena, tid) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("ELF flush failed: {s}", .{@errorName(e)}), }; } -fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { +fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { const comp = self.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; - const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{ - .root_dir = self.base.emit.root_dir, - .sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname| - try fs.path.join(arena, &.{ dirname, path }) - else - path, + const zcu_obj_path: ?Path = if (self.base.zcu_object_basename) |raw| p: { + break :p try comp.resolveEmitPathFlush(arena, .temp, raw); } else null; if (self.zigObjectPtr()) |zig_object| try zig_object.flush(self, tid); - if (module_obj_path) |path| openParseObjectReportingFailure(self, path); + if (zcu_obj_path) |path| openParseObjectReportingFailure(self, path); switch (comp.config.output_mode) { .Obj => return relocatable.flushObject(self, comp), @@ -1508,639 +1431,6 @@ pub fn initOutputSection(self: *Elf, args: struct { return out_shndx; } -fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { - dev.check(.lld_linker); - - const tracy = trace(@src()); - defer tracy.end(); - - const comp = self.base.comp; - const gpa = comp.gpa; - const diags = &comp.link_diags; - - const directory = self.base.emit.root_dir; // 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. - const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { - try self.flushModule(arena, tid, prog_node); - - if (fs.path.dirname(full_out_path)) |dirname| { - break :blk try fs.path.join(arena, &.{ dirname, self.base.zcu_object_sub_path.? }); - } else { - break :blk self.base.zcu_object_sub_path.?; - } - } else null; - - const sub_prog_node = prog_node.start("LLD Link", 0); - defer sub_prog_node.end(); - - const output_mode = comp.config.output_mode; - const is_obj = output_mode == .Obj; - const is_lib = output_mode == .Lib; - const link_mode = 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 = link_mode == .dynamic and is_exe_or_dyn_lib; - const target = self.getTarget(); - const compiler_rt_path: ?Path = 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; - break :blk null; - }; - const ubsan_rt_path: ?Path = blk: { - if (comp.ubsan_rt_lib) |x| break :blk x.full_object_path; - if (comp.ubsan_rt_obj) |x| break :blk x.full_object_path; - break :blk null; - }; - - // Here we want to determine whether we can save time by not invoking LLD when the - // output is unchanged. None of the linker options or the object files that are being - // linked are in the hash that namespaces the directory we are outputting to. Therefore, - // we must hash those now, and the resulting digest will form the "id" of the linking - // job we are about to perform. - // After a successful link, we store the id in the metadata of a symlink named "lld.id" in - // the artifact directory. So, now, we check if this symlink exists, and if it matches - // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD. - const id_symlink_basename = "lld.id"; - - var man: std.Build.Cache.Manifest = undefined; - defer if (!self.base.disable_lld_caching) man.deinit(); - - var digest: [std.Build.Cache.hex_digest_len]u8 = undefined; - - 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. - self.base.releaseLock(); - - comptime assert(Compilation.link_hash_implementation_version == 14); - - try man.addOptionalFile(self.linker_script); - try man.addOptionalFile(self.version_script); - man.hash.add(self.allow_undefined_version); - man.hash.addOptional(self.enable_new_dtags); - try link.hashInputs(&man, comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - _ = try man.addFilePath(key.status.success.object_path, null); - } - try man.addOptionalFile(module_obj_path); - try man.addOptionalFilePath(compiler_rt_path); - try man.addOptionalFilePath(ubsan_rt_path); - try man.addOptionalFilePath(if (comp.tsan_lib) |l| l.full_object_path else null); - try man.addOptionalFilePath(if (comp.fuzzer_lib) |l| l.full_object_path else null); - - // 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.entry_name); - man.hash.add(self.image_base); - man.hash.add(self.base.gc_sections); - man.hash.addOptional(self.sort_section); - man.hash.add(comp.link_eh_frame_hdr); - man.hash.add(self.emit_relocs); - man.hash.add(comp.config.rdynamic); - man.hash.addListOfBytes(self.rpath_table.keys()); - if (output_mode == .Exe) { - man.hash.add(self.base.stack_size); - } - man.hash.add(self.base.build_id); - 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 (comp.config.link_libc) { - man.hash.add(comp.libc_installation != null); - if (comp.libc_installation) |libc_installation| { - man.hash.addBytes(libc_installation.crt_dir.?); - } - } - if (have_dynamic_linker) { - man.hash.addOptionalBytes(target.dynamic_linker.get()); - } - man.hash.addOptionalBytes(self.soname); - man.hash.addOptional(comp.version); - man.hash.addListOfBytes(comp.force_undefined_symbols.keys()); - man.hash.add(self.base.allow_shlib_undefined); - 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.add(comp.config.any_fuzz); - 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(); - digest = man.final(); - - var prev_digest_buf: [digest.len]u8 = undefined; - const prev_digest: []u8 = std.Build.Cache.readSmallFile( - directory.handle, - id_symlink_basename, - &prev_digest_buf, - ) catch |err| blk: { - log.debug("ELF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); - // Handle this as a cache miss. - break :blk prev_digest_buf[0..0]; - }; - if (mem.eql(u8, prev_digest, &digest)) { - log.debug("ELF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); - // Hot diggity dog! The output binary is already there. - self.base.lock = man.toOwnedLock(); - return; - } - log.debug("ELF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); - - // We are about to change the output file to be different, so we invalidate the build hash now. - directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { - error.FileNotFound => {}, - else => |e| return e, - }; - } - - // Due to a deficiency in LLD, we need to special-case BPF to a simple file - // 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. - // - // For m68k, we go through this path because LLD doesn't support it yet, but LLVM can - // produce usable object files. - if (output_mode == .Obj and - (comp.config.lto != .none or - target.cpu.arch.isBpf() or - target.cpu.arch == .lanai or - target.cpu.arch == .m68k or - target.cpu.arch.isSPARC() or - target.cpu.arch == .ve or - target.cpu.arch == .xcore)) - { - // 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 (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; - - if (module_obj_path) |p| - break :blk Path.initCwd(p); - - // TODO I think this is unreachable. Audit this situation when solving the above TODO - // regarding eliding redundant object -> object transformations. - return error.NoObjectsToLink; - }; - try std.fs.Dir.copyFile( - the_object_path.root_dir.handle, - the_object_path.sub_path, - directory.handle, - self.base.emit.sub_path, - .{}, - ); - } else { - // Create an LLD command line and invoke it. - 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 - - // it calls exit() and does not reset all global data between invocations. - const linker_command = "ld.lld"; - try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); - if (is_obj) { - try argv.append("-r"); - } - - try argv.append("--error-limit=0"); - - if (comp.sysroot) |sysroot| { - try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); - } - - if (target_util.llvmMachineAbi(target)) |mabi| { - try argv.appendSlice(&.{ - "-mllvm", - try std.fmt.allocPrint(arena, "-target-abi={s}", .{mabi}), - }); - } - - try argv.appendSlice(&.{ - "-mllvm", - try std.fmt.allocPrint(arena, "-float-abi={s}", .{if (target.abi.float() == .hard) "hard" else "soft"}), - }); - - if (comp.config.lto != .none) { - switch (comp.root_mod.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("--lto-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), - } - } - switch (comp.root_mod.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), - } - - if (self.entry_name) |name| { - try argv.appendSlice(&.{ "--entry", name }); - } - - for (comp.force_undefined_symbols.keys()) |sym| { - try argv.append("-u"); - try argv.append(sym); - } - - switch (self.hash_style) { - .gnu => try argv.append("--hash-style=gnu"), - .sysv => try argv.append("--hash-style=sysv"), - .both => {}, // this is the default - } - - if (output_mode == .Exe) { - try argv.appendSlice(&.{ - "-z", - try std.fmt.allocPrint(arena, "stack-size={d}", .{self.base.stack_size}), - }); - } - - switch (self.base.build_id) { - .none => try argv.append("--build-id=none"), - .fast, .uuid, .sha1, .md5 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ - @tagName(self.base.build_id), - })), - .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ - std.fmt.fmtSliceHexLower(hs.toSlice()), - })), - } - - try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{self.image_base})); - - if (self.linker_script) |linker_script| { - try argv.append("-T"); - try argv.append(linker_script); - } - - if (self.sort_section) |how| { - const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)}); - try argv.append(arg); - } - - if (self.base.gc_sections) { - try argv.append("--gc-sections"); - } - - if (self.base.print_gc_sections) { - try argv.append("--print-gc-sections"); - } - - if (self.print_icf_sections) { - try argv.append("--print-icf-sections"); - } - - if (self.print_map) { - try argv.append("--print-map"); - } - - if (comp.link_eh_frame_hdr) { - try argv.append("--eh-frame-hdr"); - } - - if (self.emit_relocs) { - try argv.append("--emit-relocs"); - } - - if (comp.config.rdynamic) { - try argv.append("--export-dynamic"); - } - - if (comp.config.debug_format == .strip) { - try argv.append("-s"); - } - - if (self.z_nodelete) { - try argv.append("-z"); - try argv.append("nodelete"); - } - if (self.z_notext) { - try argv.append("-z"); - try argv.append("notext"); - } - if (self.z_defs) { - try argv.append("-z"); - try argv.append("defs"); - } - if (self.z_origin) { - try argv.append("-z"); - try argv.append("origin"); - } - if (self.z_nocopyreloc) { - try argv.append("-z"); - try argv.append("nocopyreloc"); - } - if (self.z_now) { - // LLD defaults to -zlazy - try argv.append("-znow"); - } - if (!self.z_relro) { - // LLD defaults to -zrelro - try argv.append("-znorelro"); - } - 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.z_max_page_size) |size| { - try argv.append("-z"); - try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size})); - } - - if (getLDMOption(target)) |ldm| { - try argv.append("-m"); - try argv.append(ldm); - } - - if (link_mode == .static) { - if (target.cpu.arch.isArm()) { - try argv.append("-Bstatic"); - } else { - try argv.append("-static"); - } - } else if (switch (target.os.tag) { - else => is_dyn_lib, - .haiku => is_exe_or_dyn_lib, - }) { - try argv.append("-shared"); - } - - if (comp.config.pie and output_mode == .Exe) { - try argv.append("-pie"); - } - - if (is_exe_or_dyn_lib and target.os.tag == .netbsd) { - // Add options to produce shared objects with only 2 PT_LOAD segments. - // NetBSD expects 2 PT_LOAD segments in a shared object, otherwise - // ld.elf_so fails loading dynamic libraries with "not found" error. - // See https://github.com/ziglang/zig/issues/9109 . - try argv.append("--no-rosegment"); - try argv.append("-znorelro"); - } - - try argv.append("-o"); - try argv.append(full_out_path); - - // csu prelude - const csu = try comp.getCrtPaths(arena); - if (csu.crt0) |p| try argv.append(try p.toString(arena)); - if (csu.crti) |p| try argv.append(try p.toString(arena)); - if (csu.crtbegin) |p| try argv.append(try p.toString(arena)); - - for (self.rpath_table.keys()) |rpath| { - try argv.appendSlice(&.{ "-rpath", rpath }); - } - - for (self.symbol_wrap_set.keys()) |symbol_name| { - try argv.appendSlice(&.{ "-wrap", symbol_name }); - } - - if (comp.config.link_libc) { - if (comp.libc_installation) |libc_installation| { - try argv.append("-L"); - try argv.append(libc_installation.crt_dir.?); - } - } - - if (have_dynamic_linker and - (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker)) - { - if (target.dynamic_linker.get()) |dynamic_linker| { - try argv.append("-dynamic-linker"); - try argv.append(dynamic_linker); - } - } - - if (is_dyn_lib) { - if (self.soname) |soname| { - try argv.append("-soname"); - try argv.append(soname); - } - if (self.version_script) |version_script| { - try argv.append("-version-script"); - try argv.append(version_script); - } - if (self.allow_undefined_version) { - try argv.append("--undefined-version"); - } else { - try argv.append("--no-undefined-version"); - } - if (self.enable_new_dtags) |enable_new_dtags| { - if (enable_new_dtags) { - try argv.append("--enable-new-dtags"); - } else { - try argv.append("--disable-new-dtags"); - } - } - } - - // Positional arguments to the linker such as object files. - var whole_archive = false; - - for (self.base.comp.link_inputs) |link_input| switch (link_input) { - .res => unreachable, // Windows-only - .dso => continue, - .object, .archive => |obj| { - if (obj.must_link and !whole_archive) { - try argv.append("-whole-archive"); - whole_archive = true; - } else if (!obj.must_link and whole_archive) { - try argv.append("-no-whole-archive"); - whole_archive = false; - } - try argv.append(try obj.path.toString(arena)); - }, - .dso_exact => |dso_exact| { - assert(dso_exact.name[0] == ':'); - try argv.appendSlice(&.{ "-l", dso_exact.name }); - }, - }; - - if (whole_archive) { - try argv.append("-no-whole-archive"); - whole_archive = false; - } - - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); - } - - if (module_obj_path) |p| { - try argv.append(p); - } - - if (comp.tsan_lib) |lib| { - assert(comp.config.any_sanitize_thread); - try argv.append(try lib.full_object_path.toString(arena)); - } - - if (comp.fuzzer_lib) |lib| { - assert(comp.config.any_fuzz); - try argv.append(try lib.full_object_path.toString(arena)); - } - - if (ubsan_rt_path) |p| { - try argv.append(try p.toString(arena)); - } - - // Shared libraries. - if (is_exe_or_dyn_lib) { - // Worst-case, we need an --as-needed argument for every lib, as well - // as one before and one after. - try argv.ensureUnusedCapacity(2 * self.base.comp.link_inputs.len + 2); - argv.appendAssumeCapacity("--as-needed"); - var as_needed = true; - - for (self.base.comp.link_inputs) |link_input| switch (link_input) { - .res => unreachable, // Windows-only - .object, .archive, .dso_exact => continue, - .dso => |dso| { - const lib_as_needed = !dso.needed; - switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { - 0b00, 0b11 => {}, - 0b01 => { - argv.appendAssumeCapacity("--no-as-needed"); - as_needed = false; - }, - 0b10 => { - argv.appendAssumeCapacity("--as-needed"); - as_needed = true; - }, - } - - // By this time, we depend on these libs being dynamically linked - // libraries and not static libraries (the check for that needs to be earlier), - // but they could be full paths to .so files, in which case we - // want to avoid prepending "-l". - argv.appendAssumeCapacity(try dso.path.toString(arena)); - }, - }; - - if (!as_needed) { - argv.appendAssumeCapacity("--as-needed"); - as_needed = true; - } - - // libc++ dep - if (comp.config.link_libcpp) { - try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); - try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); - } - - // libunwind dep - if (comp.config.link_libunwind) { - try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); - } - - // libc dep - diags.flags.missing_libc = false; - if (comp.config.link_libc) { - if (comp.libc_installation != null) { - 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"); - } else if (target.isGnuLibC()) { - for (glibc.libs) |lib| { - if (lib.removed_in) |rem_in| { - if (target.os.versionRange().gnuLibCVersion().?.order(rem_in) != .lt) continue; - } - - const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{ - comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, - }); - try argv.append(lib_path); - } - try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a")); - } else if (target.isMuslLibC()) { - try argv.append(try comp.crtFileAsString(arena, switch (link_mode) { - .static => "libc.a", - .dynamic => "libc.so", - })); - } else if (target.isFreeBSDLibC()) { - for (freebsd.libs) |lib| { - const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{ - comp.freebsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, - }); - try argv.append(lib_path); - } - } else if (target.isNetBSDLibC()) { - for (netbsd.libs) |lib| { - const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{ - comp.netbsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, - }); - try argv.append(lib_path); - } - } else { - diags.flags.missing_libc = true; - } - - if (comp.zigc_static_lib) |zigc| { - try argv.append(try zigc.full_object_path.toString(arena)); - } - } - } - - // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs - // to be after the shared libraries, so they are picked up from the shared - // libraries, not libcompiler_rt. - if (compiler_rt_path) |p| { - try argv.append(try p.toString(arena)); - } - - // crt postlude - if (csu.crtend) |p| try argv.append(try p.toString(arena)); - if (csu.crtn) |p| try argv.append(try p.toString(arena)); - - if (self.base.allow_shlib_undefined) { - try argv.append("--allow-shlib-undefined"); - } - - switch (self.compress_debug_sections) { - .none => {}, - .zlib => try argv.append("--compress-debug-sections=zlib"), - .zstd => try argv.append("--compress-debug-sections=zstd"), - } - - if (self.bind_global_refs_locally) { - try argv.append("-Bsymbolic"); - } - - try link.spawnLld(comp, arena, argv.items); - } - - 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. - std.Build.Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { - log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)}); - }; - // Again failure here only means an unnecessary cache miss. - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); - }; - // We hang on to this lock so that the output file path can be used without - // other processes clobbering it. - self.base.lock = man.toOwnedLock(); - } -} - pub fn writeShdrTable(self: *Elf) !void { const gpa = self.base.comp.gpa; const target_endian = self.getTarget().cpu.arch.endian(); @@ -2385,7 +1675,6 @@ pub fn writeElfHeader(self: *Elf) !void { } pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void { - if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav); return self.zigObjectPtr().?.freeNav(self, nav); } @@ -2393,14 +1682,12 @@ pub fn updateFunc( self: *Elf, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); - return self.zigObjectPtr().?.updateFunc(self, pt, func_index, air, liveness); + return self.zigObjectPtr().?.updateFunc(self, pt, func_index, mir); } pub fn updateNav( @@ -2411,7 +1698,6 @@ pub fn updateNav( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav); return self.zigObjectPtr().?.updateNav(self, pt, nav); } @@ -2423,7 +1709,6 @@ pub fn updateContainerType( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |_| return; const zcu = pt.zcu; const gpa = zcu.gpa; return self.zigObjectPtr().?.updateContainerType(pt, ty) catch |err| switch (err) { @@ -2449,12 +1734,10 @@ pub fn updateExports( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices); } pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { - if (self.llvm_object) |_| return; return self.zigObjectPtr().?.updateLineNumber(pt, ti_id); } @@ -2463,7 +1746,6 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (self.llvm_object) |_| return; return self.zigObjectPtr().?.deleteExport(self, exported, name); } @@ -4140,85 +3422,6 @@ fn shdrTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { }; } -fn getLDMOption(target: std.Target) ?[]const u8 { - // This should only return emulations understood by LLD's parseEmulation(). - return switch (target.cpu.arch) { - .aarch64 => switch (target.os.tag) { - .linux => "aarch64linux", - else => "aarch64elf", - }, - .aarch64_be => switch (target.os.tag) { - .linux => "aarch64linuxb", - else => "aarch64elfb", - }, - .amdgcn => "elf64_amdgpu", - .arm, .thumb => switch (target.os.tag) { - .linux => "armelf_linux_eabi", - else => "armelf", - }, - .armeb, .thumbeb => switch (target.os.tag) { - .linux => "armelfb_linux_eabi", - else => "armelfb", - }, - .hexagon => "hexagonelf", - .loongarch32 => "elf32loongarch", - .loongarch64 => "elf64loongarch", - .mips => switch (target.os.tag) { - .freebsd => "elf32btsmip_fbsd", - else => "elf32btsmip", - }, - .mipsel => switch (target.os.tag) { - .freebsd => "elf32ltsmip_fbsd", - else => "elf32ltsmip", - }, - .mips64 => switch (target.os.tag) { - .freebsd => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32btsmipn32_fbsd", - else => "elf64btsmip_fbsd", - }, - else => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32btsmipn32", - else => "elf64btsmip", - }, - }, - .mips64el => switch (target.os.tag) { - .freebsd => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32ltsmipn32_fbsd", - else => "elf64ltsmip_fbsd", - }, - else => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32ltsmipn32", - else => "elf64ltsmip", - }, - }, - .msp430 => "msp430elf", - .powerpc => switch (target.os.tag) { - .freebsd => "elf32ppc_fbsd", - .linux => "elf32ppclinux", - else => "elf32ppc", - }, - .powerpcle => switch (target.os.tag) { - .linux => "elf32lppclinux", - else => "elf32lppc", - }, - .powerpc64 => "elf64ppc", - .powerpc64le => "elf64lppc", - .riscv32 => "elf32lriscv", - .riscv64 => "elf64lriscv", - .s390x => "elf64_s390", - .sparc64 => "elf64_sparc", - .x86 => switch (target.os.tag) { - .freebsd => "elf_i386_fbsd", - else => "elf_i386", - }, - .x86_64 => switch (target.abi) { - .gnux32, .muslx32 => "elf32_x86_64", - else => "elf_x86_64", - }, - else => null, - }; -} - pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { return actual_size +| (actual_size / ideal_factor); } @@ -5303,10 +4506,7 @@ const codegen = @import("../codegen.zig"); const dev = @import("../dev.zig"); const eh_frame = @import("Elf/eh_frame.zig"); const gc = @import("Elf/gc.zig"); -const glibc = @import("../libs/glibc.zig"); const musl = @import("../libs/musl.zig"); -const freebsd = @import("../libs/freebsd.zig"); -const netbsd = @import("../libs/netbsd.zig"); const link = @import("../link.zig"); const relocatable = @import("Elf/relocatable.zig"); const relocation = @import("Elf/relocation.zig"); @@ -5315,7 +4515,6 @@ const trace = @import("../tracy.zig").trace; const synthetic_sections = @import("Elf/synthetic_sections.zig"); const Merge = @import("Elf/Merge.zig"); -const Air = @import("../Air.zig"); const Archive = @import("Elf/Archive.zig"); const AtomList = @import("Elf/AtomList.zig"); const Compilation = @import("../Compilation.zig"); @@ -5332,7 +4531,6 @@ const GotSection = synthetic_sections.GotSection; const GotPltSection = synthetic_sections.GotPltSection; const HashSection = synthetic_sections.HashSection; const LinkerDefined = @import("Elf/LinkerDefined.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; const Zcu = @import("../Zcu.zig"); const Object = @import("Elf/Object.zig"); const InternPool = @import("../InternPool.zig"); diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 31584ca406ce..843c23dca494 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -462,9 +462,6 @@ pub const Flags = packed struct { /// Whether the symbol is a TLS variable. is_tls: bool = false, - - /// Whether the symbol is an extern pointer (as opposed to function). - is_extern_ptr: bool = false, }; pub const Extra = struct { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 13816940fe15..71b42819e290 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -310,7 +310,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { if (self.dwarf) |*dwarf| { const pt: Zcu.PerThread = .activate(elf_file.base.comp.zcu.?, tid); defer pt.deactivate(); - try dwarf.flushModule(pt); + try dwarf.flush(pt); const gpa = elf_file.base.comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; @@ -481,7 +481,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { self.debug_str_section_dirty = false; } - // The point of flushModule() is to commit changes, so in theory, nothing should + // The point of flush() is to commit changes, so in theory, nothing should // be dirty after this. However, it is possible for some things to remain // dirty because they fail to be written in the event of compile errors, // such as debug_line_header_dirty and debug_info_header_dirty. @@ -661,7 +661,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void { if (shdr.sh_type == elf.SHT_NOBITS) continue; if (atom_ptr.scanRelocsRequiresCode(elf_file)) { // TODO ideally we don't have to fetch the code here. - // Perhaps it would make sense to save the code until flushModule where we + // Perhaps it would make sense to save the code until flush where we // would free all of generated code? const code = try self.codeAlloc(elf_file, atom_index); defer gpa.free(code); @@ -1075,7 +1075,7 @@ pub fn getOrCreateMetadataForLazySymbol( } state_ptr.* = .pending_flush; const symbol_index = symbol_index_ptr.*; - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flush if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(elf_file, pt, lazy_sym, symbol_index); return symbol_index; } @@ -1142,7 +1142,6 @@ fn getNavShdrIndex( const gpa = elf_file.base.comp.gpa; const ptr_size = elf_file.ptrWidthBytes(); const ip = &zcu.intern_pool; - const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; const nav_val = zcu.navValue(nav_index); if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) { if (self.text_index) |symbol_index| @@ -1162,7 +1161,7 @@ fn getNavShdrIndex( else => .{ true, false, nav_val.toIntern() }, }; const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0; - if (any_non_single_threaded and is_threadlocal) { + if (is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) { const is_bss = !has_relocs and for (code) |byte| { if (byte != 0) break false; } else true; @@ -1416,8 +1415,7 @@ pub fn updateFunc( elf_file: *Elf, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { const tracy = trace(@src()); defer tracy.end(); @@ -1438,13 +1436,12 @@ pub fn updateFunc( var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); - try codegen.generateFunction( + try codegen.emitFunction( &elf_file.base, pt, zcu.navSrcLoc(func.owner_nav), func_index, - air, - liveness, + mir, &code_buffer, if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none, ); @@ -1544,11 +1541,7 @@ pub fn updateNav( nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip), ); - if (!ip.isFunctionType(@"extern".ty)) { - const sym = self.symbol(sym_index); - sym.flags.is_extern_ptr = true; - if (@"extern".is_threadlocal) sym.flags.is_tls = true; - } + if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true; if (self.dwarf) |*dwarf| dwarf: { var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf; defer debug_wip_nav.deinit(); @@ -2361,7 +2354,6 @@ const trace = @import("../../tracy.zig").trace; const std = @import("std"); const Allocator = std.mem.Allocator; -const Air = @import("../../Air.zig"); const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); const Dwarf = @import("../Dwarf.zig"); diff --git a/src/link/Goff.zig b/src/link/Goff.zig index 6ed360be258b..1f4a7a4d3095 100644 --- a/src/link/Goff.zig +++ b/src/link/Goff.zig @@ -13,14 +13,12 @@ const Path = std.Build.Cache.Path; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); const Compilation = @import("../Compilation.zig"); +const codegen = @import("../codegen.zig"); const link = @import("../link.zig"); const trace = @import("../tracy.zig").trace; const build_options = @import("build_options"); -const Air = @import("../Air.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, -llvm_object: LlvmObject.Ptr, pub fn createEmpty( arena: Allocator, @@ -36,23 +34,20 @@ pub fn createEmpty( assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve. - const llvm_object = try LlvmObject.create(arena, comp); const goff = try arena.create(Goff); goff.* = .{ .base = .{ .tag = .goff, .comp = comp, .emit = emit, - .zcu_object_sub_path = emit.sub_path, + .zcu_object_basename = emit.sub_path, .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, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, - .llvm_object = llvm_object, }; return goff; @@ -70,27 +65,27 @@ pub fn open( } pub fn deinit(self: *Goff) void { - self.llvm_object.deinit(); + _ = self; } pub fn updateFunc( self: *Goff, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - try self.llvm_object.updateFunc(pt, func_index, air, liveness); + _ = self; + _ = pt; + _ = func_index; + _ = mir; + unreachable; // we always use llvm } pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateNav(pt, nav); + _ = self; + _ = pt; + _ = nav; + unreachable; // we always use llvm } pub fn updateExports( @@ -99,21 +94,19 @@ pub fn updateExports( exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, ) !void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateExports(pt, exported, export_indices); + _ = self; + _ = pt; + _ = exported; + _ = export_indices; + unreachable; // we always use llvm } pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); -} - -pub fn flushModule(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { if (build_options.skip_non_native and builtin.object_format != .goff) @panic("Attempted to compile for object format that was disabled by build configuration"); + _ = self; + _ = arena; _ = tid; - - try self.base.emitLlvmObject(arena, self.llvm_object, prog_node); + _ = prog_node; } diff --git a/src/link/Lld.zig b/src/link/Lld.zig new file mode 100644 index 000000000000..4ea809428e58 --- /dev/null +++ b/src/link/Lld.zig @@ -0,0 +1,1757 @@ +base: link.File, +ofmt: union(enum) { + elf: Elf, + coff: Coff, + wasm: Wasm, +}, + +const Coff = struct { + image_base: u64, + entry: link.File.OpenOptions.Entry, + pdb_out_path: ?[]const u8, + repro: bool, + 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: u16, + minor_subsystem_version: u16, + lib_directories: []const Cache.Directory, + module_definition_file: ?[]const u8, + subsystem: ?std.Target.SubSystem, + /// These flags are populated by `codegen.llvm.updateExports` to allow us to guess the subsystem. + lld_export_flags: struct { + c_main: bool, + winmain: bool, + wwinmain: bool, + winmain_crt_startup: bool, + wwinmain_crt_startup: bool, + dllmain_crt_startup: bool, + }, + fn init(comp: *Compilation, options: link.File.OpenOptions) !Coff { + const target = comp.root_mod.resolved_target.result; + const output_mode = comp.config.output_mode; + return .{ + .image_base = options.image_base orelse switch (output_mode) { + .Exe => switch (target.cpu.arch) { + .aarch64, .x86_64 => 0x140000000, + .thumb, .x86 => 0x400000, + else => unreachable, + }, + .Lib => switch (target.cpu.arch) { + .aarch64, .x86_64 => 0x180000000, + .thumb, .x86 => 0x10000000, + else => unreachable, + }, + .Obj => 0, + }, + .entry = options.entry, + .pdb_out_path = options.pdb_out_path, + .repro = options.repro, + .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_directories = options.lib_directories, + .module_definition_file = options.module_definition_file, + // Subsystem depends on the set of public symbol names from linked objects. + // See LinkerDriver::inferSubsystem from the LLD project for the flow chart. + .subsystem = options.subsystem, + // These flags are initially all `false`; the LLVM backend populates them when it learns about exports. + .lld_export_flags = .{ + .c_main = false, + .winmain = false, + .wwinmain = false, + .winmain_crt_startup = false, + .wwinmain_crt_startup = false, + .dllmain_crt_startup = false, + }, + }; + } +}; +pub const Elf = struct { + entry_name: ?[]const u8, + hash_style: HashStyle, + image_base: u64, + linker_script: ?[]const u8, + version_script: ?[]const u8, + sort_section: ?SortSection, + print_icf_sections: bool, + print_map: 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, + z_common_page_size: ?u64, + z_max_page_size: ?u64, + rpath_list: []const []const u8, + symbol_wrap_set: []const []const u8, + soname: ?[]const u8, + allow_undefined_version: bool, + enable_new_dtags: ?bool, + compress_debug_sections: CompressDebugSections, + bind_global_refs_locally: bool, + pub const HashStyle = enum { sysv, gnu, both }; + pub const SortSection = enum { name, alignment }; + pub const CompressDebugSections = enum { none, zlib, zstd }; + + fn init(comp: *Compilation, options: link.File.OpenOptions) !Elf { + const PtrWidth = enum { p32, p64 }; + const target = comp.root_mod.resolved_target.result; + const output_mode = comp.config.output_mode; + const is_dyn_lib = output_mode == .Lib and comp.config.link_mode == .dynamic; + const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { + 0...32 => .p32, + 33...64 => .p64, + else => return error.UnsupportedElfArchitecture, + }; + const default_entry_name: []const u8 = switch (target.cpu.arch) { + .mips, .mipsel, .mips64, .mips64el => "__start", + else => "_start", + }; + return .{ + .entry_name = switch (options.entry) { + .disabled => null, + .default => if (output_mode != .Exe) null else default_entry_name, + .enabled => default_entry_name, + .named => |name| name, + }, + .hash_style = options.hash_style, + .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 => 0x10000, + .p64 => 0x1000000, + }; + }, + .linker_script = options.linker_script, + .version_script = options.version_script, + .sort_section = options.sort_section, + .print_icf_sections = options.print_icf_sections, + .print_map = options.print_map, + .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, + .rpath_list = options.rpath_list, + .symbol_wrap_set = options.symbol_wrap_set.keys(), + .soname = options.soname, + .allow_undefined_version = options.allow_undefined_version, + .enable_new_dtags = options.enable_new_dtags, + .compress_debug_sections = options.compress_debug_sections, + .bind_global_refs_locally = options.bind_global_refs_locally, + }; + } +}; +const Wasm = struct { + /// Symbol name of the entry function to export + entry_name: ?[]const u8, + /// When true, will import the function table from the host environment. + import_table: bool, + /// When true, will export the function table to the host environment. + export_table: bool, + /// When defined, sets the initial memory size of the memory. + initial_memory: ?u64, + /// When defined, sets the maximum memory size of the memory. + max_memory: ?u64, + /// When defined, sets the start of the data section. + global_base: ?u64, + /// Set of *global* symbol names to export to the host environment. + export_symbol_names: []const []const u8, + /// When true, will allow undefined symbols + import_symbols: bool, + fn init(comp: *Compilation, options: link.File.OpenOptions) !Wasm { + const default_entry_name: []const u8 = switch (comp.config.wasi_exec_model) { + .reactor => "_initialize", + .command => "_start", + }; + return .{ + .entry_name = switch (options.entry) { + .disabled => null, + .default => if (comp.config.output_mode != .Exe) null else default_entry_name, + .enabled => default_entry_name, + .named => |name| name, + }, + .import_table = options.import_table, + .export_table = options.export_table, + .initial_memory = options.initial_memory, + .max_memory = options.max_memory, + .global_base = options.global_base, + .export_symbol_names = options.export_symbol_names, + .import_symbols = options.import_symbols, + }; + } +}; + +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Cache.Path, + options: link.File.OpenOptions, +) !*Lld { + const target = comp.root_mod.resolved_target.result; + const output_mode = comp.config.output_mode; + const optimize_mode = comp.root_mod.optimize_mode; + const is_native_os = comp.root_mod.resolved_target.is_native_os; + + const obj_file_ext: []const u8 = switch (target.ofmt) { + .coff => "obj", + .elf, .wasm => "o", + else => unreachable, + }; + const gc_sections: bool = options.gc_sections orelse switch (target.ofmt) { + .coff => optimize_mode != .Debug, + .elf => optimize_mode != .Debug and output_mode != .Obj, + .wasm => output_mode != .Obj, + else => unreachable, + }; + const stack_size: u64 = options.stack_size orelse default: { + if (target.ofmt == .wasm and target.os.tag == .freestanding) + break :default 1 * 1024 * 1024; // 1 MiB + break :default 16 * 1024 * 1024; // 16 MiB + }; + + const lld = try arena.create(Lld); + lld.* = .{ + .base = .{ + .tag = .lld, + .comp = comp, + .emit = emit, + .zcu_object_basename = try allocPrint(arena, "{s}_zcu.{s}", .{ fs.path.stem(emit.sub_path), obj_file_ext }), + .gc_sections = gc_sections, + .print_gc_sections = options.print_gc_sections, + .stack_size = stack_size, + .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os, + .file = null, + .build_id = options.build_id, + }, + .ofmt = switch (target.ofmt) { + .coff => .{ .coff = try .init(comp, options) }, + .elf => .{ .elf = try .init(comp, options) }, + .wasm => .{ .wasm = try .init(comp, options) }, + else => unreachable, + }, + }; + return lld; +} +pub fn deinit(lld: *Lld) void { + _ = lld; +} +pub fn flush( + lld: *Lld, + arena: Allocator, + tid: Zcu.PerThread.Id, + prog_node: std.Progress.Node, +) link.File.FlushError!void { + dev.check(.lld_linker); + _ = tid; + + const tracy = trace(@src()); + defer tracy.end(); + + const sub_prog_node = prog_node.start("LLD Link", 0); + defer sub_prog_node.end(); + + const comp = lld.base.comp; + const result = if (comp.config.output_mode == .Lib and comp.config.link_mode == .static) r: { + if (!@import("build_options").have_llvm or !comp.config.use_lib_llvm) { + return lld.base.comp.link_diags.fail("using lld without libllvm not implemented", .{}); + } + break :r linkAsArchive(lld, arena); + } else switch (lld.ofmt) { + .coff => coffLink(lld, arena), + .elf => elfLink(lld, arena), + .wasm => wasmLink(lld, arena), + }; + result catch |err| switch (err) { + error.OutOfMemory, error.LinkFailure => |e| return e, + else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), + }; +} + +fn linkAsArchive(lld: *Lld, arena: Allocator) !void { + const base = &lld.base; + const comp = base.comp; + const directory = base.emit.root_dir; // 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 = comp.zcu; + + const zcu_obj_path: ?Cache.Path = if (opt_zcu != null) p: { + break :p try comp.resolveEmitPathFlush(arena, .temp, base.zcu_object_basename.?); + } else null; + + log.debug("zcu_obj_path={?}", .{zcu_obj_path}); + + const compiler_rt_path: ?Cache.Path = if (comp.compiler_rt_strat == .obj) + comp.compiler_rt_obj.?.full_object_path + else + null; + + const ubsan_rt_path: ?Cache.Path = if (comp.ubsan_rt_strat == .obj) + comp.ubsan_rt_obj.?.full_object_path + else + null; + + // This function follows the same pattern as link.Elf.linkWithLLD so if you want some + // insight as to what's going on here you can read that function body which is more + // well-commented. + + const link_inputs = comp.link_inputs; + + var object_files: std.ArrayListUnmanaged([*:0]const u8) = .empty; + + try object_files.ensureUnusedCapacity(arena, link_inputs.len); + for (link_inputs) |input| { + object_files.appendAssumeCapacity(try input.path().?.toStringZ(arena)); + } + + try object_files.ensureUnusedCapacity(arena, comp.c_object_table.count() + + comp.win32_resource_table.count() + 2); + + for (comp.c_object_table.keys()) |key| { + object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena)); + } + for (comp.win32_resource_table.keys()) |key| { + object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path)); + } + if (zcu_obj_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); + if (compiler_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); + if (ubsan_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); + + if (comp.verbose_link) { + std.debug.print("ar rcs {s}", .{full_out_path_z}); + for (object_files.items) |arg| { + std.debug.print(" {s}", .{arg}); + } + std.debug.print("\n", .{}); + } + + const llvm_bindings = @import("../codegen/llvm/bindings.zig"); + const llvm = @import("../codegen/llvm.zig"); + const target = comp.root_mod.resolved_target.result; + llvm.initializeLLVMTarget(target.cpu.arch); + const bad = llvm_bindings.WriteArchive( + full_out_path_z, + object_files.items.ptr, + object_files.items.len, + switch (target.os.tag) { + .aix => .AIXBIG, + .windows => .COFF, + else => if (target.os.tag.isDarwin()) .DARWIN else .GNU, + }, + ); + if (bad) return error.UnableToWriteArchive; +} + +fn coffLink(lld: *Lld, arena: Allocator) !void { + const comp = lld.base.comp; + const gpa = comp.gpa; + const base = &lld.base; + const coff = &lld.ofmt.coff; + + const directory = base.emit.root_dir; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); + + const zcu_obj_path: ?Cache.Path = if (comp.zcu != null) p: { + break :p try comp.resolveEmitPathFlush(arena, .temp, base.zcu_object_basename.?); + } else null; + + 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 = comp.root_mod.resolved_target.result; + const optimize_mode = comp.root_mod.optimize_mode; + const entry_name: ?[]const u8 = switch (coff.entry) { + // This logic isn't quite right for disabled or enabled. No point in fixing it + // when the goal is to eliminate dependency on LLD anyway. + // https://github.com/ziglang/zig/issues/17751 + .disabled, .default, .enabled => null, + .named => |name| name, + }; + + 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. + const the_object_path = blk: { + if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; + + if (comp.c_object_table.count() != 0) + break :blk comp.c_object_table.keys()[0].status.success.object_path; + + if (zcu_obj_path) |p| + break :blk p; + + // TODO I think this is unreachable. Audit this situation when solving the above TODO + // regarding eliding redundant object -> object transformations. + return error.NoObjectsToLink; + }; + try std.fs.Dir.copyFile( + the_object_path.root_dir.handle, + the_object_path.sub_path, + directory.handle, + base.emit.sub_path, + .{}, + ); + } else { + // Create an LLD command line and invoke it. + 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 - + // it calls exit() and does not reset all global data between invocations. + const linker_command = "lld-link"; + try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); + + if (target.isMinGW()) { + try argv.append("-lldmingw"); + } + + try argv.append("-ERRORLIMIT:0"); + try argv.append("-NOLOGO"); + if (comp.config.debug_format != .strip) { + try argv.append("-DEBUG"); + + const out_ext = std.fs.path.extension(full_out_path); + const out_pdb = coff.pdb_out_path orelse try allocPrint(arena, "{s}.pdb", .{ + full_out_path[0 .. full_out_path.len - out_ext.len], + }); + const out_pdb_basename = std.fs.path.basename(out_pdb); + + try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); + try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb_basename})); + } + if (comp.version) |version| { + try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); + } + + if (target_util.llvmMachineAbi(target)) |mabi| { + try argv.append(try allocPrint(arena, "-MLLVM:-target-abi={s}", .{mabi})); + } + + try argv.append(try allocPrint(arena, "-MLLVM:-float-abi={s}", .{if (target.abi.float() == .hard) "hard" else "soft"})); + + if (comp.config.lto != .none) { + switch (optimize_mode) { + .Debug => {}, + .ReleaseSmall => try argv.append("-OPT:lldlto=2"), + .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), + } + } + if (comp.config.output_mode == .Exe) { + try argv.append(try allocPrint(arena, "-STACK:{d}", .{base.stack_size})); + } + try argv.append(try allocPrint(arena, "-BASE:{d}", .{coff.image_base})); + + switch (base.build_id) { + .none => try argv.append("-BUILD-ID:NO"), + .fast => try argv.append("-BUILD-ID"), + .uuid, .sha1, .md5, .hexstring => {}, + } + + if (target.cpu.arch == .x86) { + try argv.append("-MACHINE:X86"); + } else if (target.cpu.arch == .x86_64) { + try argv.append("-MACHINE:X64"); + } else if (target.cpu.arch == .thumb) { + try argv.append("-MACHINE:ARM"); + } else if (target.cpu.arch == .aarch64) { + try argv.append("-MACHINE:ARM64"); + } + + for (comp.force_undefined_symbols.keys()) |symbol| { + try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol})); + } + + if (is_dyn_lib) { + try argv.append("-DLL"); + } + + if (entry_name) |name| { + try argv.append(try allocPrint(arena, "-ENTRY:{s}", .{name})); + } + + if (coff.repro) { + try argv.append("-BREPRO"); + } + + if (coff.tsaware) { + try argv.append("-tsaware"); + } + if (coff.nxcompat) { + try argv.append("-nxcompat"); + } + if (!coff.dynamicbase) { + try argv.append("-dynamicbase:NO"); + } + if (base.allow_shlib_undefined) { + try argv.append("-FORCE:UNRESOLVED"); + } + + try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); + + if (comp.emit_implib) |raw_emit_path| { + const path = try comp.resolveEmitPathFlush(arena, .temp, raw_emit_path); + try argv.append(try allocPrint(arena, "-IMPLIB:{}", .{path})); + } + + if (comp.config.link_libc) { + if (comp.libc_installation) |libc_installation| { + try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?})); + + if (target.abi == .msvc or target.abi == .itanium) { + try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?})); + try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?})); + } + } + } + + for (coff.lib_directories) |lib_directory| { + try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{lib_directory.path orelse "."})); + } + + try argv.ensureUnusedCapacity(comp.link_inputs.len); + for (comp.link_inputs) |link_input| switch (link_input) { + .dso_exact => unreachable, // not applicable to PE/COFF + inline .dso, .res => |x| { + argv.appendAssumeCapacity(try x.path.toString(arena)); + }, + .object, .archive => |obj| { + if (obj.must_link) { + argv.appendAssumeCapacity(try allocPrint(arena, "-WHOLEARCHIVE:{}", .{@as(Cache.Path, obj.path)})); + } else { + argv.appendAssumeCapacity(try obj.path.toString(arena)); + } + }, + }; + + for (comp.c_object_table.keys()) |key| { + try argv.append(try key.status.success.object_path.toString(arena)); + } + + for (comp.win32_resource_table.keys()) |key| { + try argv.append(key.status.success.res_path); + } + + if (zcu_obj_path) |p| { + try argv.append(try p.toString(arena)); + } + + if (coff.module_definition_file) |def| { + try argv.append(try allocPrint(arena, "-DEF:{s}", .{def})); + } + + const resolved_subsystem: ?std.Target.SubSystem = blk: { + if (coff.subsystem) |explicit| break :blk explicit; + switch (target.os.tag) { + .windows => { + if (comp.zcu != null) { + if (coff.lld_export_flags.dllmain_crt_startup or is_dyn_lib) + break :blk null; + if (coff.lld_export_flags.c_main or comp.config.is_test or + coff.lld_export_flags.winmain_crt_startup or + coff.lld_export_flags.wwinmain_crt_startup) + { + break :blk .Console; + } + if (coff.lld_export_flags.winmain or coff.lld_export_flags.wwinmain) + break :blk .Windows; + } + }, + .uefi => break :blk .EfiApplication, + else => {}, + } + break :blk null; + }; + + const Mode = enum { uefi, win32 }; + const mode: Mode = mode: { + if (resolved_subsystem) |subsystem| { + const subsystem_suffix = try allocPrint(arena, ",{d}.{d}", .{ + coff.major_subsystem_version, coff.minor_subsystem_version, + }); + + switch (subsystem) { + .Console => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:console{s}", .{ + subsystem_suffix, + })); + break :mode .win32; + }, + .EfiApplication => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_application{s}", .{ + subsystem_suffix, + })); + break :mode .uefi; + }, + .EfiBootServiceDriver => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_boot_service_driver{s}", .{ + subsystem_suffix, + })); + break :mode .uefi; + }, + .EfiRom => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_rom{s}", .{ + subsystem_suffix, + })); + break :mode .uefi; + }, + .EfiRuntimeDriver => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_runtime_driver{s}", .{ + subsystem_suffix, + })); + break :mode .uefi; + }, + .Native => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:native{s}", .{ + subsystem_suffix, + })); + break :mode .win32; + }, + .Posix => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:posix{s}", .{ + subsystem_suffix, + })); + break :mode .win32; + }, + .Windows => { + try argv.append(try allocPrint(arena, "-SUBSYSTEM:windows{s}", .{ + subsystem_suffix, + })); + break :mode .win32; + }, + } + } else if (target.os.tag == .uefi) { + break :mode .uefi; + } else { + break :mode .win32; + } + }; + + switch (mode) { + .uefi => try argv.appendSlice(&[_][]const u8{ + "-BASE:0", + "-ENTRY:EfiMain", + "-OPT:REF", + "-SAFESEH:NO", + "-MERGE:.rdata=.data", + "-NODEFAULTLIB", + "-SECTION:.xdata,D", + }), + .win32 => { + if (link_in_crt) { + if (target.abi.isGnu()) { + if (target.cpu.arch == .x86) { + try argv.append("-ALTERNATENAME:__image_base__=___ImageBase"); + } else { + try argv.append("-ALTERNATENAME:__image_base__=__ImageBase"); + } + + if (is_dyn_lib) { + try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj")); + if (target.cpu.arch == .x86) { + try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12"); + } else { + try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup"); + } + } else { + try argv.append(try comp.crtFileAsString(arena, "crt2.obj")); + } + + try argv.append(try comp.crtFileAsString(arena, "libmingw32.lib")); + } else { + try argv.append(switch (comp.config.link_mode) { + .static => "libcmt.lib", + .dynamic => "msvcrt.lib", + }); + + const lib_str = switch (comp.config.link_mode) { + .static => "lib", + .dynamic => "", + }; + try argv.append(try allocPrint(arena, "{s}vcruntime.lib", .{lib_str})); + try argv.append(try allocPrint(arena, "{s}ucrt.lib", .{lib_str})); + + //Visual C++ 2015 Conformance Changes + //https://msdn.microsoft.com/en-us/library/bb531344.aspx + try argv.append("legacy_stdio_definitions.lib"); + + // msvcrt depends on kernel32 and ntdll + try argv.append("kernel32.lib"); + try argv.append("ntdll.lib"); + } + } else { + try argv.append("-NODEFAULTLIB"); + if (!is_lib and entry_name == null) { + if (comp.zcu != null) { + if (coff.lld_export_flags.winmain_crt_startup) { + try argv.append("-ENTRY:WinMainCRTStartup"); + } else { + try argv.append("-ENTRY:wWinMainCRTStartup"); + } + } else { + try argv.append("-ENTRY:wWinMainCRTStartup"); + } + } + } + }, + } + + if (comp.config.link_libc and link_in_crt) { + if (comp.zigc_static_lib) |zigc| { + try argv.append(try zigc.full_object_path.toString(arena)); + } + } + + // libc++ dep + if (comp.config.link_libcpp) { + try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); + try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); + } + + // libunwind dep + if (comp.config.link_libunwind) { + try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); + } + + if (comp.config.any_fuzz) { + try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena)); + } + + const ubsan_rt_path: ?Cache.Path = blk: { + if (comp.ubsan_rt_lib) |x| break :blk x.full_object_path; + if (comp.ubsan_rt_obj) |x| break :blk x.full_object_path; + break :blk null; + }; + if (ubsan_rt_path) |path| { + try argv.append(try path.toString(arena)); + } + + if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) { + // MSVC compiler_rt is missing some stuff, so we build it unconditionally but + // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. + if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena)); + if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena)); + } + + try argv.ensureUnusedCapacity(comp.windows_libs.count()); + for (comp.windows_libs.keys()) |key| { + const lib_basename = try allocPrint(arena, "{s}.lib", .{key}); + if (comp.crt_files.get(lib_basename)) |crt_file| { + argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena)); + continue; + } + if (try findLib(arena, lib_basename, coff.lib_directories)) |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, coff.lib_directories)) |full_path| { + argv.appendAssumeCapacity(full_path); + continue; + } + } + if (target.abi == .msvc or target.abi == .itanium) { + argv.appendAssumeCapacity(lib_basename); + continue; + } + + log.err("DLL import library for -l{s} not found", .{key}); + return error.DllImportLibraryNotFound; + } + + try spawnLld(comp, arena, argv.items); + } +} +fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Cache.Directory) !?[]const u8 { + for (lib_directories) |lib_directory| { + lib_directory.handle.access(name, .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => |e| return e, + }; + return try lib_directory.join(arena, &.{name}); + } + return null; +} + +fn elfLink(lld: *Lld, arena: Allocator) !void { + const comp = lld.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; + const base = &lld.base; + const elf = &lld.ofmt.elf; + + const directory = base.emit.root_dir; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); + + const zcu_obj_path: ?Cache.Path = if (comp.zcu != null) p: { + break :p try comp.resolveEmitPathFlush(arena, .temp, base.zcu_object_basename.?); + } else null; + + const output_mode = comp.config.output_mode; + const is_obj = output_mode == .Obj; + const is_lib = output_mode == .Lib; + const link_mode = 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 = link_mode == .dynamic and is_exe_or_dyn_lib; + const target = comp.root_mod.resolved_target.result; + const compiler_rt_path: ?Cache.Path = 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; + break :blk null; + }; + const ubsan_rt_path: ?Cache.Path = blk: { + if (comp.ubsan_rt_lib) |x| break :blk x.full_object_path; + if (comp.ubsan_rt_obj) |x| break :blk x.full_object_path; + break :blk null; + }; + + // Due to a deficiency in LLD, we need to special-case BPF to a simple file + // 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. + // + // For m68k, we go through this path because LLD doesn't support it yet, but LLVM can + // produce usable object files. + if (output_mode == .Obj and + (comp.config.lto != .none or + target.cpu.arch.isBpf() or + target.cpu.arch == .lanai or + target.cpu.arch == .m68k or + target.cpu.arch.isSPARC() or + target.cpu.arch == .ve or + target.cpu.arch == .xcore)) + { + // 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 (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; + + if (comp.c_object_table.count() != 0) + break :blk comp.c_object_table.keys()[0].status.success.object_path; + + if (zcu_obj_path) |p| + break :blk p; + + // TODO I think this is unreachable. Audit this situation when solving the above TODO + // regarding eliding redundant object -> object transformations. + return error.NoObjectsToLink; + }; + try std.fs.Dir.copyFile( + the_object_path.root_dir.handle, + the_object_path.sub_path, + directory.handle, + base.emit.sub_path, + .{}, + ); + } else { + // Create an LLD command line and invoke it. + 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 - + // it calls exit() and does not reset all global data between invocations. + const linker_command = "ld.lld"; + try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); + if (is_obj) { + try argv.append("-r"); + } + + try argv.append("--error-limit=0"); + + if (comp.sysroot) |sysroot| { + try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); + } + + if (target_util.llvmMachineAbi(target)) |mabi| { + try argv.appendSlice(&.{ + "-mllvm", + try std.fmt.allocPrint(arena, "-target-abi={s}", .{mabi}), + }); + } + + try argv.appendSlice(&.{ + "-mllvm", + try std.fmt.allocPrint(arena, "-float-abi={s}", .{if (target.abi.float() == .hard) "hard" else "soft"}), + }); + + if (comp.config.lto != .none) { + switch (comp.root_mod.optimize_mode) { + .Debug => {}, + .ReleaseSmall => try argv.append("--lto-O2"), + .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), + } + } + switch (comp.root_mod.optimize_mode) { + .Debug => {}, + .ReleaseSmall => try argv.append("-O2"), + .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + } + + if (elf.entry_name) |name| { + try argv.appendSlice(&.{ "--entry", name }); + } + + for (comp.force_undefined_symbols.keys()) |sym| { + try argv.append("-u"); + try argv.append(sym); + } + + switch (elf.hash_style) { + .gnu => try argv.append("--hash-style=gnu"), + .sysv => try argv.append("--hash-style=sysv"), + .both => {}, // this is the default + } + + if (output_mode == .Exe) { + try argv.appendSlice(&.{ + "-z", + try std.fmt.allocPrint(arena, "stack-size={d}", .{base.stack_size}), + }); + } + + switch (base.build_id) { + .none => try argv.append("--build-id=none"), + .fast, .uuid, .sha1, .md5 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ + @tagName(base.build_id), + })), + .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + })), + } + + try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{elf.image_base})); + + if (elf.linker_script) |linker_script| { + try argv.append("-T"); + try argv.append(linker_script); + } + + if (elf.sort_section) |how| { + const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)}); + try argv.append(arg); + } + + if (base.gc_sections) { + try argv.append("--gc-sections"); + } + + if (base.print_gc_sections) { + try argv.append("--print-gc-sections"); + } + + if (elf.print_icf_sections) { + try argv.append("--print-icf-sections"); + } + + if (elf.print_map) { + try argv.append("--print-map"); + } + + if (comp.link_eh_frame_hdr) { + try argv.append("--eh-frame-hdr"); + } + + if (elf.emit_relocs) { + try argv.append("--emit-relocs"); + } + + if (comp.config.rdynamic) { + try argv.append("--export-dynamic"); + } + + if (comp.config.debug_format == .strip) { + try argv.append("-s"); + } + + if (elf.z_nodelete) { + try argv.append("-z"); + try argv.append("nodelete"); + } + if (elf.z_notext) { + try argv.append("-z"); + try argv.append("notext"); + } + if (elf.z_defs) { + try argv.append("-z"); + try argv.append("defs"); + } + if (elf.z_origin) { + try argv.append("-z"); + try argv.append("origin"); + } + if (elf.z_nocopyreloc) { + try argv.append("-z"); + try argv.append("nocopyreloc"); + } + if (elf.z_now) { + // LLD defaults to -zlazy + try argv.append("-znow"); + } + if (!elf.z_relro) { + // LLD defaults to -zrelro + try argv.append("-znorelro"); + } + if (elf.z_common_page_size) |size| { + try argv.append("-z"); + try argv.append(try std.fmt.allocPrint(arena, "common-page-size={d}", .{size})); + } + if (elf.z_max_page_size) |size| { + try argv.append("-z"); + try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size})); + } + + if (getLDMOption(target)) |ldm| { + try argv.append("-m"); + try argv.append(ldm); + } + + if (link_mode == .static) { + if (target.cpu.arch.isArm()) { + try argv.append("-Bstatic"); + } else { + try argv.append("-static"); + } + } else if (switch (target.os.tag) { + else => is_dyn_lib, + .haiku => is_exe_or_dyn_lib, + }) { + try argv.append("-shared"); + } + + if (comp.config.pie and output_mode == .Exe) { + try argv.append("-pie"); + } + + if (is_exe_or_dyn_lib and target.os.tag == .netbsd) { + // Add options to produce shared objects with only 2 PT_LOAD segments. + // NetBSD expects 2 PT_LOAD segments in a shared object, otherwise + // ld.elf_so fails loading dynamic libraries with "not found" error. + // See https://github.com/ziglang/zig/issues/9109 . + try argv.append("--no-rosegment"); + try argv.append("-znorelro"); + } + + try argv.append("-o"); + try argv.append(full_out_path); + + // csu prelude + const csu = try comp.getCrtPaths(arena); + if (csu.crt0) |p| try argv.append(try p.toString(arena)); + if (csu.crti) |p| try argv.append(try p.toString(arena)); + if (csu.crtbegin) |p| try argv.append(try p.toString(arena)); + + for (elf.rpath_list) |rpath| { + try argv.appendSlice(&.{ "-rpath", rpath }); + } + + for (elf.symbol_wrap_set) |symbol_name| { + try argv.appendSlice(&.{ "-wrap", symbol_name }); + } + + if (comp.config.link_libc) { + if (comp.libc_installation) |libc_installation| { + try argv.append("-L"); + try argv.append(libc_installation.crt_dir.?); + } + } + + if (have_dynamic_linker and + (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker)) + { + if (target.dynamic_linker.get()) |dynamic_linker| { + try argv.append("-dynamic-linker"); + try argv.append(dynamic_linker); + } + } + + if (is_dyn_lib) { + if (elf.soname) |soname| { + try argv.append("-soname"); + try argv.append(soname); + } + if (elf.version_script) |version_script| { + try argv.append("-version-script"); + try argv.append(version_script); + } + if (elf.allow_undefined_version) { + try argv.append("--undefined-version"); + } else { + try argv.append("--no-undefined-version"); + } + if (elf.enable_new_dtags) |enable_new_dtags| { + if (enable_new_dtags) { + try argv.append("--enable-new-dtags"); + } else { + try argv.append("--disable-new-dtags"); + } + } + } + + // Positional arguments to the linker such as object files. + var whole_archive = false; + + for (base.comp.link_inputs) |link_input| switch (link_input) { + .res => unreachable, // Windows-only + .dso => continue, + .object, .archive => |obj| { + if (obj.must_link and !whole_archive) { + try argv.append("-whole-archive"); + whole_archive = true; + } else if (!obj.must_link and whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } + try argv.append(try obj.path.toString(arena)); + }, + .dso_exact => |dso_exact| { + assert(dso_exact.name[0] == ':'); + try argv.appendSlice(&.{ "-l", dso_exact.name }); + }, + }; + + if (whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } + + for (comp.c_object_table.keys()) |key| { + try argv.append(try key.status.success.object_path.toString(arena)); + } + + if (zcu_obj_path) |p| { + try argv.append(try p.toString(arena)); + } + + if (comp.tsan_lib) |lib| { + assert(comp.config.any_sanitize_thread); + try argv.append(try lib.full_object_path.toString(arena)); + } + + if (comp.fuzzer_lib) |lib| { + assert(comp.config.any_fuzz); + try argv.append(try lib.full_object_path.toString(arena)); + } + + if (ubsan_rt_path) |p| { + try argv.append(try p.toString(arena)); + } + + // Shared libraries. + if (is_exe_or_dyn_lib) { + // Worst-case, we need an --as-needed argument for every lib, as well + // as one before and one after. + try argv.ensureUnusedCapacity(2 * base.comp.link_inputs.len + 2); + argv.appendAssumeCapacity("--as-needed"); + var as_needed = true; + + for (base.comp.link_inputs) |link_input| switch (link_input) { + .res => unreachable, // Windows-only + .object, .archive, .dso_exact => continue, + .dso => |dso| { + const lib_as_needed = !dso.needed; + switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { + 0b00, 0b11 => {}, + 0b01 => { + argv.appendAssumeCapacity("--no-as-needed"); + as_needed = false; + }, + 0b10 => { + argv.appendAssumeCapacity("--as-needed"); + as_needed = true; + }, + } + + // By this time, we depend on these libs being dynamically linked + // libraries and not static libraries (the check for that needs to be earlier), + // but they could be full paths to .so files, in which case we + // want to avoid prepending "-l". + argv.appendAssumeCapacity(try dso.path.toString(arena)); + }, + }; + + if (!as_needed) { + argv.appendAssumeCapacity("--as-needed"); + as_needed = true; + } + + // libc++ dep + if (comp.config.link_libcpp) { + try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); + try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); + } + + // libunwind dep + if (comp.config.link_libunwind) { + try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); + } + + // libc dep + diags.flags.missing_libc = false; + if (comp.config.link_libc) { + if (comp.libc_installation != null) { + 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"); + } else if (target.isGnuLibC()) { + for (glibc.libs) |lib| { + if (lib.removed_in) |rem_in| { + if (target.os.versionRange().gnuLibCVersion().?.order(rem_in) != .lt) continue; + } + + const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{ + comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, + }); + try argv.append(lib_path); + } + try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a")); + } else if (target.isMuslLibC()) { + try argv.append(try comp.crtFileAsString(arena, switch (link_mode) { + .static => "libc.a", + .dynamic => "libc.so", + })); + } else if (target.isFreeBSDLibC()) { + for (freebsd.libs) |lib| { + const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{ + comp.freebsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, + }); + try argv.append(lib_path); + } + } else if (target.isNetBSDLibC()) { + for (netbsd.libs) |lib| { + const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{ + comp.netbsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, + }); + try argv.append(lib_path); + } + } else { + diags.flags.missing_libc = true; + } + + if (comp.zigc_static_lib) |zigc| { + try argv.append(try zigc.full_object_path.toString(arena)); + } + } + } + + // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs + // to be after the shared libraries, so they are picked up from the shared + // libraries, not libcompiler_rt. + if (compiler_rt_path) |p| { + try argv.append(try p.toString(arena)); + } + + // crt postlude + if (csu.crtend) |p| try argv.append(try p.toString(arena)); + if (csu.crtn) |p| try argv.append(try p.toString(arena)); + + if (base.allow_shlib_undefined) { + try argv.append("--allow-shlib-undefined"); + } + + switch (elf.compress_debug_sections) { + .none => {}, + .zlib => try argv.append("--compress-debug-sections=zlib"), + .zstd => try argv.append("--compress-debug-sections=zstd"), + } + + if (elf.bind_global_refs_locally) { + try argv.append("-Bsymbolic"); + } + + try spawnLld(comp, arena, argv.items); + } +} +fn getLDMOption(target: std.Target) ?[]const u8 { + // This should only return emulations understood by LLD's parseEmulation(). + return switch (target.cpu.arch) { + .aarch64 => switch (target.os.tag) { + .linux => "aarch64linux", + else => "aarch64elf", + }, + .aarch64_be => switch (target.os.tag) { + .linux => "aarch64linuxb", + else => "aarch64elfb", + }, + .amdgcn => "elf64_amdgpu", + .arm, .thumb => switch (target.os.tag) { + .linux => "armelf_linux_eabi", + else => "armelf", + }, + .armeb, .thumbeb => switch (target.os.tag) { + .linux => "armelfb_linux_eabi", + else => "armelfb", + }, + .hexagon => "hexagonelf", + .loongarch32 => "elf32loongarch", + .loongarch64 => "elf64loongarch", + .mips => switch (target.os.tag) { + .freebsd => "elf32btsmip_fbsd", + else => "elf32btsmip", + }, + .mipsel => switch (target.os.tag) { + .freebsd => "elf32ltsmip_fbsd", + else => "elf32ltsmip", + }, + .mips64 => switch (target.os.tag) { + .freebsd => switch (target.abi) { + .gnuabin32, .muslabin32 => "elf32btsmipn32_fbsd", + else => "elf64btsmip_fbsd", + }, + else => switch (target.abi) { + .gnuabin32, .muslabin32 => "elf32btsmipn32", + else => "elf64btsmip", + }, + }, + .mips64el => switch (target.os.tag) { + .freebsd => switch (target.abi) { + .gnuabin32, .muslabin32 => "elf32ltsmipn32_fbsd", + else => "elf64ltsmip_fbsd", + }, + else => switch (target.abi) { + .gnuabin32, .muslabin32 => "elf32ltsmipn32", + else => "elf64ltsmip", + }, + }, + .msp430 => "msp430elf", + .powerpc => switch (target.os.tag) { + .freebsd => "elf32ppc_fbsd", + .linux => "elf32ppclinux", + else => "elf32ppc", + }, + .powerpcle => switch (target.os.tag) { + .linux => "elf32lppclinux", + else => "elf32lppc", + }, + .powerpc64 => "elf64ppc", + .powerpc64le => "elf64lppc", + .riscv32 => "elf32lriscv", + .riscv64 => "elf64lriscv", + .s390x => "elf64_s390", + .sparc64 => "elf64_sparc", + .x86 => switch (target.os.tag) { + .freebsd => "elf_i386_fbsd", + else => "elf_i386", + }, + .x86_64 => switch (target.abi) { + .gnux32, .muslx32 => "elf32_x86_64", + else => "elf_x86_64", + }, + else => null, + }; +} +fn wasmLink(lld: *Lld, arena: Allocator) !void { + const comp = lld.base.comp; + 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 base = &lld.base; + const wasm = &lld.ofmt.wasm; + + const gpa = comp.gpa; + + const directory = base.emit.root_dir; // Just an alias to make it shorter to type. + const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); + + const zcu_obj_path: ?Cache.Path = if (comp.zcu != null) p: { + break :p try comp.resolveEmitPathFlush(arena, .temp, base.zcu_object_basename.?); + } else null; + + const is_obj = comp.config.output_mode == .Obj; + const compiler_rt_path: ?Cache.Path = blk: { + if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path; + if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path; + break :blk null; + }; + const ubsan_rt_path: ?Cache.Path = blk: { + if (comp.ubsan_rt_lib) |lib| break :blk lib.full_object_path; + if (comp.ubsan_rt_obj) |obj| break :blk obj.full_object_path; + break :blk null; + }; + + if (is_obj) { + // LLD's WASM 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 (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; + + if (comp.c_object_table.count() != 0) + break :blk comp.c_object_table.keys()[0].status.success.object_path; + + if (zcu_obj_path) |p| + break :blk p; + + // TODO I think this is unreachable. Audit this situation when solving the above TODO + // regarding eliding redundant object -> object transformations. + return error.NoObjectsToLink; + }; + try fs.Dir.copyFile( + the_object_path.root_dir.handle, + the_object_path.sub_path, + directory.handle, + base.emit.sub_path, + .{}, + ); + } else { + // Create an LLD command line and invoke it. + 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 - + // it calls exit() and does not reset all global data between invocations. + const linker_command = "wasm-ld"; + try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); + try argv.append("--error-limit=0"); + + if (comp.config.lto != .none) { + switch (comp.root_mod.optimize_mode) { + .Debug => {}, + .ReleaseSmall => try argv.append("-O2"), + .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + } + } + + if (import_memory) { + try argv.append("--import-memory"); + } + + if (export_memory) { + try argv.append("--export-memory"); + } + + if (wasm.import_table) { + assert(!wasm.export_table); + try argv.append("--import-table"); + } + + if (wasm.export_table) { + assert(!wasm.import_table); + try argv.append("--export-table"); + } + + // 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 (!base.gc_sections) { + try argv.append("--no-gc-sections"); + } + + if (comp.config.debug_format == .strip) { + try argv.append("-s"); + } + + if (wasm.initial_memory) |initial_memory| { + const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory}); + try argv.append(arg); + } + + if (wasm.max_memory) |max_memory| { + const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory}); + try argv.append(arg); + } + + if (shared_memory) { + try argv.append("--shared-memory"); + } + + if (wasm.global_base) |global_base| { + const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base}); + try argv.append(arg); + } else { + // We prepend it by default, so when a stack overflow happens the runtime will trap correctly, + // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496 + // + // The user can overwrite this behavior by setting the global-base + try argv.append("--stack-first"); + } + + // Users are allowed to specify which symbols they want to export to the wasm host. + for (wasm.export_symbol_names) |symbol_name| { + const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); + try argv.append(arg); + } + + if (comp.config.rdynamic) { + try argv.append("--export-dynamic"); + } + + if (wasm.entry_name) |entry_name| { + try argv.appendSlice(&.{ "--entry", entry_name }); + } else { + try argv.append("--no-entry"); + } + + try argv.appendSlice(&.{ + "-z", + try std.fmt.allocPrint(arena, "stack-size={d}", .{base.stack_size}), + }); + + switch (base.build_id) { + .none => try argv.append("--build-id=none"), + .fast, .uuid, .sha1 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ + @tagName(base.build_id), + })), + .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ + std.fmt.fmtSliceHexLower(hs.toSlice()), + })), + .md5 => {}, + } + + if (wasm.import_symbols) { + try argv.append("--allow-undefined"); + } + + if (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic) { + try argv.append("--shared"); + } + if (comp.config.pie) { + try argv.append("--pie"); + } + + try argv.appendSlice(&.{ "-o", full_out_path }); + + if (target.cpu.arch == .wasm64) { + try argv.append("-mwasm64"); + } + + const is_exe_or_dyn_lib = comp.config.output_mode == .Exe or + (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic); + + if (comp.config.link_libc and is_exe_or_dyn_lib) { + if (target.os.tag == .wasi) { + for (comp.wasi_emulated_libs) |crt_file| { + try argv.append(try comp.crtFileAsString( + arena, + wasi_libc.emulatedLibCRFileLibName(crt_file), + )); + } + + try argv.append(try comp.crtFileAsString( + arena, + wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model), + )); + try argv.append(try comp.crtFileAsString(arena, "libc.a")); + } + + if (comp.zigc_static_lib) |zigc| { + try argv.append(try zigc.full_object_path.toString(arena)); + } + + if (comp.config.link_libcpp) { + try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); + try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); + } + } + + // Positional arguments to the linker such as object files. + var whole_archive = false; + for (comp.link_inputs) |link_input| switch (link_input) { + .object, .archive => |obj| { + if (obj.must_link and !whole_archive) { + try argv.append("-whole-archive"); + whole_archive = true; + } else if (!obj.must_link and whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } + try argv.append(try obj.path.toString(arena)); + }, + .dso => |dso| { + try argv.append(try dso.path.toString(arena)); + }, + .dso_exact => unreachable, + .res => unreachable, + }; + if (whole_archive) { + try argv.append("-no-whole-archive"); + whole_archive = false; + } + + for (comp.c_object_table.keys()) |key| { + try argv.append(try key.status.success.object_path.toString(arena)); + } + if (zcu_obj_path) |p| { + try argv.append(try p.toString(arena)); + } + + if (compiler_rt_path) |p| { + try argv.append(try p.toString(arena)); + } + + if (ubsan_rt_path) |p| { + try argv.append(try p.toStringZ(arena)); + } + + try spawnLld(comp, arena, argv.items); + + // Give +x to the .wasm file if it is an executable and the OS is WASI. + // Some systems may be configured to execute such binaries directly. Even if that + // is not the case, it means we will get "exec format error" when trying to run + // it, and then can react to that in the same way as trying to run an ELF file + // from a foreign CPU architecture. + if (fs.has_executable_bit and target.os.tag == .wasi and + comp.config.output_mode == .Exe) + { + // TODO: what's our strategy for reporting linker errors from this function? + // report a nice error here with the file path if it fails instead of + // just returning the error code. + // chmod does not interact with umask, so we use a conservative -rwxr--r-- here. + std.posix.fchmodat(fs.cwd().fd, full_out_path, 0o744, 0) catch |err| switch (err) { + error.OperationNotSupported => unreachable, // Not a symlink. + else => |e| return e, + }; + } + } +} + +fn spawnLld( + comp: *Compilation, + arena: Allocator, + argv: []const []const u8, +) !void { + if (comp.verbose_link) { + // Skip over our own name so that the LLD linker name is the first argv item. + Compilation.dump_argv(argv[1..]); + } + + // If possible, we run LLD as a child process because it does not always + // behave properly as a library, unfortunately. + // https://github.com/ziglang/zig/issues/3825 + if (!std.process.can_spawn) { + const exit_code = try lldMain(arena, argv, false); + if (exit_code == 0) return; + if (comp.clang_passthrough_mode) std.process.exit(exit_code); + return error.LinkFailure; + } + + var stderr: []u8 = &.{}; + defer comp.gpa.free(stderr); + + var child = std.process.Child.init(argv, arena); + const term = (if (comp.clang_passthrough_mode) term: { + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; + + break :term child.spawnAndWait(); + } else term: { + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Pipe; + + child.spawn() catch |err| break :term err; + stderr = try child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize)); + break :term child.wait(); + }) catch |first_err| term: { + const err = switch (first_err) { + error.NameTooLong => err: { + const s = fs.path.sep_str; + const rand_int = std.crypto.random.int(u64); + const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp"; + + const rsp_file = try comp.dirs.local_cache.handle.createFileZ(rsp_path, .{}); + defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err| + log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) }); + { + defer rsp_file.close(); + var rsp_buf = std.io.bufferedWriter(rsp_file.writer()); + const rsp_writer = rsp_buf.writer(); + for (argv[2..]) |arg| { + try rsp_writer.writeByte('"'); + for (arg) |c| { + switch (c) { + '\"', '\\' => try rsp_writer.writeByte('\\'), + else => {}, + } + try rsp_writer.writeByte(c); + } + try rsp_writer.writeByte('"'); + try rsp_writer.writeByte('\n'); + } + try rsp_buf.flush(); + } + + var rsp_child = std.process.Child.init(&.{ argv[0], argv[1], try std.fmt.allocPrint( + arena, + "@{s}", + .{try comp.dirs.local_cache.join(arena, &.{rsp_path})}, + ) }, arena); + if (comp.clang_passthrough_mode) { + rsp_child.stdin_behavior = .Inherit; + rsp_child.stdout_behavior = .Inherit; + rsp_child.stderr_behavior = .Inherit; + + break :term rsp_child.spawnAndWait() catch |err| break :err err; + } else { + rsp_child.stdin_behavior = .Ignore; + rsp_child.stdout_behavior = .Ignore; + rsp_child.stderr_behavior = .Pipe; + + rsp_child.spawn() catch |err| break :err err; + stderr = try rsp_child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize)); + break :term rsp_child.wait() catch |err| break :err err; + } + }, + else => first_err, + }; + log.err("unable to spawn LLD {s}: {s}", .{ argv[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; + + const diags = &comp.link_diags; + switch (term) { + .Exited => |code| if (code != 0) { + if (comp.clang_passthrough_mode) std.process.exit(code); + diags.lockAndParseLldStderr(argv[1], stderr); + return error.LinkFailure; + }, + else => { + if (comp.clang_passthrough_mode) std.process.abort(); + return diags.fail("{s} terminated with stderr:\n{s}", .{ argv[0], stderr }); + }, + } + + if (stderr.len > 0) log.warn("unexpected LLD stderr:\n{s}", .{stderr}); +} + +const std = @import("std"); +const Allocator = std.mem.Allocator; +const Cache = std.Build.Cache; +const allocPrint = std.fmt.allocPrint; +const assert = std.debug.assert; +const fs = std.fs; +const log = std.log.scoped(.link); +const mem = std.mem; + +const Compilation = @import("../Compilation.zig"); +const Zcu = @import("../Zcu.zig"); +const dev = @import("../dev.zig"); +const freebsd = @import("../libs/freebsd.zig"); +const glibc = @import("../libs/glibc.zig"); +const netbsd = @import("../libs/netbsd.zig"); +const wasi_libc = @import("../libs/wasi_libc.zig"); +const link = @import("../link.zig"); +const lldMain = @import("../main.zig").lldMain; +const target_util = @import("../target.zig"); +const trace = @import("../tracy.zig").trace; +const Lld = @This(); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3ddc12a5b0aa..3f3a94bee71a 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -6,9 +6,6 @@ base: link.File, rpath_list: []const []const u8, -/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. -llvm_object: ?LlvmObject.Ptr = null, - /// Debug symbols bundle (or dSym). d_sym: ?DebugSymbols = null, @@ -176,13 +173,6 @@ pub fn createEmpty( const output_mode = comp.config.output_mode; const link_mode = comp.config.link_mode; - // If using LLVM to generate the object file for the zig compilation unit, - // we need a place to put the object file so that it can be subsequently - // handled. - const zcu_object_sub_path = if (!use_llvm) - null - else - try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); const allow_shlib_undefined = options.allow_shlib_undefined orelse false; const self = try arena.create(MachO); @@ -191,13 +181,15 @@ pub fn createEmpty( .tag = .macho, .comp = comp, .emit = emit, - .zcu_object_sub_path = zcu_object_sub_path, + .zcu_object_basename = if (use_llvm) + try std.fmt.allocPrint(arena, "{s}_zcu.o", .{fs.path.stem(emit.sub_path)}) + else + null, .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 = allow_shlib_undefined, .file = null, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, .rpath_list = options.rpath_list, @@ -225,15 +217,12 @@ pub fn createEmpty( .force_load_objc = options.force_load_objc, .discard_local_symbols = options.discard_local_symbols, }; - if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, comp); - } errdefer self.base.destroy(); self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{ .truncate = true, .read = true, - .mode = link.File.determineMode(false, output_mode, link_mode), + .mode = link.File.determineMode(output_mode, link_mode), }); // Append null file @@ -280,8 +269,6 @@ pub fn open( pub fn deinit(self: *MachO) void { const gpa = self.base.comp.gpa; - if (self.llvm_object) |llvm_object| llvm_object.deinit(); - if (self.d_sym) |*d_sym| { d_sym.deinit(); } @@ -349,15 +336,6 @@ pub fn flush( arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, -) link.File.FlushError!void { - try self.flushModule(arena, tid, prog_node); -} - -pub fn flushModule( - self: *MachO, - arena: Allocator, - tid: Zcu.PerThread.Id, - prog_node: std.Progress.Node, ) link.File.FlushError!void { const tracy = trace(@src()); defer tracy.end(); @@ -366,28 +344,19 @@ pub fn flushModule( const gpa = comp.gpa; const diags = &self.base.comp.link_diags; - if (self.llvm_object) |llvm_object| { - try self.base.emitLlvmObject(arena, llvm_object, prog_node); - } - const sub_prog_node = prog_node.start("MachO Flush", 0); defer sub_prog_node.end(); - const directory = self.base.emit.root_dir; - const module_obj_path: ?Path = if (self.base.zcu_object_sub_path) |path| .{ - .root_dir = directory, - .sub_path = if (fs.path.dirname(self.base.emit.sub_path)) |dirname| - try fs.path.join(arena, &.{ dirname, path }) - else - path, + const zcu_obj_path: ?Path = if (self.base.zcu_object_basename) |raw| p: { + break :p try comp.resolveEmitPathFlush(arena, .temp, raw); } else null; // --verbose-link if (comp.verbose_link) try self.dumpArgv(comp); - if (self.getZigObject()) |zo| try zo.flushModule(self, tid); - if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); - if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); + if (self.getZigObject()) |zo| try zo.flush(self, tid); + if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, zcu_obj_path); + if (self.base.isObject()) return relocatable.flushObject(self, comp, zcu_obj_path); var positionals = std.ArrayList(link.Input).init(gpa); defer positionals.deinit(); @@ -409,7 +378,7 @@ pub fn flushModule( positionals.appendAssumeCapacity(try link.openObjectInput(diags, key.status.success.object_path)); } - if (module_obj_path) |path| try positionals.append(try link.openObjectInput(diags, path)); + if (zcu_obj_path) |path| try positionals.append(try link.openObjectInput(diags, path)); if (comp.config.any_sanitize_thread) { try positionals.append(try link.openObjectInput(diags, comp.tsan_lib.?.full_object_path)); @@ -629,7 +598,7 @@ pub fn flushModule( error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("failed to calculate and write uuid: {s}", .{@errorName(e)}), }; - if (self.getDebugSymbols()) |dsym| dsym.flushModule(self) catch |err| switch (err) { + if (self.getDebugSymbols()) |dsym| dsym.flush(self) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to get debug symbols: {s}", .{@errorName(e)}), }; @@ -658,12 +627,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { const directory = self.base.emit.root_dir; const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); - const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { - if (fs.path.dirname(full_out_path)) |dirname| { - break :blk try fs.path.join(arena, &.{ dirname, path }); - } else { - break :blk path; - } + const zcu_obj_path: ?[]const u8 = if (self.base.zcu_object_basename) |raw| p: { + const p = try comp.resolveEmitPathFlush(arena, .temp, raw); + break :p try p.toString(arena); } else null; var argv = std.ArrayList([]const u8).init(arena); @@ -692,7 +658,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { try argv.append(try key.status.success.object_path.toString(arena)); } - if (module_obj_path) |p| { + if (zcu_obj_path) |p| { try argv.append(p); } } else { @@ -784,7 +750,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { try argv.append(try key.status.success.object_path.toString(arena)); } - if (module_obj_path) |p| { + if (zcu_obj_path) |p| { try argv.append(p); } @@ -3073,26 +3039,22 @@ pub fn updateFunc( self: *MachO, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); - return self.getZigObject().?.updateFunc(self, pt, func_index, air, liveness); + return self.getZigObject().?.updateFunc(self, pt, func_index, mir); } pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav); return self.getZigObject().?.updateNav(self, pt, nav); } pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { - if (self.llvm_object) |_| return; return self.getZigObject().?.updateLineNumber(pt, ti_id); } @@ -3105,7 +3067,6 @@ pub fn updateExports( if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); return self.getZigObject().?.updateExports(self, pt, exported, export_indices); } @@ -3114,17 +3075,14 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (self.llvm_object) |_| return; return self.getZigObject().?.deleteExport(self, exported, name); } pub fn freeNav(self: *MachO, nav: InternPool.Nav.Index) void { - if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav); return self.getZigObject().?.freeNav(nav); } pub fn getNavVAddr(self: *MachO, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.getZigObject().?.getNavVAddr(self, pt, nav_index, reloc_info); } @@ -3139,7 +3097,6 @@ pub fn lowerUav( } pub fn getUavVAddr(self: *MachO, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.getZigObject().?.getUavVAddr(self, uav, reloc_info); } @@ -5473,7 +5430,6 @@ const target_util = @import("../target.zig"); const trace = @import("../tracy.zig").trace; const synthetic = @import("MachO/synthetic.zig"); -const Air = @import("../Air.zig"); const Alignment = Atom.Alignment; const Allocator = mem.Allocator; const Archive = @import("MachO/Archive.zig"); @@ -5496,7 +5452,6 @@ const ObjcStubsSection = synthetic.ObjcStubsSection; const Object = @import("MachO/Object.zig"); const LazyBind = bind.LazyBind; const LaSymbolPtrSection = synthetic.LaSymbolPtrSection; -const LlvmObject = @import("../codegen/llvm.zig").Object; const Md5 = std.crypto.hash.Md5; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 04b2fe92b06e..eef3492b485e 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -178,7 +178,7 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64 return offset; } -pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { +pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void { const zo = macho_file.getZigObject().?; for (self.relocs.items) |*reloc| { const sym = zo.symbols.items[reloc.target]; diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 7493d3ceab5a..be126b09638b 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -389,9 +389,6 @@ pub const Flags = packed struct { /// ZigObject specific flags /// Whether the symbol has a trampoline trampoline: bool = false, - - /// Whether the symbol is an extern pointer (as opposed to function). - is_extern_ptr: bool = false, }; pub const SectionFlags = packed struct(u8) { diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index a0de86654421..f9ecdc6fb50d 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -550,7 +550,7 @@ pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.se return sect; } -pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void { +pub fn flush(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void { const diags = &macho_file.base.comp.link_diags; // Handle any lazy symbols that were emitted by incremental compilation. @@ -589,7 +589,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) if (self.dwarf) |*dwarf| { const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid); defer pt.deactivate(); - dwarf.flushModule(pt) catch |err| switch (err) { + dwarf.flush(pt) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to flush dwarf module: {s}", .{@errorName(e)}), }; @@ -599,7 +599,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) self.debug_strtab_dirty = false; } - // The point of flushModule() is to commit changes, so in theory, nothing should + // The point of flush() is to commit changes, so in theory, nothing should // be dirty after this. However, it is possible for some things to remain // dirty because they fail to be written in the event of compile errors, // such as debug_line_header_dirty and debug_info_header_dirty. @@ -777,8 +777,7 @@ pub fn updateFunc( macho_file: *MachO, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { const tracy = trace(@src()); defer tracy.end(); @@ -796,13 +795,12 @@ pub fn updateFunc( var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); - try codegen.generateFunction( + try codegen.emitFunction( &macho_file.base, pt, zcu.navSrcLoc(func.owner_nav), func_index, - air, - liveness, + mir, &code_buffer, if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, ); @@ -883,11 +881,7 @@ pub fn updateNav( const name = @"extern".name.toSlice(ip); const lib_name = @"extern".lib_name.toSlice(ip); const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name); - if (!ip.isFunctionType(@"extern".ty)) { - const sym = &self.symbols.items[sym_index]; - sym.flags.is_extern_ptr = true; - if (@"extern".is_threadlocal) sym.flags.tlv = true; - } + if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true; if (self.dwarf) |*dwarf| dwarf: { var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf; defer debug_wip_nav.deinit(); @@ -1160,7 +1154,6 @@ fn getNavOutputSection( ) error{OutOfMemory}!u8 { _ = self; const ip = &zcu.intern_pool; - const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded; const nav_val = zcu.navValue(nav_index); if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return macho_file.zig_text_sect_index.?; const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { @@ -1168,7 +1161,7 @@ fn getNavOutputSection( .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, else => .{ true, false, nav_val.toIntern() }, }; - if (any_non_single_threaded and is_threadlocal) { + if (is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) { for (code) |byte| { if (byte != 0) break; } else return macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection( @@ -1537,7 +1530,7 @@ pub fn getOrCreateMetadataForLazySymbol( } state_ptr.* = .pending_flush; const symbol_index = symbol_index_ptr.*; - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flush if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(macho_file, pt, lazy_sym, symbol_index); return symbol_index; } @@ -1813,7 +1806,6 @@ const target_util = @import("../../target.zig"); const trace = @import("../../tracy.zig").trace; const std = @import("std"); -const Air = @import("../../Air.zig"); const Allocator = std.mem.Allocator; const Archive = @import("Archive.zig"); const Atom = @import("Atom.zig"); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 5cbb9287d7b1..c99ebb81bb78 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -301,7 +301,6 @@ pub fn createEmpty( .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, }, .sixtyfour_bit = sixtyfour_bit, @@ -387,8 +386,7 @@ pub fn updateFunc( self: *Plan9, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { if (build_options.skip_non_native and builtin.object_format != .plan9) { @panic("Attempted to compile for object format that was disabled by build configuration"); @@ -413,13 +411,12 @@ pub fn updateFunc( }; defer dbg_info_output.dbg_line.deinit(); - try codegen.generateFunction( + try codegen.emitFunction( &self.base, pt, zcu.navSrcLoc(func.owner_nav), func_index, - air, - liveness, + mir, &code_buffer, .{ .plan9 = &dbg_info_output }, ); @@ -494,7 +491,7 @@ fn updateFinish(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index // write the symbol // we already have the got index const sym: aout.Sym = .{ - .value = undefined, // the value of stuff gets filled in in flushModule + .value = undefined, // the value of stuff gets filled in in flush .type = atom.type, .name = try gpa.dupe(u8, nav.name.toSlice(ip)), }; @@ -527,25 +524,6 @@ fn allocateGotIndex(self: *Plan9) usize { } } -pub fn flush( - self: *Plan9, - arena: Allocator, - tid: Zcu.PerThread.Id, - prog_node: std.Progress.Node, -) link.File.FlushError!void { - const comp = self.base.comp; - const diags = &comp.link_diags; - const use_lld = build_options.have_llvm and comp.config.use_lld; - assert(!use_lld); - - switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) { - .Exe => {}, - .Obj => return diags.fail("writing plan9 object files unimplemented", .{}), - .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}), - } - return self.flushModule(arena, tid, prog_node); -} - pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { if (delta_line > 0 and delta_line < 65) { const toappend = @as(u8, @intCast(delta_line)); @@ -586,7 +564,7 @@ fn atomCount(self: *Plan9) usize { return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count; } -pub fn flushModule( +pub fn flush( self: *Plan9, arena: Allocator, /// TODO: stop using this @@ -607,10 +585,16 @@ pub fn flushModule( const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; + switch (comp.config.output_mode) { + .Exe => {}, + .Obj => return diags.fail("writing plan9 object files unimplemented", .{}), + .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}), + } + const sub_prog_node = prog_node.start("Flush Module", 0); defer sub_prog_node.end(); - log.debug("flushModule", .{}); + log.debug("flush", .{}); defer assert(self.hdr.entry != 0x0); @@ -1039,7 +1023,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F const atom = atom_ptr.*; _ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self); _ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self); - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flush if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom); return atom; } @@ -1182,11 +1166,7 @@ pub fn open( const file = try emit.root_dir.handle.createFile(emit.sub_path, .{ .read = true, - .mode = link.File.determineMode( - use_lld, - comp.config.output_mode, - comp.config.link_mode, - ), + .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), }); errdefer file.close(); self.base.file = file; diff --git a/src/link/Queue.zig b/src/link/Queue.zig new file mode 100644 index 000000000000..d197edab0233 --- /dev/null +++ b/src/link/Queue.zig @@ -0,0 +1,279 @@ +//! Stores and manages the queue of link tasks. Each task is either a `PrelinkTask` or a `ZcuTask`. +//! +//! There must be at most one link thread (the thread processing these tasks) active at a time. If +//! `!comp.separateCodegenThreadOk()`, then ZCU tasks will be run on the main thread, bypassing this +//! queue entirely. +//! +//! All prelink tasks must be processed before any ZCU tasks are processed. After all prelink tasks +//! are run, but before any ZCU tasks are run, `prelink` must be called on the `link.File`. +//! +//! There will sometimes be a `ZcuTask` in the queue which is not yet ready because it depends on +//! MIR which has not yet been generated by any codegen thread. In this case, we must pause +//! processing of linker tasks until the MIR is ready. It would be incorrect to run any other link +//! tasks first, since this would make builds unreproducible. + +mutex: std.Thread.Mutex, +/// Validates that only one `flushTaskQueue` thread is running at a time. +flush_safety: std.debug.SafetyLock, + +/// This is the number of prelink tasks which are expected but have not yet been enqueued. +/// Guarded by `mutex`. +pending_prelink_tasks: u32, + +/// Prelink tasks which have been enqueued and are not yet owned by the worker thread. +/// Allocated into `gpa`, guarded by `mutex`. +queued_prelink: std.ArrayListUnmanaged(PrelinkTask), +/// The worker thread moves items from `queued_prelink` into this array in order to process them. +/// Allocated into `gpa`, accessed only by the worker thread. +wip_prelink: std.ArrayListUnmanaged(PrelinkTask), + +/// Like `queued_prelink`, but for ZCU tasks. +/// Allocated into `gpa`, guarded by `mutex`. +queued_zcu: std.ArrayListUnmanaged(ZcuTask), +/// Like `wip_prelink`, but for ZCU tasks. +/// Allocated into `gpa`, accessed only by the worker thread. +wip_zcu: std.ArrayListUnmanaged(ZcuTask), + +/// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this +/// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the +/// index into `wip_zcu` which we have reached. +wip_zcu_idx: usize, + +/// The sum of all `air_bytes` for all currently-queued `ZcuTask.link_func` tasks. Because +/// MIR bytes are approximately proportional to AIR bytes, this acts to limit the amount of +/// AIR and MIR which is queued for codegen and link respectively, to prevent excessive +/// memory usage if analysis produces AIR faster than it can be processed by codegen/link. +/// The cap is `max_air_bytes_in_flight`. +/// Guarded by `mutex`. +air_bytes_in_flight: u32, +/// If nonzero, then a call to `enqueueZcu` is blocked waiting to add a `link_func` task, but +/// cannot until `air_bytes_in_flight` is no greater than this value. +/// Guarded by `mutex`. +air_bytes_waiting: u32, +/// After setting `air_bytes_waiting`, `enqueueZcu` will wait on this condition (with `mutex`). +/// When `air_bytes_waiting` many bytes can be queued, this condition should be signaled. +air_bytes_cond: std.Thread.Condition, + +/// Guarded by `mutex`. +state: union(enum) { + /// The link thread is currently running or queued to run. + running, + /// The link thread is not running or queued, because it has exhausted all immediately available + /// tasks. It should be spawned when more tasks are enqueued. If `pending_prelink_tasks` is not + /// zero, we are specifically waiting for prelink tasks. + finished, + /// The link thread is not running or queued, because it is waiting for this MIR to be populated. + /// Once codegen completes, it must call `mirReady` which will restart the link thread. + wait_for_mir: *ZcuTask.LinkFunc.SharedMir, +}, + +/// In the worst observed case, MIR is around 50 times as large as AIR. More typically, the ratio is +/// around 20. Going by that 50x multiplier, and assuming we want to consume no more than 500 MiB of +/// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight. +const max_air_bytes_in_flight = 10 * 1024 * 1024; + +/// The initial `Queue` state, containing no tasks, expecting no prelink tasks, and with no running worker thread. +/// The `pending_prelink_tasks` and `queued_prelink` fields may be modified as needed before calling `start`. +pub const empty: Queue = .{ + .mutex = .{}, + .flush_safety = .{}, + .pending_prelink_tasks = 0, + .queued_prelink = .empty, + .wip_prelink = .empty, + .queued_zcu = .empty, + .wip_zcu = .empty, + .wip_zcu_idx = 0, + .state = .finished, + .air_bytes_in_flight = 0, + .air_bytes_waiting = 0, + .air_bytes_cond = .{}, +}; +/// `lf` is needed to correctly deinit any pending `ZcuTask`s. +pub fn deinit(q: *Queue, comp: *Compilation) void { + const gpa = comp.gpa; + for (q.queued_zcu.items) |t| t.deinit(comp.zcu.?); + for (q.wip_zcu.items[q.wip_zcu_idx..]) |t| t.deinit(comp.zcu.?); + q.queued_prelink.deinit(gpa); + q.wip_prelink.deinit(gpa); + q.queued_zcu.deinit(gpa); + q.wip_zcu.deinit(gpa); +} + +/// This is expected to be called exactly once, after which the caller must not directly access +/// `queued_prelink` or `pending_prelink_tasks` any longer. This will spawn the link thread if +/// necessary. +pub fn start(q: *Queue, comp: *Compilation) void { + assert(q.state == .finished); + assert(q.queued_zcu.items.len == 0); + if (q.queued_prelink.items.len != 0) { + q.state = .running; + comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp }); + } +} + +/// Called by codegen workers after they have populated a `ZcuTask.LinkFunc.SharedMir`. If the link +/// thread was waiting for this MIR, it can resume. +pub fn mirReady(q: *Queue, comp: *Compilation, mir: *ZcuTask.LinkFunc.SharedMir) void { + // We would like to assert that `mir` is not pending, but that would race with a worker thread + // potentially freeing it. + { + q.mutex.lock(); + defer q.mutex.unlock(); + switch (q.state) { + .finished, .running => return, + .wait_for_mir => |wait_for| if (wait_for != mir) return, + } + // We were waiting for `mir`, so we will restart the linker thread. + q.state = .running; + } + assert(mir.status.load(.monotonic) != .pending); + comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp }); +} + +/// Enqueues all prelink tasks in `tasks`. Asserts that they were expected, i.e. that `tasks.len` is +/// less than or equal to `q.pending_prelink_tasks`. Also asserts that `tasks.len` is not 0. +pub fn enqueuePrelink(q: *Queue, comp: *Compilation, tasks: []const PrelinkTask) Allocator.Error!void { + { + q.mutex.lock(); + defer q.mutex.unlock(); + try q.queued_prelink.appendSlice(comp.gpa, tasks); + q.pending_prelink_tasks -= @intCast(tasks.len); + switch (q.state) { + .wait_for_mir => unreachable, // we've not started zcu tasks yet + .running => return, + .finished => {}, + } + // Restart the linker thread, because it was waiting for a task + q.state = .running; + } + comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp }); +} + +pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error!void { + assert(comp.separateCodegenThreadOk()); + { + q.mutex.lock(); + defer q.mutex.unlock(); + // If this is a `link_func` task, we might need to wait for `air_bytes_in_flight` to fall. + if (task == .link_func) { + const max_in_flight = max_air_bytes_in_flight -| task.link_func.air_bytes; + while (q.air_bytes_in_flight > max_in_flight) { + q.air_bytes_waiting = task.link_func.air_bytes; + q.air_bytes_cond.wait(&q.mutex); + q.air_bytes_waiting = 0; + } + q.air_bytes_in_flight += task.link_func.air_bytes; + } + try q.queued_zcu.append(comp.gpa, task); + switch (q.state) { + .running, .wait_for_mir => return, + .finished => if (q.pending_prelink_tasks != 0) return, + } + // Restart the linker thread, unless it would immediately be blocked + if (task == .link_func and task.link_func.mir.status.load(.monotonic) == .pending) { + q.state = .{ .wait_for_mir = task.link_func.mir }; + return; + } + q.state = .running; + } + comp.thread_pool.spawnWgId(&comp.link_task_wait_group, flushTaskQueue, .{ q, comp }); +} + +fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { + q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex` + + if (std.debug.runtime_safety) { + q.mutex.lock(); + defer q.mutex.unlock(); + assert(q.state == .running); + } + prelink: while (true) { + assert(q.wip_prelink.items.len == 0); + { + q.mutex.lock(); + defer q.mutex.unlock(); + std.mem.swap(std.ArrayListUnmanaged(PrelinkTask), &q.queued_prelink, &q.wip_prelink); + if (q.wip_prelink.items.len == 0) { + if (q.pending_prelink_tasks == 0) { + break :prelink; // prelink is done + } else { + // We're expecting more prelink tasks so can't move on to ZCU tasks. + q.state = .finished; + q.flush_safety.unlock(); + return; + } + } + } + for (q.wip_prelink.items) |task| { + link.doPrelinkTask(comp, task); + } + q.wip_prelink.clearRetainingCapacity(); + } + + // We've finished the prelink tasks, so run prelink if necessary. + if (comp.bin_file) |lf| { + if (!lf.post_prelink) { + if (lf.prelink()) |_| { + lf.post_prelink = true; + } else |err| switch (err) { + error.OutOfMemory => comp.link_diags.setAllocFailure(), + error.LinkFailure => {}, + } + } + } + + // Now we can run ZCU tasks. + while (true) { + if (q.wip_zcu.items.len == q.wip_zcu_idx) { + q.wip_zcu.clearRetainingCapacity(); + q.wip_zcu_idx = 0; + q.mutex.lock(); + defer q.mutex.unlock(); + std.mem.swap(std.ArrayListUnmanaged(ZcuTask), &q.queued_zcu, &q.wip_zcu); + if (q.wip_zcu.items.len == 0) { + // We've exhausted all available tasks. + q.state = .finished; + q.flush_safety.unlock(); + return; + } + } + const task = q.wip_zcu.items[q.wip_zcu_idx]; + // If the task is a `link_func`, we might have to stop until its MIR is populated. + pending: { + if (task != .link_func) break :pending; + const status_ptr = &task.link_func.mir.status; + // First check without the mutex to optimize for the common case where MIR is ready. + if (status_ptr.load(.monotonic) != .pending) break :pending; + q.mutex.lock(); + defer q.mutex.unlock(); + if (status_ptr.load(.monotonic) != .pending) break :pending; + // We will stop for now, and get restarted once this MIR is ready. + q.state = .{ .wait_for_mir = task.link_func.mir }; + q.flush_safety.unlock(); + return; + } + link.doZcuTask(comp, tid, task); + task.deinit(comp.zcu.?); + if (task == .link_func) { + // Decrease `air_bytes_in_flight`, since we've finished processing this MIR. + q.mutex.lock(); + defer q.mutex.unlock(); + q.air_bytes_in_flight -= task.link_func.air_bytes; + if (q.air_bytes_waiting != 0 and + q.air_bytes_in_flight <= max_air_bytes_in_flight -| q.air_bytes_waiting) + { + q.air_bytes_cond.signal(); + } + } + q.wip_zcu_idx += 1; + } +} + +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const Compilation = @import("../Compilation.zig"); +const link = @import("../link.zig"); +const PrelinkTask = link.PrelinkTask; +const ZcuTask = link.ZcuTask; +const Queue = @This(); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index a49771c3e2f2..bafefccfc0e4 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -17,7 +17,7 @@ //! All regular functions. // Because SPIR-V requires re-compilation anyway, and so hot swapping will not work -// anyway, we simply generate all the code in flushModule. This keeps +// anyway, we simply generate all the code in flush. This keeps // things considerably simpler. const SpirV = @This(); @@ -83,7 +83,6 @@ pub fn createEmpty( .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, .object = codegen.Object.init(gpa, comp.getTarget()), @@ -112,24 +111,6 @@ pub fn deinit(self: *SpirV) void { self.object.deinit(); } -pub fn updateFunc( - self: *SpirV, - pt: Zcu.PerThread, - func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, -) link.File.UpdateNavError!void { - if (build_options.skip_non_native) { - @panic("Attempted to compile for architecture that was disabled by build configuration"); - } - - const ip = &pt.zcu.intern_pool; - const func = pt.zcu.funcInfo(func_index); - log.debug("lowering function {}", .{ip.getNav(func.owner_nav).name.fmt(ip)}); - - try self.object.updateFunc(pt, func_index, air, liveness); -} - pub fn updateNav(self: *SpirV, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { if (build_options.skip_non_native) { @panic("Attempted to compile for architecture that was disabled by build configuration"); @@ -193,18 +174,14 @@ pub fn updateExports( // TODO: Export regular functions, variables, etc using Linkage attributes. } -pub fn flush(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); -} - -pub fn flushModule( +pub fn flush( self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.File.FlushError!void { // The goal is to never use this because it's only needed if we need to - // write to InternPool, but flushModule is too late to be writing to the + // write to InternPool, but flush is too late to be writing to the // InternPool. _ = tid; diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 69684724a5b4..eda755298670 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -29,19 +29,16 @@ const leb = std.leb; const log = std.log.scoped(.link); const mem = std.mem; -const Air = @import("../Air.zig"); const Mir = @import("../arch/wasm/Mir.zig"); const CodeGen = @import("../arch/wasm/CodeGen.zig"); const abi = @import("../arch/wasm/abi.zig"); const Compilation = @import("../Compilation.zig"); const Dwarf = @import("Dwarf.zig"); const InternPool = @import("../InternPool.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; const Zcu = @import("../Zcu.zig"); const codegen = @import("../codegen.zig"); const dev = @import("../dev.zig"); const link = @import("../link.zig"); -const lldMain = @import("../main.zig").lldMain; const trace = @import("../tracy.zig").trace; const wasi_libc = @import("../libs/wasi_libc.zig"); const Value = @import("../Value.zig"); @@ -75,14 +72,10 @@ global_base: ?u64, initial_memory: ?u64, /// When defined, sets the maximum memory size of the memory. max_memory: ?u64, -/// When true, will import the function table from the host environment. -import_table: bool, /// When true, will export the function table to the host environment. export_table: bool, /// 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. -llvm_object: ?LlvmObject.Ptr = null, /// List of relocatable files to be linked into the final binary. objects: std.ArrayListUnmanaged(Object) = .{}, @@ -288,7 +281,7 @@ mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, /// Corresponds to `mir_instructions`. mir_extra: std.ArrayListUnmanaged(u32) = .empty, /// All local types for all Zcu functions. -all_zcu_locals: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty, +mir_locals: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty, params_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty, returns_scratch: std.ArrayListUnmanaged(std.wasm.Valtype) = .empty, @@ -872,9 +865,24 @@ const ZcuDataStarts = struct { }; pub const ZcuFunc = union { - function: CodeGen.Function, + function: Function, tag_name: TagName, + pub const Function = extern struct { + /// Index into `Wasm.mir_instructions`. + instructions_off: u32, + /// This is unused except for as a safety slice bound and could be removed. + instructions_len: u32, + /// Index into `Wasm.mir_extra`. + extra_off: u32, + /// This is unused except for as a safety slice bound and could be removed. + extra_len: u32, + /// Index into `Wasm.mir_locals`. + locals_off: u32, + locals_len: u32, + prologue: Mir.Prologue, + }; + pub const TagName = extern struct { symbol_name: String, type_index: FunctionType.Index, @@ -2938,28 +2946,20 @@ pub fn createEmpty( const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .wasm); - 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 wasi_exec_model = comp.config.wasi_exec_model; - // If using LLD to link, this code should produce an object file so that it - // can be passed to LLD. - // If using LLVM to generate the object file for the zig compilation unit, - // we need a place to put the object file so that it can be subsequently - // handled. - const zcu_object_sub_path = if (!use_lld and !use_llvm) - null - else - try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); - const wasm = try arena.create(Wasm); wasm.* = .{ .base = .{ .tag = .wasm, .comp = comp, .emit = emit, - .zcu_object_sub_path = zcu_object_sub_path, + .zcu_object_basename = if (use_llvm) + try std.fmt.allocPrint(arena, "{s}_zcu.o", .{fs.path.stem(emit.sub_path)}) + else + null, // Garbage collection is so crucial to WebAssembly that we design // the linker around the assumption that it will be on in the vast // majority of cases, and therefore express "no garbage collection" @@ -2973,13 +2973,11 @@ pub fn createEmpty( }, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, .file = null, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, .name = undefined, .string_table = .empty, .string_bytes = .empty, - .import_table = options.import_table, .export_table = options.export_table, .import_symbols = options.import_symbols, .export_symbol_names = options.export_symbol_names, @@ -2992,9 +2990,6 @@ pub fn createEmpty( .object_host_name = .none, .preloaded_strings = undefined, }; - if (use_llvm and comp.config.have_zcu) { - wasm.llvm_object = try LlvmObject.create(arena, comp); - } errdefer wasm.base.destroy(); if (options.object_host_name) |name| wasm.object_host_name = (try wasm.internString(name)).toOptional(); @@ -3010,17 +3005,7 @@ pub fn createEmpty( .named => |name| (try wasm.internString(name)).toOptional(), }; - if (use_lld and (use_llvm or !comp.config.have_zcu)) { - // LLVM emits the object file (if any); LLD links it into the final product. - return wasm; - } - - // What path should this Wasm linker code output to? - // If using LLD to link, this code should produce an object file so that it - // can be passed to LLD. - const sub_path = if (use_lld) zcu_object_sub_path.? else emit.sub_path; - - wasm.base.file = try emit.root_dir.handle.createFile(sub_path, .{ + wasm.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{ .truncate = true, .read = true, .mode = if (fs.has_executable_bit) @@ -3031,7 +3016,7 @@ pub fn createEmpty( else 0, }); - wasm.name = sub_path; + wasm.name = emit.sub_path; return wasm; } @@ -3116,7 +3101,6 @@ fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void { pub fn deinit(wasm: *Wasm) void { const gpa = wasm.base.comp.gpa; - if (wasm.llvm_object) |llvm_object| llvm_object.deinit(); wasm.navs_exe.deinit(gpa); wasm.navs_obj.deinit(gpa); @@ -3132,7 +3116,7 @@ pub fn deinit(wasm: *Wasm) void { wasm.mir_instructions.deinit(gpa); wasm.mir_extra.deinit(gpa); - wasm.all_zcu_locals.deinit(gpa); + wasm.mir_locals.deinit(gpa); if (wasm.dwarf) |*dwarf| dwarf.deinit(); @@ -3192,34 +3176,94 @@ pub fn deinit(wasm: *Wasm) void { wasm.missing_exports.deinit(gpa); } -pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, air: Air, liveness: Air.Liveness) !void { +pub fn updateFunc( + wasm: *Wasm, + pt: Zcu.PerThread, + func_index: InternPool.Index, + any_mir: *const codegen.AnyMir, +) !void { if (build_options.skip_non_native and builtin.object_format != .wasm) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); dev.check(.wasm_backend); + // This linker implementation only works with codegen backend `.stage2_wasm`. + const mir = &any_mir.wasm; const zcu = pt.zcu; const gpa = zcu.gpa; - try wasm.functions.ensureUnusedCapacity(gpa, 1); - try wasm.zcu_funcs.ensureUnusedCapacity(gpa, 1); - const ip = &zcu.intern_pool; + const is_obj = zcu.comp.config.output_mode == .Obj; + const target = &zcu.comp.root_mod.resolved_target.result; const owner_nav = zcu.funcInfo(func_index).owner_nav; log.debug("updateFunc {}", .{ip.getNav(owner_nav).fqn.fmt(ip)}); + // For Wasm, we do not lower the MIR to code just yet. That lowering happens during `flush`, + // after garbage collection, which can affect function and global indexes, which affects the + // LEB integer encoding, which affects the output binary size. + + // However, we do move the MIR into a more efficient in-memory representation, where the arrays + // for all functions are packed together rather than keeping them each in their own `Mir`. + const mir_instructions_off: u32 = @intCast(wasm.mir_instructions.len); + const mir_extra_off: u32 = @intCast(wasm.mir_extra.items.len); + const mir_locals_off: u32 = @intCast(wasm.mir_locals.items.len); + { + // Copying MultiArrayList data is a little non-trivial. Resize, then memcpy both slices. + const old_len = wasm.mir_instructions.len; + try wasm.mir_instructions.resize(gpa, old_len + mir.instructions.len); + const dest_slice = wasm.mir_instructions.slice().subslice(old_len, mir.instructions.len); + const src_slice = mir.instructions; + @memcpy(dest_slice.items(.tag), src_slice.items(.tag)); + @memcpy(dest_slice.items(.data), src_slice.items(.data)); + } + try wasm.mir_extra.appendSlice(gpa, mir.extra); + try wasm.mir_locals.appendSlice(gpa, mir.locals); + + // We also need to populate some global state from `mir`. + try wasm.zcu_indirect_function_set.ensureUnusedCapacity(gpa, mir.indirect_function_set.count()); + for (mir.indirect_function_set.keys()) |nav| wasm.zcu_indirect_function_set.putAssumeCapacity(nav, {}); + for (mir.func_tys.keys()) |func_ty| { + const fn_info = zcu.typeToFunc(.fromInterned(func_ty)).?; + _ = try wasm.internFunctionType(fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target); + } + wasm.error_name_table_ref_count += mir.error_name_table_ref_count; + // We need to populate UAV data. In theory, we can lower the UAV values while we fill `mir.uavs`. + // However, lowering the data might cause *more* UAVs to be created, and mixing them up would be + // a headache. So instead, just write `undefined` placeholder code and use the `ZcuDataStarts`. const zds: ZcuDataStarts = .init(wasm); + for (mir.uavs.keys(), mir.uavs.values()) |uav_val, uav_align| { + if (uav_align != .none) { + const gop = try wasm.overaligned_uavs.getOrPut(gpa, uav_val); + gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(uav_align) else uav_align; + } + if (is_obj) { + const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val); + if (!gop.found_existing) gop.value_ptr.* = undefined; // `zds` handles lowering + } else { + const gop = try wasm.uavs_exe.getOrPut(gpa, uav_val); + if (!gop.found_existing) gop.value_ptr.* = .{ + .code = undefined, // `zds` handles lowering + .count = 0, + }; + gop.value_ptr.count += 1; + } + } + try zds.finish(wasm, pt); // actually generates the UAVs + + try wasm.functions.ensureUnusedCapacity(gpa, 1); + try wasm.zcu_funcs.ensureUnusedCapacity(gpa, 1); // This converts AIR to MIR but does not yet lower to wasm code. - // That lowering happens during `flush`, after garbage collection, which - // can affect function and global indexes, which affects the LEB integer - // encoding, which affects the output binary size. - const function = try CodeGen.function(wasm, pt, func_index, air, liveness); - wasm.zcu_funcs.putAssumeCapacity(func_index, .{ .function = function }); + wasm.zcu_funcs.putAssumeCapacity(func_index, .{ .function = .{ + .instructions_off = mir_instructions_off, + .instructions_len = @intCast(mir.instructions.len), + .extra_off = mir_extra_off, + .extra_len = @intCast(mir.extra.len), + .locals_off = mir_locals_off, + .locals_len = @intCast(mir.locals.len), + .prologue = mir.prologue, + } }); wasm.functions.putAssumeCapacity(.pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.entries.len - 1) }), {}); - - try zds.finish(wasm, pt); } // Generate code for the "Nav", storing it in memory to be later written to @@ -3228,7 +3272,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index if (build_options.skip_non_native and builtin.object_format != .wasm) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index); const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); @@ -3308,8 +3351,6 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (wasm.llvm_object != null) return; - const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const name_slice = name.toSlice(ip); @@ -3332,7 +3373,6 @@ pub fn updateExports( if (build_options.skip_non_native and builtin.object_format != .wasm) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); const zcu = pt.zcu; const gpa = zcu.gpa; @@ -3379,21 +3419,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { } } -pub fn flush(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - const comp = wasm.base.comp; - const use_lld = build_options.have_llvm and comp.config.use_lld; - const diags = &comp.link_diags; - - if (use_lld) { - return wasm.linkWithLLD(arena, tid, prog_node) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.LinkFailure => return error.LinkFailure, - else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), - }; - } - return wasm.flushModule(arena, tid, prog_node); -} - pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!void { const tracy = trace(@src()); defer tracy.end(); @@ -3785,37 +3810,25 @@ fn markTable(wasm: *Wasm, i: ObjectTableIndex) link.File.FlushError!void { try wasm.tables.put(wasm.base.comp.gpa, .fromObjectTable(i), {}); } -pub fn flushModule( +pub fn flush( wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.File.FlushError!void { // The goal is to never use this because it's only needed if we need to - // write to InternPool, but flushModule is too late to be writing to the + // write to InternPool, but flush is too late to be writing to the // InternPool. _ = tid; const comp = wasm.base.comp; - const use_lld = build_options.have_llvm and comp.config.use_lld; const diags = &comp.link_diags; const gpa = comp.gpa; - if (wasm.llvm_object) |llvm_object| { - try wasm.base.emitLlvmObject(arena, llvm_object, prog_node); - if (use_lld) return; - } - if (comp.verbose_link) Compilation.dump_argv(wasm.dump_argv_list.items); - if (wasm.base.zcu_object_sub_path) |path| { - const module_obj_path: Path = .{ - .root_dir = wasm.base.emit.root_dir, - .sub_path = if (fs.path.dirname(wasm.base.emit.sub_path)) |dirname| - try fs.path.join(arena, &.{ dirname, path }) - else - path, - }; - openParseObjectReportingFailure(wasm, module_obj_path); + if (wasm.base.zcu_object_basename) |raw| { + const zcu_obj_path: Path = try comp.resolveEmitPathFlush(arena, .temp, raw); + openParseObjectReportingFailure(wasm, zcu_obj_path); try prelink(wasm, prog_node); } @@ -3850,432 +3863,6 @@ pub fn flushModule( }; } -fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { - dev.check(.lld_linker); - - const tracy = trace(@src()); - defer tracy.end(); - - const comp = wasm.base.comp; - const diags = &comp.link_diags; - 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 = comp.gpa; - - const directory = wasm.base.emit.root_dir; // 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. - const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { - try wasm.flushModule(arena, tid, prog_node); - - if (fs.path.dirname(full_out_path)) |dirname| { - break :blk try fs.path.join(arena, &.{ dirname, wasm.base.zcu_object_sub_path.? }); - } else { - break :blk wasm.base.zcu_object_sub_path.?; - } - } else null; - - const sub_prog_node = prog_node.start("LLD Link", 0); - defer sub_prog_node.end(); - - const is_obj = comp.config.output_mode == .Obj; - const compiler_rt_path: ?Path = blk: { - if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path; - if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path; - break :blk null; - }; - const ubsan_rt_path: ?Path = blk: { - if (comp.ubsan_rt_lib) |lib| break :blk lib.full_object_path; - if (comp.ubsan_rt_obj) |obj| break :blk obj.full_object_path; - break :blk null; - }; - - const id_symlink_basename = "lld.id"; - - var man: Cache.Manifest = undefined; - defer if (!wasm.base.disable_lld_caching) man.deinit(); - - var digest: [Cache.hex_digest_len]u8 = undefined; - - 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. - wasm.base.releaseLock(); - - comptime assert(Compilation.link_hash_implementation_version == 14); - - try link.hashInputs(&man, comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - _ = try man.addFilePath(key.status.success.object_path, null); - } - try man.addOptionalFile(module_obj_path); - try man.addOptionalFilePath(compiler_rt_path); - try man.addOptionalFilePath(ubsan_rt_path); - man.hash.addOptionalBytes(wasm.entry_name.slice(wasm)); - man.hash.add(wasm.base.stack_size); - man.hash.add(wasm.base.build_id); - 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.initial_memory); - man.hash.addOptional(wasm.max_memory); - man.hash.add(shared_memory); - man.hash.addOptional(wasm.global_base); - man.hash.addListOfBytes(wasm.export_symbol_names); - // strip does not need to go into the linker hash because it is part of the hash namespace - - // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. - _ = try man.hit(); - digest = man.final(); - - var prev_digest_buf: [digest.len]u8 = undefined; - const prev_digest: []u8 = Cache.readSmallFile( - directory.handle, - id_symlink_basename, - &prev_digest_buf, - ) catch |err| blk: { - log.debug("WASM LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); - // Handle this as a cache miss. - break :blk prev_digest_buf[0..0]; - }; - if (mem.eql(u8, prev_digest, &digest)) { - log.debug("WASM LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); - // Hot diggity dog! The output binary is already there. - wasm.base.lock = man.toOwnedLock(); - return; - } - log.debug("WASM LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); - - // We are about to change the output file to be different, so we invalidate the build hash now. - directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { - error.FileNotFound => {}, - else => |e| return e, - }; - } - - if (is_obj) { - // LLD's WASM 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 (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; - - if (module_obj_path) |p| - break :blk Path.initCwd(p); - - // TODO I think this is unreachable. Audit this situation when solving the above TODO - // regarding eliding redundant object -> object transformations. - return error.NoObjectsToLink; - }; - try fs.Dir.copyFile( - the_object_path.root_dir.handle, - the_object_path.sub_path, - directory.handle, - wasm.base.emit.sub_path, - .{}, - ); - } else { - // Create an LLD command line and invoke it. - 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 - - // it calls exit() and does not reset all global data between invocations. - const linker_command = "wasm-ld"; - try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); - try argv.append("--error-limit=0"); - - if (comp.config.lto != .none) { - switch (comp.root_mod.optimize_mode) { - .Debug => {}, - .ReleaseSmall => try argv.append("-O2"), - .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), - } - } - - if (import_memory) { - try argv.append("--import-memory"); - } - - if (export_memory) { - try argv.append("--export-memory"); - } - - if (wasm.import_table) { - assert(!wasm.export_table); - try argv.append("--import-table"); - } - - if (wasm.export_table) { - assert(!wasm.import_table); - try argv.append("--export-table"); - } - - // 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 (comp.config.debug_format == .strip) { - try argv.append("-s"); - } - - if (wasm.initial_memory) |initial_memory| { - const arg = try std.fmt.allocPrint(arena, "--initial-memory={d}", .{initial_memory}); - try argv.append(arg); - } - - if (wasm.max_memory) |max_memory| { - const arg = try std.fmt.allocPrint(arena, "--max-memory={d}", .{max_memory}); - try argv.append(arg); - } - - if (shared_memory) { - try argv.append("--shared-memory"); - } - - if (wasm.global_base) |global_base| { - const arg = try std.fmt.allocPrint(arena, "--global-base={d}", .{global_base}); - try argv.append(arg); - } else { - // We prepend it by default, so when a stack overflow happens the runtime will trap correctly, - // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496 - // - // The user can overwrite this behavior by setting the global-base - try argv.append("--stack-first"); - } - - // Users are allowed to specify which symbols they want to export to the wasm host. - for (wasm.export_symbol_names) |symbol_name| { - const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); - try argv.append(arg); - } - - if (comp.config.rdynamic) { - try argv.append("--export-dynamic"); - } - - if (wasm.entry_name.slice(wasm)) |entry_name| { - try argv.appendSlice(&.{ "--entry", entry_name }); - } else { - try argv.append("--no-entry"); - } - - try argv.appendSlice(&.{ - "-z", - try std.fmt.allocPrint(arena, "stack-size={d}", .{wasm.base.stack_size}), - }); - - switch (wasm.base.build_id) { - .none => try argv.append("--build-id=none"), - .fast, .uuid, .sha1 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ - @tagName(wasm.base.build_id), - })), - .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ - std.fmt.fmtSliceHexLower(hs.toSlice()), - })), - .md5 => {}, - } - - if (wasm.import_symbols) { - try argv.append("--allow-undefined"); - } - - if (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic) { - try argv.append("--shared"); - } - if (comp.config.pie) { - try argv.append("--pie"); - } - - try argv.appendSlice(&.{ "-o", full_out_path }); - - if (target.cpu.arch == .wasm64) { - try argv.append("-mwasm64"); - } - - const is_exe_or_dyn_lib = comp.config.output_mode == .Exe or - (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic); - - if (comp.config.link_libc and is_exe_or_dyn_lib) { - if (target.os.tag == .wasi) { - for (comp.wasi_emulated_libs) |crt_file| { - try argv.append(try comp.crtFileAsString( - arena, - wasi_libc.emulatedLibCRFileLibName(crt_file), - )); - } - - try argv.append(try comp.crtFileAsString( - arena, - wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model), - )); - try argv.append(try comp.crtFileAsString(arena, "libc.a")); - } - - if (comp.zigc_static_lib) |zigc| { - try argv.append(try zigc.full_object_path.toString(arena)); - } - - if (comp.config.link_libcpp) { - try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); - try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); - } - } - - // Positional arguments to the linker such as object files. - var whole_archive = false; - for (comp.link_inputs) |link_input| switch (link_input) { - .object, .archive => |obj| { - if (obj.must_link and !whole_archive) { - try argv.append("-whole-archive"); - whole_archive = true; - } else if (!obj.must_link and whole_archive) { - try argv.append("-no-whole-archive"); - whole_archive = false; - } - try argv.append(try obj.path.toString(arena)); - }, - .dso => |dso| { - try argv.append(try dso.path.toString(arena)); - }, - .dso_exact => unreachable, - .res => unreachable, - }; - if (whole_archive) { - try argv.append("-no-whole-archive"); - whole_archive = false; - } - - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); - } - if (module_obj_path) |p| { - try argv.append(p); - } - - if (compiler_rt_path) |p| { - try argv.append(try p.toString(arena)); - } - - if (ubsan_rt_path) |p| { - try argv.append(try p.toStringZ(arena)); - } - - 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..]); - } - - if (std.process.can_spawn) { - // If possible, we run LLD as a child process because it does not always - // behave properly as a library, unfortunately. - // https://github.com/ziglang/zig/issues/3825 - var child = std.process.Child.init(argv.items, arena); - if (comp.clang_passthrough_mode) { - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - const term = child.spawnAndWait() catch |err| { - log.err("failed to spawn (passthrough mode) LLD {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnWasm; - }; - switch (term) { - .Exited => |code| { - if (code != 0) { - std.process.exit(code); - } - }, - else => std.process.abort(), - } - } else { - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; - - try child.spawn(); - - const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize)); - - const term = child.wait() catch |err| { - log.err("failed to spawn LLD {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnWasm; - }; - - switch (term) { - .Exited => |code| { - if (code != 0) { - diags.lockAndParseLldStderr(linker_command, stderr); - return error.LinkFailure; - } - }, - else => { - return diags.fail("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - }, - } - - if (stderr.len != 0) { - log.warn("unexpected LLD stderr:\n{s}", .{stderr}); - } - } - } else { - const exit_code = try lldMain(arena, argv.items, false); - if (exit_code != 0) { - if (comp.clang_passthrough_mode) { - std.process.exit(exit_code); - } else { - return diags.fail("{s} returned exit code {d}:\n{s}", .{ argv.items[0], exit_code }); - } - } - } - - // Give +x to the .wasm file if it is an executable and the OS is WASI. - // Some systems may be configured to execute such binaries directly. Even if that - // is not the case, it means we will get "exec format error" when trying to run - // it, and then can react to that in the same way as trying to run an ELF file - // from a foreign CPU architecture. - if (fs.has_executable_bit and target.os.tag == .wasi and - comp.config.output_mode == .Exe) - { - // TODO: what's our strategy for reporting linker errors from this function? - // report a nice error here with the file path if it fails instead of - // just returning the error code. - // chmod does not interact with umask, so we use a conservative -rwxr--r-- here. - std.posix.fchmodat(fs.cwd().fd, full_out_path, 0o744, 0) catch |err| switch (err) { - error.OperationNotSupported => unreachable, // Not a symlink. - else => |e| return e, - }; - } - } - - 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| { - log.warn("failed to save linking hash digest symlink: {s}", .{@errorName(err)}); - }; - // Again failure here only means an unnecessary cache miss. - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); - }; - // We hang on to this lock so that the output file path can be used without - // other processes clobbering it. - wasm.base.lock = man.toOwnedLock(); - } -} - fn defaultEntrySymbolName( preloaded_strings: *const PreloadedStrings, wasi_exec_model: std.builtin.WasiExecModel, @@ -4465,58 +4052,54 @@ pub fn symbolNameIndex(wasm: *Wasm, name: String) Allocator.Error!SymbolTableInd return @enumFromInt(gop.index); } -pub fn refUavObj(wasm: *Wasm, ip_index: InternPool.Index, orig_ptr_ty: InternPool.Index) !UavsObjIndex { - const comp = wasm.base.comp; - const zcu = comp.zcu.?; - const ip = &zcu.intern_pool; - const gpa = comp.gpa; - assert(comp.config.output_mode == .Obj); - - if (orig_ptr_ty != .none) { - const abi_alignment = Zcu.Type.fromInterned(ip.typeOf(ip_index)).abiAlignment(zcu); - const explicit_alignment = ip.indexToKey(orig_ptr_ty).ptr_type.flags.alignment; - if (explicit_alignment.compare(.gt, abi_alignment)) { - const gop = try wasm.overaligned_uavs.getOrPut(gpa, ip_index); - gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(explicit_alignment) else explicit_alignment; - } - } - - const gop = try wasm.uavs_obj.getOrPut(gpa, ip_index); - if (!gop.found_existing) gop.value_ptr.* = .{ - // Lowering the value is delayed to avoid recursion. - .code = undefined, - .relocs = undefined, - }; - return @enumFromInt(gop.index); -} - -pub fn refUavExe(wasm: *Wasm, ip_index: InternPool.Index, orig_ptr_ty: InternPool.Index) !UavsExeIndex { +pub fn addUavReloc( + wasm: *Wasm, + reloc_offset: usize, + uav_val: InternPool.Index, + orig_ptr_ty: InternPool.Index, + addend: u32, +) !void { const comp = wasm.base.comp; const zcu = comp.zcu.?; const ip = &zcu.intern_pool; const gpa = comp.gpa; - assert(comp.config.output_mode != .Obj); - if (orig_ptr_ty != .none) { - const abi_alignment = Zcu.Type.fromInterned(ip.typeOf(ip_index)).abiAlignment(zcu); - const explicit_alignment = ip.indexToKey(orig_ptr_ty).ptr_type.flags.alignment; - if (explicit_alignment.compare(.gt, abi_alignment)) { - const gop = try wasm.overaligned_uavs.getOrPut(gpa, ip_index); - gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(explicit_alignment) else explicit_alignment; - } - } - - const gop = try wasm.uavs_exe.getOrPut(gpa, ip_index); - if (gop.found_existing) { - gop.value_ptr.count += 1; + @"align": { + const ptr_type = ip.indexToKey(orig_ptr_ty).ptr_type; + const this_align = ptr_type.flags.alignment; + if (this_align == .none) break :@"align"; + const abi_align = Zcu.Type.fromInterned(ptr_type.child).abiAlignment(zcu); + if (this_align.compare(.lte, abi_align)) break :@"align"; + const gop = try wasm.overaligned_uavs.getOrPut(gpa, uav_val); + gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(this_align) else this_align; + } + + if (comp.config.output_mode == .Obj) { + const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val); + if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later + try wasm.out_relocs.append(gpa, .{ + .offset = @intCast(reloc_offset), + .pointee = .{ .symbol_index = try wasm.uavSymbolIndex(uav_val) }, + .tag = switch (wasm.pointerSize()) { + 32 => .memory_addr_i32, + 64 => .memory_addr_i64, + else => unreachable, + }, + .addend = @intCast(addend), + }); } else { - gop.value_ptr.* = .{ - // Lowering the value is delayed to avoid recursion. - .code = undefined, - .count = 1, + const gop = try wasm.uavs_exe.getOrPut(gpa, uav_val); + if (!gop.found_existing) gop.value_ptr.* = .{ + .code = undefined, // to avoid recursion, `ZcuDataStarts` will lower the value later + .count = 0, }; + gop.value_ptr.count += 1; + try wasm.uav_fixups.append(gpa, .{ + .uavs_exe_index = @enumFromInt(gop.index), + .offset = @intCast(reloc_offset), + .addend = addend, + }); } - return @enumFromInt(gop.index); } pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex { @@ -4550,10 +4133,11 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex { } /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. -pub fn uavAddr(wasm: *Wasm, uav_index: UavsExeIndex) u32 { +pub fn uavAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 { assert(wasm.flush_buffer.memory_layout_finished); const comp = wasm.base.comp; assert(comp.config.output_mode != .Obj); + const uav_index: UavsExeIndex = @enumFromInt(wasm.uavs_exe.getIndex(ip_index).?); const ds_id: DataSegmentId = .pack(wasm, .{ .uav_exe = uav_index }); return wasm.flush_buffer.data_segments.get(ds_id).?; } diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 7ed72e851807..60f5971e40af 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -9,6 +9,7 @@ const Alignment = Wasm.Alignment; const String = Wasm.String; const Relocation = Wasm.Relocation; const InternPool = @import("../../InternPool.zig"); +const Mir = @import("../../arch/wasm/Mir.zig"); const build_options = @import("build_options"); @@ -868,7 +869,21 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .enum_type => { try emitTagNameFunction(wasm, binary_bytes, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); }, - else => try i.value(wasm).function.lower(wasm, binary_bytes), + else => { + const func = i.value(wasm).function; + const mir: Mir = .{ + .instructions = wasm.mir_instructions.slice().subslice(func.instructions_off, func.instructions_len), + .extra = wasm.mir_extra.items[func.extra_off..][0..func.extra_len], + .locals = wasm.mir_locals.items[func.locals_off..][0..func.locals_len], + .prologue = func.prologue, + // These fields are unused by `lower`. + .uavs = undefined, + .indirect_function_set = undefined, + .func_tys = undefined, + .error_name_table_ref_count = undefined, + }; + try mir.lower(wasm, binary_bytes); + }, } }, }; diff --git a/src/link/Xcoff.zig b/src/link/Xcoff.zig index 525d99d39165..fd143713ffcf 100644 --- a/src/link/Xcoff.zig +++ b/src/link/Xcoff.zig @@ -13,14 +13,12 @@ const Path = std.Build.Cache.Path; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); const Compilation = @import("../Compilation.zig"); +const codegen = @import("../codegen.zig"); const link = @import("../link.zig"); const trace = @import("../tracy.zig").trace; const build_options = @import("build_options"); -const Air = @import("../Air.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, -llvm_object: LlvmObject.Ptr, pub fn createEmpty( arena: Allocator, @@ -36,23 +34,20 @@ pub fn createEmpty( assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve. - const llvm_object = try LlvmObject.create(arena, comp); const xcoff = try arena.create(Xcoff); xcoff.* = .{ .base = .{ .tag = .xcoff, .comp = comp, .emit = emit, - .zcu_object_sub_path = emit.sub_path, + .zcu_object_basename = emit.sub_path, .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, - .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, - .llvm_object = llvm_object, }; return xcoff; @@ -70,27 +65,27 @@ pub fn open( } pub fn deinit(self: *Xcoff) void { - self.llvm_object.deinit(); + _ = self; } pub fn updateFunc( self: *Xcoff, pt: Zcu.PerThread, func_index: InternPool.Index, - air: Air, - liveness: Air.Liveness, + mir: *const codegen.AnyMir, ) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - try self.llvm_object.updateFunc(pt, func_index, air, liveness); + _ = self; + _ = pt; + _ = func_index; + _ = mir; + unreachable; // we always use llvm } pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateNav(pt, nav); + _ = self; + _ = pt; + _ = nav; + unreachable; // we always use llvm } pub fn updateExports( @@ -99,21 +94,19 @@ pub fn updateExports( exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, ) !void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateExports(pt, exported, export_indices); + _ = self; + _ = pt; + _ = exported; + _ = export_indices; + unreachable; // we always use llvm } pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); -} - -pub fn flushModule(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { if (build_options.skip_non_native and builtin.object_format != .xcoff) @panic("Attempted to compile for object format that was disabled by build configuration"); + _ = self; + _ = arena; _ = tid; - - try self.base.emitLlvmObject(arena, self.llvm_object, prog_node); + _ = prog_node; } diff --git a/src/main.zig b/src/main.zig index 20ccf4b7ec1c..3821fafb80e1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -699,55 +699,30 @@ const Emit = union(enum) { yes_default_path, yes: []const u8, - const Resolved = struct { - data: ?Compilation.EmitLoc, - dir: ?fs.Dir, - - fn deinit(self: *Resolved) void { - if (self.dir) |*dir| { - dir.close(); - } - } - }; - - fn resolve(emit: Emit, default_basename: []const u8, output_to_cache: bool) !Resolved { - var resolved: Resolved = .{ .data = null, .dir = null }; - errdefer resolved.deinit(); - - switch (emit) { - .no => {}, - .yes_default_path => { - resolved.data = Compilation.EmitLoc{ - .directory = if (output_to_cache) null else .{ - .path = null, - .handle = fs.cwd(), - }, - .basename = default_basename, - }; - }, - .yes => |full_path| { - const basename = fs.path.basename(full_path); - if (fs.path.dirname(full_path)) |dirname| { - const handle = try fs.cwd().openDir(dirname, .{}); - resolved = .{ - .dir = handle, - .data = Compilation.EmitLoc{ - .basename = basename, - .directory = .{ - .path = dirname, - .handle = handle, - }, - }, - }; - } else { - resolved.data = Compilation.EmitLoc{ - .basename = basename, - .directory = .{ .path = null, .handle = fs.cwd() }, + const OutputToCacheReason = enum { listen, @"zig run", @"zig test" }; + fn resolve(emit: Emit, default_basename: []const u8, output_to_cache: ?OutputToCacheReason) Compilation.CreateOptions.Emit { + return switch (emit) { + .no => .no, + .yes_default_path => if (output_to_cache != null) .yes_cache else .{ .yes_path = default_basename }, + .yes => |path| if (output_to_cache) |reason| { + switch (reason) { + .listen => fatal("--listen incompatible with explicit output path '{s}'", .{path}), + .@"zig run", .@"zig test" => fatal( + "'{s}' with explicit output path '{s}' requires explicit '-femit-bin=path' or '-fno-emit-bin'", + .{ @tagName(reason), path }, + ), + } + } else e: { + // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would. + if (fs.path.dirname(path)) |dir_path| { + var dir = fs.cwd().openDir(dir_path, .{}) catch |err| { + fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) }); }; + dir.close(); } + break :e .{ .yes_path = path }; }, - } - return resolved; + }; } }; @@ -867,9 +842,9 @@ fn buildOutputType( var linker_allow_undefined_version: bool = false; var linker_enable_new_dtags: ?bool = null; var disable_c_depfile = false; - var linker_sort_section: ?link.File.Elf.SortSection = null; + var linker_sort_section: ?link.File.Lld.Elf.SortSection = null; var linker_gc_sections: ?bool = null; - var linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null; + var linker_compress_debug_sections: ?link.File.Lld.Elf.CompressDebugSections = null; var linker_allow_shlib_undefined: ?bool = null; var allow_so_scripts: bool = false; var linker_bind_global_refs_locally: ?bool = null; @@ -921,7 +896,7 @@ fn buildOutputType( var debug_compiler_runtime_libs = false; var opt_incremental: ?bool = null; var install_name: ?[]const u8 = null; - var hash_style: link.File.Elf.HashStyle = .both; + var hash_style: link.File.Lld.Elf.HashStyle = .both; var entitlements: ?[]const u8 = null; var pagezero_size: ?u64 = null; var lib_search_strategy: link.UnresolvedInput.SearchStrategy = .paths_first; @@ -1196,11 +1171,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.File.Elf.CompressDebugSections, param) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.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.File.Elf.CompressDebugSections.zlib; + linker_compress_debug_sections = link.File.Lld.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| { @@ -2368,7 +2343,7 @@ fn buildOutputType( if (it.only_arg.len == 0) { linker_compress_debug_sections = .zlib; } else { - linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, it.only_arg) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, it.only_arg) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{it.only_arg}); }; } @@ -2505,7 +2480,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.File.Elf.SortSection, arg1) orelse { + linker_sort_section = std.meta.stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse { fatal("expected [name|alignment] after --sort-section, found '{s}'", .{arg1}); }; } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or @@ -2551,7 +2526,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.File.Elf.CompressDebugSections, arg1) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, arg1) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1}); }; } else if (mem.startsWith(u8, arg, "-z")) { @@ -2764,7 +2739,7 @@ fn buildOutputType( mem.eql(u8, arg, "--hash-style")) { const next_arg = linker_args_it.nextOrFatal(); - hash_style = std.meta.stringToEnum(link.File.Elf.HashStyle, next_arg) orelse { + hash_style = std.meta.stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse { fatal("expected [sysv|gnu|both] after --hash-style, found '{s}'", .{ next_arg, }); @@ -2830,7 +2805,7 @@ fn buildOutputType( .link => { create_module.opts.output_mode = if (is_shared_lib) .Lib else .Exe; if (emit_bin != .no) { - emit_bin = if (out_path) |p| .{ .yes = p } else EmitBin.yes_a_out; + emit_bin = if (out_path) |p| .{ .yes = p } else .yes_a_out; } if (emit_llvm) { fatal("-emit-llvm cannot be used when linking", .{}); @@ -3208,7 +3183,17 @@ fn buildOutputType( var cleanup_emit_bin_dir: ?fs.Dir = null; defer if (cleanup_emit_bin_dir) |*dir| dir.close(); - const output_to_cache = listen != .none; + // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if + // the binary is requested with no explicit path (as is the default), we emit to the cache. + const output_to_cache: ?Emit.OutputToCacheReason = switch (listen) { + .stdio, .ip4 => .listen, + .none => if (arg_mode == .run and emit_bin == .yes_default_path) + .@"zig run" + else if (arg_mode == .zig_test and emit_bin == .yes_default_path) + .@"zig test" + else + null, + }; const optional_version = if (have_version) version else null; const root_name = if (provided_name) |n| n else main_mod.fully_qualified_name; @@ -3225,150 +3210,57 @@ fn buildOutputType( }, }; - const a_out_basename = switch (target.ofmt) { - .coff => "a.exe", - else => "a.out", - }; - - const emit_bin_loc: ?Compilation.EmitLoc = switch (emit_bin) { - .no => null, - .yes_default_path => Compilation.EmitLoc{ - .directory = blk: { - switch (arg_mode) { - .run, .zig_test => break :blk null, - .build, .cc, .cpp, .translate_c, .zig_test_obj => { - if (output_to_cache) { - break :blk null; - } else { - break :blk .{ .path = null, .handle = fs.cwd() }; - } - }, - } - }, - .basename = if (clang_preprocessor_mode == .pch) - try std.fmt.allocPrint(arena, "{s}.pch", .{root_name}) - else - try std.zig.binNameAlloc(arena, .{ + const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) { + .no => .no, + .yes_default_path => emit: { + if (output_to_cache != null) break :emit .yes_cache; + const name = switch (clang_preprocessor_mode) { + .pch => try std.fmt.allocPrint(arena, "{s}.pch", .{root_name}), + else => try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = target, .output_mode = create_module.resolved_options.output_mode, .link_mode = create_module.resolved_options.link_mode, .version = optional_version, }), + }; + break :emit .{ .yes_path = name }; }, - .yes => |full_path| b: { - const basename = fs.path.basename(full_path); - if (fs.path.dirname(full_path)) |dirname| { - const handle = fs.cwd().openDir(dirname, .{}) catch |err| { - fatal("unable to open output directory '{s}': {s}", .{ dirname, @errorName(err) }); - }; - cleanup_emit_bin_dir = handle; - break :b Compilation.EmitLoc{ - .basename = basename, - .directory = .{ - .path = dirname, - .handle = handle, - }, - }; - } else { - break :b Compilation.EmitLoc{ - .basename = basename, - .directory = .{ .path = null, .handle = fs.cwd() }, + .yes => |path| if (output_to_cache != null) { + assert(output_to_cache == .listen); // there was an explicit bin path + fatal("--listen incompatible with explicit output path '{s}'", .{path}); + } else emit: { + // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would. + if (fs.path.dirname(path)) |dir_path| { + var dir = fs.cwd().openDir(dir_path, .{}) catch |err| { + fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) }); }; + dir.close(); } + break :emit .{ .yes_path = path }; }, - .yes_a_out => Compilation.EmitLoc{ - .directory = .{ .path = null, .handle = fs.cwd() }, - .basename = a_out_basename, + .yes_a_out => emit: { + assert(output_to_cache == null); + break :emit .{ .yes_path = switch (target.ofmt) { + .coff => "a.exe", + else => "a.out", + } }; }, }; const default_h_basename = try std.fmt.allocPrint(arena, "{s}.h", .{root_name}); - var emit_h_resolved = emit_h.resolve(default_h_basename, output_to_cache) catch |err| { - switch (emit_h) { - .yes => |p| { - fatal("unable to open directory from argument '-femit-h', '{s}': {s}", .{ - p, @errorName(err), - }); - }, - .yes_default_path => { - fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ - default_h_basename, @errorName(err), - }); - }, - .no => unreachable, - } - }; - defer emit_h_resolved.deinit(); + const emit_h_resolved = emit_h.resolve(default_h_basename, output_to_cache); const default_asm_basename = try std.fmt.allocPrint(arena, "{s}.s", .{root_name}); - var emit_asm_resolved = emit_asm.resolve(default_asm_basename, output_to_cache) catch |err| { - switch (emit_asm) { - .yes => |p| { - fatal("unable to open directory from argument '-femit-asm', '{s}': {s}", .{ - p, @errorName(err), - }); - }, - .yes_default_path => { - fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ - default_asm_basename, @errorName(err), - }); - }, - .no => unreachable, - } - }; - defer emit_asm_resolved.deinit(); + const emit_asm_resolved = emit_asm.resolve(default_asm_basename, output_to_cache); const default_llvm_ir_basename = try std.fmt.allocPrint(arena, "{s}.ll", .{root_name}); - var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename, output_to_cache) catch |err| { - switch (emit_llvm_ir) { - .yes => |p| { - fatal("unable to open directory from argument '-femit-llvm-ir', '{s}': {s}", .{ - p, @errorName(err), - }); - }, - .yes_default_path => { - fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ - default_llvm_ir_basename, @errorName(err), - }); - }, - .no => unreachable, - } - }; - defer emit_llvm_ir_resolved.deinit(); + const emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename, output_to_cache); const default_llvm_bc_basename = try std.fmt.allocPrint(arena, "{s}.bc", .{root_name}); - var emit_llvm_bc_resolved = emit_llvm_bc.resolve(default_llvm_bc_basename, output_to_cache) catch |err| { - switch (emit_llvm_bc) { - .yes => |p| { - fatal("unable to open directory from argument '-femit-llvm-bc', '{s}': {s}", .{ - p, @errorName(err), - }); - }, - .yes_default_path => { - fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ - default_llvm_bc_basename, @errorName(err), - }); - }, - .no => unreachable, - } - }; - defer emit_llvm_bc_resolved.deinit(); + const emit_llvm_bc_resolved = emit_llvm_bc.resolve(default_llvm_bc_basename, output_to_cache); - var emit_docs_resolved = emit_docs.resolve("docs", output_to_cache) catch |err| { - switch (emit_docs) { - .yes => |p| { - fatal("unable to open directory from argument '-femit-docs', '{s}': {s}", .{ - p, @errorName(err), - }); - }, - .yes_default_path => { - fatal("unable to open directory 'docs': {s}", .{@errorName(err)}); - }, - .no => unreachable, - } - }; - defer emit_docs_resolved.deinit(); + const emit_docs_resolved = emit_docs.resolve("docs", output_to_cache); const is_exe_or_dyn_lib = switch (create_module.resolved_options.output_mode) { .Obj => false, @@ -3378,7 +3270,7 @@ fn buildOutputType( // Note that cmake when targeting Windows will try to execute // zig cc to make an executable and output an implib too. const implib_eligible = is_exe_or_dyn_lib and - emit_bin_loc != null and target.os.tag == .windows; + emit_bin_resolved != .no and target.os.tag == .windows; if (!implib_eligible) { if (!emit_implib_arg_provided) { emit_implib = .no; @@ -3387,22 +3279,18 @@ fn buildOutputType( } } const default_implib_basename = try std.fmt.allocPrint(arena, "{s}.lib", .{root_name}); - var emit_implib_resolved = switch (emit_implib) { - .no => Emit.Resolved{ .data = null, .dir = null }, - .yes => |p| emit_implib.resolve(default_implib_basename, output_to_cache) catch |err| { - fatal("unable to open directory from argument '-femit-implib', '{s}': {s}", .{ - p, @errorName(err), + const emit_implib_resolved: Compilation.CreateOptions.Emit = switch (emit_implib) { + .no => .no, + .yes => emit_implib.resolve(default_implib_basename, output_to_cache), + .yes_default_path => emit: { + if (output_to_cache != null) break :emit .yes_cache; + const p = try fs.path.join(arena, &.{ + fs.path.dirname(emit_bin_resolved.yes_path) orelse ".", + default_implib_basename, }); - }, - .yes_default_path => Emit.Resolved{ - .data = Compilation.EmitLoc{ - .directory = emit_bin_loc.?.directory, - .basename = default_implib_basename, - }, - .dir = null, + break :emit .{ .yes_path = p }; }, }; - defer emit_implib_resolved.deinit(); var thread_pool: ThreadPool = undefined; try thread_pool.init(.{ @@ -3456,7 +3344,7 @@ fn buildOutputType( src.src_path = try dirs.local_cache.join(arena, &.{sub_path}); } - if (build_options.have_llvm and emit_asm != .no) { + if (build_options.have_llvm and emit_asm_resolved != .no) { // LLVM has no way to set this non-globally. const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" }; @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv); @@ -3472,23 +3360,11 @@ fn buildOutputType( fatal("--debug-incremental requires -fincremental", .{}); } - const disable_lld_caching = !output_to_cache; - const cache_mode: Compilation.CacheMode = b: { + // Once incremental compilation is the default, we'll want some smarter logic here, + // considering things like the backend in use and whether there's a ZCU. + if (output_to_cache == null) break :b .none; if (incremental) break :b .incremental; - if (disable_lld_caching) break :b .incremental; - if (!create_module.resolved_options.have_zcu) break :b .whole; - - // TODO: once we support incremental compilation for the LLVM backend - // via saving the LLVM module into a bitcode file and restoring it, - // along with compiler state, this clause can be removed so that - // incremental cache mode is used for LLVM backend too. - if (create_module.resolved_options.use_llvm) break :b .whole; - - // Eventually, this default should be `.incremental`. However, since incremental - // compilation is currently an opt-in feature, it makes a strictly worse default cache mode - // than `.whole`. - // https://github.com/ziglang/zig/issues/21165 break :b .whole; }; @@ -3510,13 +3386,13 @@ fn buildOutputType( .main_mod = main_mod, .root_mod = root_mod, .std_mod = std_mod, - .emit_bin = emit_bin_loc, - .emit_h = emit_h_resolved.data, - .emit_asm = emit_asm_resolved.data, - .emit_llvm_ir = emit_llvm_ir_resolved.data, - .emit_llvm_bc = emit_llvm_bc_resolved.data, - .emit_docs = emit_docs_resolved.data, - .emit_implib = emit_implib_resolved.data, + .emit_bin = emit_bin_resolved, + .emit_h = emit_h_resolved, + .emit_asm = emit_asm_resolved, + .emit_llvm_ir = emit_llvm_ir_resolved, + .emit_llvm_bc = emit_llvm_bc_resolved, + .emit_docs = emit_docs_resolved, + .emit_implib = emit_implib_resolved, .lib_directories = create_module.lib_directories.items, .rpath_list = create_module.rpath_list.items, .symbol_wrap_set = symbol_wrap_set, @@ -3599,7 +3475,6 @@ fn buildOutputType( .test_filters = test_filters.items, .test_name_prefix = test_name_prefix, .test_runner_path = test_runner_path, - .disable_lld_caching = disable_lld_caching, .cache_mode = cache_mode, .subsystem = subsystem, .debug_compile_errors = debug_compile_errors, @@ -3744,13 +3619,8 @@ fn buildOutputType( }) { dev.checkAny(&.{ .run_command, .test_command }); - if (test_exec_args.items.len == 0 and target.ofmt == .c) default_exec_args: { + if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) { // Default to using `zig run` to execute the produced .c code from `zig test`. - const c_code_loc = emit_bin_loc orelse break :default_exec_args; - const c_code_directory = c_code_loc.directory orelse comp.bin_file.?.emit.root_dir; - const c_code_path = try fs.path.join(arena, &[_][]const u8{ - c_code_directory.path orelse ".", c_code_loc.basename, - }); try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" }); if (dirs.zig_lib.path) |p| { try test_exec_args.appendSlice(arena, &.{ "-I", p }); @@ -3775,7 +3645,7 @@ fn buildOutputType( if (create_module.dynamic_linker) |dl| { try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }); } - try test_exec_args.append(arena, c_code_path); + try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file } try runOrTest( @@ -4354,12 +4224,22 @@ fn runOrTest( runtime_args_start: ?usize, link_libc: bool, ) !void { - const lf = comp.bin_file orelse return; - // A naive `directory.join` here will indeed get the correct path to the binary, - // however, in the case of cwd, we actually want `./foo` so that the path can be executed. - const exe_path = try fs.path.join(arena, &[_][]const u8{ - lf.emit.root_dir.path orelse ".", lf.emit.sub_path, - }); + const raw_emit_bin = comp.emit_bin orelse return; + const exe_path = switch (comp.cache_use) { + .none => p: { + if (fs.path.isAbsolute(raw_emit_bin)) break :p raw_emit_bin; + // Use `fs.path.join` to make a file in the cwd is still executed properly. + break :p try fs.path.join(arena, &.{ + ".", + raw_emit_bin, + }); + }, + .whole, .incremental => try comp.dirs.local_cache.join(arena, &.{ + "o", + &Cache.binToHex(comp.digest.?), + raw_emit_bin, + }), + }; var argv = std.ArrayList([]const u8).init(gpa); defer argv.deinit(); @@ -5087,16 +4967,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { }; }; - const exe_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = "build", - .target = resolved_target.result, - .output_mode = .Exe, - }); - const emit_bin: Compilation.EmitLoc = .{ - .directory = null, // Use the local zig-cache. - .basename = exe_basename, - }; - process.raiseFileDescriptorLimit(); const cwd_path = try introspect.getResolvedCwd(arena); @@ -5357,8 +5227,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { .config = config, .root_mod = root_mod, .main_mod = build_mod, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .yes_cache, .self_exe_path = self_exe_path, .thread_pool = &thread_pool, .verbose_cc = verbose_cc, @@ -5386,8 +5255,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { // Since incremental compilation isn't done yet, we use cache_mode = whole // above, and thus the output file is already closed. //try comp.makeBinFileExecutable(); - child_argv.items[argv_index_exe] = - try dirs.local_cache.join(arena, &.{comp.cache_use.whole.bin_sub_path.?}); + child_argv.items[argv_index_exe] = try dirs.local_cache.join(arena, &.{ + "o", + &Cache.binToHex(comp.digest.?), + comp.emit_bin.?, + }); } if (process.can_spawn) { @@ -5504,16 +5376,6 @@ fn jitCmd( .is_explicit_dynamic_linker = false, }; - const exe_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = options.cmd_name, - .target = resolved_target.result, - .output_mode = .Exe, - }); - const emit_bin: Compilation.EmitLoc = .{ - .directory = null, // Use the global zig-cache. - .basename = exe_basename, - }; - const self_exe_path = fs.selfExePathAlloc(arena) catch |err| { fatal("unable to find self exe path: {s}", .{@errorName(err)}); }; @@ -5605,8 +5467,7 @@ fn jitCmd( .config = config, .root_mod = root_mod, .main_mod = root_mod, - .emit_bin = emit_bin, - .emit_h = null, + .emit_bin = .yes_cache, .self_exe_path = self_exe_path, .thread_pool = &thread_pool, .cache_mode = .whole, @@ -5637,7 +5498,11 @@ fn jitCmd( }; } - const exe_path = try dirs.global_cache.join(arena, &.{comp.cache_use.whole.bin_sub_path.?}); + const exe_path = try dirs.global_cache.join(arena, &.{ + "o", + &Cache.binToHex(comp.digest.?), + comp.emit_bin.?, + }); child_argv.appendAssumeCapacity(exe_path); } diff --git a/src/target.zig b/src/target.zig index 247b783439fb..0cecc168f574 100644 --- a/src/target.zig +++ b/src/target.zig @@ -739,7 +739,7 @@ pub fn functionPointerMask(target: std.Target) ?u64 { pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool { switch (backend) { - .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target), + .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target), .stage2_c => return true, else => return false, } @@ -850,7 +850,9 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt }, .separate_thread => switch (backend) { .stage2_llvm => false, - else => true, + .stage2_c, .stage2_wasm, .stage2_x86_64 => true, + // TODO: most self-hosted backends should be able to support this without too much work. + else => false, }, }; } diff --git a/stage1/wasi.c b/stage1/wasi.c index 0c9ca18c57ba..ef2183dae849 100644 --- a/stage1/wasi.c +++ b/stage1/wasi.c @@ -517,7 +517,7 @@ uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iov case wasi_filetype_character_device: break; case wasi_filetype_regular_file: break; case wasi_filetype_directory: return wasi_errno_inval; - default: panic("unimplemented"); + default: panic("unimplemented: fd_read special file"); } size_t size = 0; @@ -629,7 +629,7 @@ uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t i case wasi_filetype_character_device: break; case wasi_filetype_regular_file: break; case wasi_filetype_directory: return wasi_errno_inval; - default: panic("unimplemented"); + default: panic("unimplemented: fd_pwrite special file"); } fpos_t pos; @@ -679,7 +679,7 @@ uint32_t wasi_snapshot_preview1_fd_filestat_set_times(uint32_t fd, uint64_t atim fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_times(%u, %llu, %llu, 0x%X)\n", fd, (unsigned long long)atim, (unsigned long long)mtim, fst_flags); #endif - panic("unimplemented"); + panic("unimplemented: fd_filestat_set_times"); return wasi_errno_success; } @@ -703,7 +703,7 @@ uint32_t wasi_snapshot_preview1_environ_get(uint32_t environ, uint32_t environ_b fprintf(stderr, "wasi_snapshot_preview1_environ_get()\n"); #endif - panic("unimplemented"); + panic("unimplemented: environ_get"); return wasi_errno_success; } @@ -757,7 +757,7 @@ uint32_t wasi_snapshot_preview1_fd_readdir(uint32_t fd, uint32_t buf, uint32_t b fprintf(stderr, "wasi_snapshot_preview1_fd_readdir(%u, 0x%X, %u, %llu)\n", fd, buf, buf_len, (unsigned long long)cookie); #endif - panic("unimplemented"); + panic("unimplemented: fd_readdir"); return wasi_errno_success; } @@ -774,7 +774,7 @@ uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t io case wasi_filetype_character_device: break; case wasi_filetype_regular_file: break; case wasi_filetype_directory: return wasi_errno_inval; - default: panic("unimplemented"); + default: panic("unimplemented: fd_write special file"); } size_t size = 0; @@ -825,7 +825,7 @@ uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32 fds[fd_len].fdflags = fdflags; switch (des[de].filetype) { case wasi_filetype_directory: fds[fd_len].stream = NULL; break; - default: panic("unimplemented"); + default: panic("unimplemented: path_open non-directory DirEntry"); } fds[fd_len].fs_rights_inheriting = fs_rights_inheriting; @@ -943,7 +943,7 @@ uint32_t wasi_snapshot_preview1_path_unlink_file(uint32_t fd, uint32_t path, uin enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de); if (lookup_errno != wasi_errno_success) return lookup_errno; if (des[de].filetype == wasi_filetype_directory) return wasi_errno_isdir; - if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented"); + if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented: path_unlink_file special file"); DirEntry_unlink(de); return wasi_errno_success; } @@ -961,7 +961,7 @@ uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t io case wasi_filetype_character_device: break; case wasi_filetype_regular_file: break; case wasi_filetype_directory: return wasi_errno_inval; - default: panic("unimplemented"); + default: panic("unimplemented: fd_pread special file"); } fpos_t pos; @@ -975,7 +975,7 @@ uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t io if (fds[fd].stream != NULL) read_size = fread(&m[load32_align2(&iovs_ptr[i].ptr)], 1, len, fds[fd].stream); else - panic("unimplemented"); + panic("unimplemented: fd_pread stream=NULL"); size += read_size; if (read_size < len) break; } @@ -1000,7 +1000,7 @@ uint32_t wasi_snapshot_preview1_fd_seek(uint32_t fd, uint64_t in_offset, uint32_ case wasi_filetype_character_device: break; case wasi_filetype_regular_file: break; case wasi_filetype_directory: return wasi_errno_inval; - default: panic("unimplemented"); + default: panic("unimplemented: fd_seek special file"); } if (fds[fd].stream == NULL) return wasi_errno_success; @@ -1035,7 +1035,7 @@ uint32_t wasi_snapshot_preview1_poll_oneoff(uint32_t in, uint32_t out, uint32_t fprintf(stderr, "wasi_snapshot_preview1_poll_oneoff(%u)\n", nsubscriptions); #endif - panic("unimplemented"); + panic("unimplemented: poll_oneoff"); return wasi_errno_success; } diff --git a/test/link/macho.zig b/test/link/macho.zig index a98245926e0a..ed83000c08d6 100644 --- a/test/link/macho.zig +++ b/test/link/macho.zig @@ -211,7 +211,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step { expectLinkErrors(exe, test_step, .{ .exact = &.{ "error: duplicate symbol definition: _strong", "note: defined by /?/a.o", - "note: defined by /?/main.o", + "note: defined by /?/main_zcu.o", } }); return test_step; @@ -2648,7 +2648,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step { expectLinkErrors(exe, test_step, .{ .exact = &.{ "error: undefined symbol: _foo", "note: referenced by /?/a.o:_bar", - "note: referenced by /?/main.o:_main.main", + "note: referenced by /?/main_zcu.o:_main.main", } }); } else { expectLinkErrors(exe, test_step, .{ .exact = &.{ diff --git a/test/src/check-stack-trace.zig b/test/src/check-stack-trace.zig index fccbbe36090f..43800086afd3 100644 --- a/test/src/check-stack-trace.zig +++ b/test/src/check-stack-trace.zig @@ -65,7 +65,7 @@ pub fn main() !void { // This actually violates the DWARF specification (DWARF5 ยง 3.1.1, lines 24-27). // The self-hosted backend uses the root Zig source file of the module (in compilance with the spec). if (std.mem.eql(u8, file_name, "test") or - std.mem.eql(u8, file_name, "test.exe.obj") or + std.mem.eql(u8, file_name, "test_zcu.obj") or std.mem.endsWith(u8, file_name, ".zig")) { try buf.appendSlice("[main_file]"); diff --git a/tools/incr-check.zig b/tools/incr-check.zig index 6e69b93b96c0..6c048f7a8709 100644 --- a/tools/incr-check.zig +++ b/tools/incr-check.zig @@ -314,7 +314,7 @@ const Eval = struct { const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len]; const result_dir = ".local-cache" ++ std.fs.path.sep_str ++ "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*); - const bin_name = try std.zig.binNameAlloc(arena, .{ + const bin_name = try std.zig.EmitArtifact.bin.cacheName(arena, .{ .root_name = "root", // corresponds to the module name "root" .target = eval.target.resolved, .output_mode = .Exe,